Files
oko_public/for_bots.md
T
2026-09-09 21:44:05 -05:00

7.0 KiB

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.