Files
oko_public/for_bots.md
T

130 lines
7.0 KiB
Markdown
Raw Normal View History

2026-09-09 21:44:05 -05:00
# oko — Matrix storage backend + dev homeserver (session log)
Date: 2026-09-05
Author: opencode session (big-pickle)
## Objective
Replace the oko coordinator's backend storage (previously MySQL + local filesystem)
with Matrix: every clip is stored in a Matrix room as an `m.video` event, with its
metadata posted as an `m.text` reply directly beneath the video event. A real
development homeserver (Conduit) was provisioned on the FreeBSD VPS `magbot.online`
so the system is usable end-to-end.
## Final routing rules (agreed behavior)
| criteria | outcome |
|-----------------------------------|------------------------------------------------|
| no motion | not stored (dropped before decode/encode) |
| motion, no detections | clips room only (+ view room, caption only) |
| motion + detections | clips room **and** detections room (+ view room, caption only) |
Every motion clip is also posted to a third **view room** (`-view-room`): the
same uploaded `mxc://` media as an `m.video` event whose body is a one-line
human caption (`<source> · <n> frames · <fps> fps · motion <n>%`) and no JSON
metadata reply, so a human can browse clips without scrolling through JSON.
Livestreaming is explicitly out of scope.
## Coordinator rewrite (Matrix backend)
- `coordinator/matrix.go` (new)
- `matrixStore` type wrapping `mautrix.Client` (maunium.net/go/mautrix v0.29.0).
- `newMatrixStore`: `Whoami` self-check to fail fast on bad token; both room IDs
must start with `!` (validated at startup).
- `postClip`: uploads a single encode (`UploadBytesWithName`) to get one `mxc://`
URL, then sends the `m.video` event and a metadata `m.text` reply with
`m.in_reply_to` pointing at the video event. Both rooms reference the same MXC.
- `routeTargets`: the routing truth table (no motion -> nil; motion -> clips room;
motion+detections -> clips room + detections room).
- `hasDetections`: true when any frame has non-empty detections.
- `clipJSON`/`buildClipMetadata`: metadata body shape (see schema below).
- `coordinator/main.go`
- New flags: `-listen`, `-passphrase`, `-matrix-homeserver`, `-matrix-user`,
`-matrix-token-file` (or `OKO_MATRIX_TOKEN` env), `-clips-room`, `-detections-room`,
`-view-room` (third room, minimal caption only).
- Removed `-storage`, `-db-*`, `-keepalive-url`-era MySQL/filesystem writes.
- Token is read from a file or env — never from argv (audit #10).
- No-motion clips dropped before decode/encode; retained `computeFPS`, temp-file
MP4 encode, TCP ingest, passphrase decrypt.
- Metadata `m.text` body (pretty-printed JSON), shown in the live rooms:
`source_data`, `width`, `height`, `channels`, `gocv_image_type`, `frame_count`,
`fps`, `timestamps`, `guids`, `detections` (per-frame map: title/version/…), plus
`motion_percent`.
## terp change
- `terp/main.go`: removed the "no classifier detections -> drop" branch; all motion
clips are now forwarded to the coordinator (required so motion-without-DaemonSet
clips reach Matrix).
- `terp/terp_test.go`: updated four tests for the new forwarding behavior.
- Note: `terp/terp` committed binary was rebuilt to match source (tracked, modified).
## Tests
- `coordinator/matrix_test.go` (new): `TestRouteTargets`, `TestHasDetections`,
`TestBuildClipMetadata`.
- `coordinator/coordinator_test.go`: rewritten; keeps `computeFPS` tests; removed
replaced filesystem/MySQL tests.
- All pass: `go build`, `go vet`, `go test ./...` in `coordinator` and `terp`.
## Config / repo wiring
- `config.yaml`: coord1 node now points at the real homeserver/rooms.
- `run-stack.sh`: env-overridable defaults `OKO_MATRIX_HS`, `OKO_MATRIX_USER`,
`OKO_MATRIX_TOKEN_FILE`, `OKO_CLIPS_ROOM`, `OKO_DETECTIONS_ROOM`.
- `.gitignore`: added `matrix.token`, `*.token`, `logs/`, `storage/`.
- `matrix.credentials.example`: redacted template (real creds live on the VPS and
in a local 0600 file — see below).
## Dev Matrix homeserver (Conduit) on magbot.online
- FreeBSD 14.2 VPS, 1 CPU / ~1 GB RAM / ~70 GB free; SSH as `nolan` (no passwordless
sudo, root SSH denied) -> everything installed user-space.
- `nolan`'s shell is fish: run remote logic via script files: `sh /path/script.sh`.
- Conduit 0.10.13 + rocksdb/gflags/snappy extracted to `/home/nolan/matrixroot`;
binary needs `LD_LIBRARY_PATH=/home/nolan/matrixroot/usr/local/lib`.
- Config: `/home/nolan/conduit/conduit.toml` (server_name magbot.online, port 8008,
rocksdb, max_request_size 100MB, registration now DISABLED, federation off).
- Runtime/DB/log: `/home/nolan/conduit/{data,conduit.log}`.
- Start script: `/home/nolan/start-conduit.sh` (sets LD_LIBRARY_PATH + CONDUIT_CONFIG,
nohup). `@reboot` autostart installed in `nolan` crontab.
- Accounts: bot `@okobot:magbot.online` (used by coordinator), viewer
`@nolan:magbot.online` (joined both rooms). Bot access token -> repo `matrix.token`
(0600, gitignored).
- Rooms: clips `!mSnSuG3WTmoTfN6lvNHjFsbwFoMeEXlk4xFRmbg824k`
(#oko-clips:magbot.online), detections `!bAkHwtJ5FhfXpEsUFesllGshMejkgKwSQeAPJ8muOq0`
(#oko-detections:magbot.online). Both private, nolan invited+joined.
- Real credentials stored (0600): VPS `/home/nolan/oko-matrix-credentials.txt`
and local `/tmp/opencode/oko-matrix-credentials.txt`.
- Reachable over plain HTTP on :8008; no TLS yet (later: nginx reverse proxy on
magbot.online, which already runs nginx).
## End-to-end verification (live)
- `curl` client API + register (token-based) worked before registration was locked;
unprivileged register now returns `M_FORBIDDEN`.
- mautrix path health-checked against the live server with a throwaway client
(`/tmp/opencode/matrixtest`): Whoami, media upload -> `mxc://`, `m.video` event,
metadata reply with `m.in_reply_to` all OK; viewer sync/timeline fetch confirmed.
- Ran the real `coordinator` binary against the live homeserver with synthetic
gob clips (`/tmp/opencode/clipsender`):
- motion only -> clip stored in clips room only.
- motion + person detection -> stored in clips room AND detections room.
- Viewer `@nolan` retrieved both events + metadata replies.
## Operational notes / TODOs
- Smoke/test clips remain in both rooms (Conduit client API returns
`M_UNRECOGNIZED` for redaction) — clean up via an admin tool when convenient.
- Conduit has no TLS; enable nginx reverse proxy (or tailscale) before deploying
to real cameras. Federation currently off.
- `terp/terp` tracked binary was back in sync with source (rebuilt; modified).
- Local `config.yaml` placeholders were replaced with live values; the livestream
side-channel (livestream-cache module + runCam livestream glue) and its config
schema were removed entirely; `config.example.yaml` now documents the clip
pipeline schema.
- No live `OKO_TEST_MATRIX`-gated e2e test was added to the Go test suite; the live
path was validated manually as described above.
- Coordinator not currently running as a service on the dev box — start via
`./run-stack.sh` (or manually) when cameras are attached.