docs/terminal-contracts.md
Ref: Size: 1.9 KiB History
# Terminal and agent contracts Read when changing these components. Implementation history retained from CLAUDE.md; the current code and regression tests are authoritative. - **`proxy.zig` and the QUIC modules carry opaque bytes and know nothing of frames.** Keep the wire contract — `term` — out of `proxy.zig`'s imports. - **`predict.zig` output never enters the replica.** It is an overlay. - **One replay core.** CLI, wasm, and test fixtures all go through `replica.zig`, over a `grid`, never an engine — the client parses no VT. Do not hand-roll a second applier. - **A client dump equals a daemon dump byte for byte, modulo trailing spaces per row.** The rule is stated in three places, and all three must keep saying the same thing: the header on `grid.dumpRowsPlain` (which `Grid.dumpPlain` calls), the server harness's `trimRowTails`, and the e2e `converged_quiet` strip. Ghostty's VT formatter trimmed trailing whitespace on the old wire, so no replica ever held a typed trailing space; the cell encoder's default-space cutoff is parity with that. - **Latest wins.** The grid follows the most recently active client. - **`mux a` attaches at 0×0** so an agent never resizes a human's session. - **OSC 133 marks are opt-in** (`MUX_SHELL_INTEGRATION=1`); without them `mux a` falls back to `pgid`/`settle` and there is no real exit code. Every `mux a` reply names the `mechanism` that answered it. - **OSC 52 clipboard READ is refused deliberately.** Not a gap. - **Agent forwarding is opt-in (`-A`) and the daemon pumps blind.** The per-session agent socket always exists and overwrites the daemon's own `SSH_AUTH_SOCK` — unset when there is no socket, never inherited. The latest-active `-A` client answers. `mux a` and browsers never OFFER an agent, though anything they run inside a session uses that session's socket like any other process. Frames, never transport; both ends cap a frame at `agent_data_max`.