Architecture

How it all fits together

A television behind an office firewall is unreachable from the open internet. Screenwhere solves that once, with a small always-on box that dials outward — and then every capability rides on that single connection.

The one hard problem: NAT

The TV, the camera and the smart plug all live on a private network. A server in the cloud cannot reach in to them — you can't pull the camera's video, you can't open a control socket, you can't attach a debugger. Every plane hits the same wall.

So each site contains one always-on Linux box — the site agent — that calls outward to the cloud relay over a WebSocket. Because the connection is established from inside the network, it works through any firewall with nothing to open. The cloud never initiates; it only ever answers the box.

Private LAN TV · camera · plug · site agent firewall / NAT Cloud relay one VPS outbound WS inbound ✕ blocked

The pieces

Site agent — one box per network

A Raspberry Pi 4 (USB-SSD boot, systemd, self-healing) on the TV's LAN. It reaches every TV on that network, so one office with 20 TVs needs one box plus 20 cameras — not 20 boxes. It runs: the control bridge (ported from the kac-remote protocols), the on-demand camera push (ffmpeg), the session recorder, smart-plug control, and LAN discovery. Identity is by MAC, not IP, so a camera that drifts to a new DHCP address self-heals.

Cloud relay — one VPS

A single WebSocket + HTTP server (Docker, TLS) that owns the set registry, session auth + 2FA, team access control, command forwarding, the on-demand-push state machine, recording/replay routing, the audit log, usage stats, health alerts and the egress estimate — and hosts the web app. State is small JSON files, lazily flushed: no database needed for ~20 sets. It sits beside the existing MediaMTX + coturn that carry the low-latency video.

Clients

A web app (the dashboard, the picker, and a per-set detail with camera, remote, debug, replay and recordings) plus the kac-remote mobile app for remote-only control over the cloud.

MCP server — the AI-agent façade

A small, stateless server (its own container, behind the same TLS proxy) that lets an AI agent read and control a user's sets as that user. It's a pure forwarder: each request carries the user's token, which the server hands to the relay — so the relay stays the single access authority, enforcing the exact same rules and audit as the web app. It holds no standing credential and no state. The MCP page walks through the tools and the click-to-connect login.

Security from the start. The agent authorises with a per-set token; users log in for a server-minted session token (role read live → unforgeable) with TOTP 2FA required for everyone and 30-day device-trust. Team ACLs scope every set. AI agents connect with a per-user access token or OAuth 2.1 that resolves to the same account with the same live role — never more. Everything is TLS; secrets never touch git.

The data model

Everything binds to one identity — the set: a TV + its camera (+ optional plug). The registry stores its name, brand/model/OS/year, LAN config (TV/cam/plug IP + MAC), camera path, recording opt-in and access scope. The TV's IP and the camera credentials live only on the box — never in the cloud.

Where the test suites actually live

A scenario is a document, and every project keeps its documents in a git repository on the relay — a commit for every save that changed something. That is what makes version history, going back, and side-by-side differences real rather than a feature bolted on top of a database column.

Each scenario is kept in three interchangeable formats at once, so the file extension never lies about what is inside it: whichever one you prefer to read is the one you open, and the others are regenerated to match. The repository can be copied onto your own machine and written back to with ordinary git — no separate account, no second permission system; the same access token the command-line tool uses, and the same rules about what may be changed as inside the app. Sending work back is treated as saving it, and the moment it arrives the library shows it, runs use it and scheduled checks monitor it.

Three versions of a suite exist at once, and only one road leads to the one the nightly watches run.

main production · the watches run this develop shared · the editor opens this test/… one piece of work approval 1 2 3
1work forks from the shared version — and is named after the work 2it merges back with no review: by hand, or on its own after enough silence 3a promotion is approved by somebody else than the person who asked production is never written to directly — there is no other road up

A watch stores which of those it runs, so what is being monitored is a property of the watch and not of whoever saved last.

Next: browse the features built on this, or see the full release history.