CLAUDE.md
Ref: Size: 7.4 KiB History
# mux Terminal multiplexer in Zig, for Linux and Apple-silicon macOS. The daemon owns the ghostty-vt engine; clients receive cell snapshots and row updates. Read the relevant module header and contract document before edits. ## Scope The terminal wall is frozen: bug fixes only until the native client meets issue `94ed7dfd`. No new wall features or invariants. `mux web` stays and will own the layout file. See the 2026-09-05 entry in [decisions](docs/decisions.md). When the user requests sprint delivery, follow the repository [sprint-delivery skill](docs/skills/sprint-delivery/SKILL.md). Ordinary isolated edits do not require that workflow. ## Toolchain and gates Use `mise` (pinned to Zig 0.15.2 in `mise.toml`) through Make; Make resolves `ZIG` via `mise which zig` and respects an explicit `ZIG=/path/to/zig` override. `mise install` provisions this compiler per machine; worktrees reuse it, so `deps/zig` is not required. The system Zig is incompatible. Make handles the macOS shadow SDK. See [development commands](docs/development.md) for setup, releases, cross-OS checks and the full command list. - `make build`: lint, then build the development CLI. - `make lint`: fetch and verify pinned zlint, then lint repository Zig sources. - `make check`: required before commit; lint, formatting, unit tests, shell checks, web ABI verification, comment references and source-rule checks. - `make ci`: required before delivery; check, e2e, agent and throughput gates. - `make daemon-test client-test native-core-test`: focused component tests. - `make native native-e2e`: GUI build/tests and real-window checks; the full GUI remains outside the default delivery gate. - `make mac xos`: explicit macOS and cross-OS journeys; see development setup. ## Architecture `build.zig` owns the module definitions, imports and source-boundary rules. Use [component ownership](docs/component-ownership.md) to find the affected component and focused tests. Do not maintain another inventory of module files here. A Zig file belongs to one build module, even when used by several clients. - `src/engine/`: terminal grid, protocol, replay and authoritative VT engine. - `src/server/`: daemon, sessions, PTYs and upgrade handling. - `src/client/`: reusable client services and browser hub. - `src/gui/`, `src/tui/`, `web/`: native, terminal and browser frontends. - `src/os/`: operating-system implementations behind shared interfaces. - `src/cli/`: command entry points. `mux d`, `mux a`, `mux web` select modes; other first words select a client transport. `muxg` is the native GUI. Source-rule exceptions must explain the immediately following occurrence. One permitted occurrence must not exempt the rest of a file. Rule definitions and their diagnostics live in `build.zig`; `test/bans.sh` tests enforcement. ## Contracts - The daemon owns VT parsing. CLI, wasm and fixtures use one replay core over the cell grid. Prediction is an overlay and never enters the replica. - Proxy and QUIC transport carry opaque bytes, independent of terminal frames. - Client and daemon plain dumps agree after trimming row-tail whitespace. - Latest-active client controls session geometry. Agent clients attach at 0×0. - Read-only discovery never starts a daemon. Start and upgrade behavior belong to the daemon; processes are executed as argv without shell interpretation. - Detach leaves sessions alive. Ending a session and stopping a daemon are explicit actions. Never steal a socket owned by a live daemon. - Agent forwarding is opt-in. Clipboard reads through OSC 52 are refused. Read the detailed contracts for the area being changed: | Folder | Row — its child files | |---|---| | `src/engine/` | `term`(`term.zig`) — `protocol` `replica` `grid` · `engine`(`engine.zig`) — `delta` — the daemon's ghostty-vt; no client row imports it outside a test | | `src/server/` | `daemon`(`server.zig`) — `server_agent` `server_sessions` `cmd` `shellint` `quic_server` `upgrade` `server_test_*` · `pty` | | `src/client/` | `client` — `client_core` `hosts` `handoff` `layout` `keymap` `askpass` `selection` `session_pump` `buffered_wire` `open_wait` `resolver` `discovery` · `webhub` · `wasm_core` `client_core_wasm_check` (wasm roots the build wires outside the table) | | `src/gui/` | `native_core`(`native_core.zig`) — `workspace` `runtime` `picker` `persistence` `interaction` `font_options` `config` `theme` · `native`(`native.zig`) — `font` `atlas` `quads` `gl` `frame` `bench` | | `src/tui/` | `wall`(`wallview.zig`) — `interact` `paint` `predict` `wall_host` `wall_picker` `wall_pump` `wall_layout` `wall_test_*` | | `src/cli/` | `mux`(dispatch) — `main`(daemon) `mux_main`(client) `webhub_main`(hub) · `muxg`(native viewer) · `agent`(`muxa.zig`) · `cliflags`(`flags.zig`) | | `src/os/` | `server_os`(`server_os.zig`) — `server_os_linux` `server_os_macos` · `client_os`(`client_os.zig`) — `client_os_linux` `client_os_macos` · `spawn` — the platform layer, one row per side so the client never links a fork or a pty; imports nothing of ours (spec 2026-09-03) | | `src/` | `xdg` `sockpath` `dial` `link` `serve` `proxy` `quic` `testtmp` — what both sides link; `dial` is the client side of a daemon socket and `link` the live connection under it whatever reached it (fd, handoff stdio, QUIC), `serve` the right to bind a socket path and the duty to unlink it, `term` and nothing else under them | - [Terminal and agent contracts](docs/terminal-contracts.md). - [Daemon, transport and upgrade contracts](docs/daemon-contracts.md). - [Terminal wall and browser layout contracts](docs/wall-contracts.md). ## Working rules - Assert user-visible behavior with real binaries, PTYs and shells. Test plural sessions/panes and nonzero origins; single-item fixtures alone miss interactions. Ask the OS about process state, rather than trusting the daemon. - Use `test/os_oracle.sh` for platform queries and the shared e2e helpers for fixtures. Linux evidence does not establish macOS behavior. - For ad hoc rigs, use `tools/isolated-run.sh PATH_TO_MUX COMMAND [ARG ...]`. It isolates XDG state and the default daemon socket. Custom sockets need their own cleanup. Never run throwaway rigs against the user's daemon/state. - Capture noisy checks with `tools/run-logged.sh LOG COMMAND [ARG ...]`. It preserves the command's exit status; piping a check into tail does not. - Unit tests must not write to stdout: it carries the Zig test-runner protocol. Inject a writer or capture fd 1 in a test-owned pipe. - Measure performance with ReleaseSafe (`make throughput`), not Debug builds. - Keep rationale in comments, stated plainly. Put historical narratives in decision records. Comment-reference checks enforce valid references, not prose length; do not compress explanations merely to satisfy a counter. - Split code along responsibilities. Keep wrappers only where they preserve an existing API; do not create unrelated fragments to reduce a line count. - Commit subjects are `type: what changed`, without a parenthesized scope. Types: feat, fix, refactor, test, docs, build, chore. Use fixups during work and autosquash before delivery. - `git-collab issue list` is the live backlog. The commit-msg hook stamps Patch trailers; batch collab writes because each can sync with origin. See [testing rationale](docs/testing-practices.md) for the incidents behind these practices. [README](README.md) covers usage; [decisions](docs/decisions.md) records design history. The old roadmap is historical, not the live queue.