a73x

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`.