How it works
The daemon owns sessions and clients attach to them. For omp, the app also speaks the harness’s own collab protocol, so it does not have to scrape a terminal. Three sources feed one reducer in the app.
The daemon owns the session
A session is a managed PTY plus metadata, not a forked “phone agent”. You start a real CLI (omp, a shell, claude, codex…); every client attaches to the same sessionId and sees the same output. Input from any attached client is written to the PTY. Disconnecting detaches only; the PTY keeps running, which is the point compared with a raw SSH session.
Each live session also carries a VT screen (so the phone draws a styled grid with cursor, colours and scrollback instead of raw bytes), an attention detector that reads OSC 9/99/777 notifications, the bell and a configured prompt line, a bounded transcript ring for replay, and a viewer set that suppresses a push for a session already on screen. The persisted record is versioned, so a restarted daemon still lists what it had and can resume it.
Clients attach over iroh
The daemon hosts an iroh endpoint (QUIC, hole-punched, with relay fallback). A client pairs on one ALPN with a 6-digit code, then connects on another with the daemon token. Frames are length-prefixed JSON. The daemon dials out, so no inbound networking is required. The code is limited (10-minute lifetime, single use, throttled, discarded after repeated failure); the token is equivalent to an SSH key. A local WebSocket on 127.0.0.1:7740 serves the in-host CLI.
The app speaks omp’s own collab protocol
A running omp TUI can host an end-to-end-encrypted room on its relay. The app joins as a guest with its own implementation (vendored wire types plus AES-GCM) and gets a snapshot, live events, permission requests, prompts and abort. The room key stays in the link. The daemon can also act as a machine gateway for this: it proxies omp collab list and omp collab link so a paired phone sees every shared session and mints a fresh link on tap — without ever seeing session contents.
New: a daemon-hosted omp RPC session
The daemon can host an omp --mode rpc-ui session itself. Its RPC transport negotiates protocol v2 and reassembles chunked frames. A host adapter then maps RPC into the collab frame vocabulary — entries, state, agents, events — and sends it to attached clients as session.structured over the daemon’s normal session channel. Because the vocabulary is the one the app already renders, the same reducer covers all three sources: collab guest, terminal grid, and daemon-hosted RPC. There is no second protocol in the app.
The project’s review notes record this as verified against a real omp: a WebSocket test sees entry, state, agents and event frames from a live session.
What is not built
- A subagent transcript view (the protocol has
fetch-transcript; the app does not use it). - A Play Store or EAS-hosted build.
- Idempotency receipts beyond a prompt’s client id, revision-stamped roster deltas, and a per-connection outbound byte cap.
- The daemon does not yet report the host’s
PATHcontext, so “is omp available here” is partly computed on the phone. - Live model or thinking switching over collab: the guest protocol has no frame for it.
This page is the whole picture. The design decisions behind it, and the review of comparable projects that produced them, are kept with the source.