Decision Records
Index of every decision that has closed off a design space in phux.
Full source summary
Index of every decision that has closed off a design space in phux. Format and Status: vocabulary defined in ../docs/CONVENTIONS.md. Read these when you need to know why something is the way it is — the architecture docs describe what the code is.
Read a decision when you need the reason a design space was closed. Use architecture for the current system shape.
We write down decisions so future contributors (including future-us) can understand why the system is the way it is. Format follows Michael Nygard’s template.
Index
| # | Decision | Status |
|---|---|---|
| 0001 | Use Rust | Accepted |
| 0002 | Diff-based wire protocol, not VT byte replay | Superseded by 0013 |
| 0003 | Single server, many sessions | Accepted |
| 0004 | libghostty-vt is the canonical grid | Accepted |
| 0005 | Relationship to zmx and zmosh | Accepted |
| 0006 | Input event types re-export libghostty-vt’s atoms | Accepted (amended by 0024) |
| 0007 | Mosh-class transport semantics and satellite forward-compat | Accepted (forward-compat; superseded in part by 0098) |
| 0008 | Use libghostty-vt’s types directly; stop reimplementing them | Accepted (amended by 0024) |
| 0009 | phux vs coder/mux: positioning | Accepted |
| 0010 | phux is TUI-first, non-TUI not precluded; tmux control mode reserved as compat option | Accepted (forward-compat; superseded in part by 0017) |
| 0011 | phux-protocol and phux-core are independent; IdBridge is their only meeting point | Accepted |
| 0012 | Window layout is a binary split tree, not n-ary | Accepted (superseded in part by 0015) |
| 0013 | Libghostty bytes on the wire; structured input remains | Accepted (supersedes 0002) |
| 0014 | Server-side Terminal placement: per-pane PaneActor on a LocalSet | Accepted |
| 0015 | Protocol layering: L1 substrate, L2 collections, L3 metadata | Accepted (superseded in part by 0030) |
| 0016 | TerminalId as the wire primary; PaneId is a consumer-side alias | Superseded by 0102 |
| 0017 | The reference TUI is not protocol-privileged | Accepted (supersedes in part 0010) |
| 0018 | Lazy state synchronization is the wire’s long-arc shape | Accepted (builds on 0013) |
| 0019 | Multi-pane TUI rendering: layout persistence, wire shape, and chrome | Accepted |
| 0020 | Layered render: ratatui chrome over libghostty pane interiors | Accepted |
| 0021 | Control-plane commands and client-side selector resolution | Accepted (superseded in part by 0030) |
| 0022 | phux as a tool for agents | Accepted |
| 0023 | Config UX: pure-config, defaults as a live base layer | Accepted (builds on 0017) |
| 0024 | The wire protocol owns its input atoms | Accepted (amends 0006, 0008) |
| 0025 | Browser web client over a WebSocket transport | Accepted (builds on 0017, 0024) |
| 0026 | Overlays: one theme, a real stack, and a single dispatch path | Accepted (builds on 0020) |
| 0027 | Terminals are referenced, not owned: views, links, and L3 tags | Accepted (builds on 0017, 0015) |
| 0028 | Runtime log control | Accepted (forward-compat; builds on 0024) |
| 0029 | One cursor authority and a repaint scheduler | Accepted (builds on 0020) |
| 0030 | Engine-delegated wire and projection consumers | Superseded by 0102 |
| 0031 | Remote-consumer authentication and encryption (no SSH tunnel) | Proposed |
| 0032 | Graceful server upgrade (sessions survive a binary update) | Accepted |
| 0033 | Input authority leases and process signals (“take the wheel + kill”) | Accepted |
| 0034 | Kitty graphics / image passthrough through the cell renderer | Proposed |
| 0035 | Agent-asked event: a pending human-answerable question on the wire | Accepted |
| 0036 | Agent-asked detection sources | Accepted |
| 0037 | Overlay-network reachability for remote self-host consumers | Accepted (forward-compat; builds on 0007, 0031) |
| 0038 | Hub-to-satellite authentication | Accepted (builds on 0031) |
| 0039 | Layered config: an ordered extends stack with explicit array append | Accepted |
| 0040 | Agent identity and lifecycle are an L3 metadata record | Accepted |
| 0041 | Managed plugin installs: snapshot fetches, system tools, one lockfile | Accepted |
| 0042 | Launch executor: a CLI verb that spawns an integration template | Accepted |
| 0043 | State-diff output mode and loss-tolerant reference advance | Accepted |
| 0044 | Dedicated input lane: route input off the single runtime thread | Accepted |
| 0045 | Client-side copy-mode over the consumer’s own engine | Accepted (builds on 0030) |
| 0046 | The server derives agent state; detection is level-triggered | Accepted (builds on 0040) |
| 0047 | CI metrics recorded to an orphan ci-metrics branch | Superseded by 0082 |
| 0048 | Drag-to-resize panes and default outer-terminal mouse capture | Accepted |
| 0049 | Client-local focus and advisory agent attention | Accepted (builds on 0019) |
| 0050 | Explicit spawn ownership, client-owned placement | Accepted |
| 0051 | Outbound dial-out (connector) transport mode | Accepted (builds on 0037) |
| 0052 | Connector route identity, registration, and config surface | Accepted (builds on 0051) |
| 0053 | Acknowledged idempotent input batches | Accepted (builds on 0021, 0024, and 0044) |
| 0054 | Worktree-bound sessions by name convention | Accepted |
| 0055 | Always-on server and ssh-bootstrapped enrollment | Accepted (superseded in part by 0080, 0096) |
| 0056 | Cross-session Terminal move | Accepted (builds on 0050) |
| 0057 | A minimal reference relay in-tree | Accepted (builds on 0051, 0052) |
| 0058 | Right-click context menus for panes, windows, and sessions | Accepted |
| 0059 | Sandboxed chunked file upload | Accepted (builds on 0007, 0021, and 0031) |
| 0060 | Self-contained session recording | Accepted (builds on 0013) |
| 0061 | Capabilities add, versions break | Accepted (builds on 0060) |
| 0062 | Headless resize and the window-size policy | Accepted (builds on 0027) |
| 0063 | Ephemeral server lifetime | Accepted (builds on 0003) |
| 0064 | Playback as a pane | Accepted (supersedes in part 0060) |
| 0065 | One CLI grammar | Accepted |
| 0066 | One phux host namespace over the split machine registries | Accepted |
| 0067 | Cache-preserving agent fleet context | Accepted (builds on 0040, 0046) |
| 0068 | Native agent-session restore | Accepted (builds on 0040, 0042) |
| 0069 | Generated reference docs from the compiled binary | Accepted |
| 0070 | Native engine-state bootstrap and client-owned history | Accepted (builds on 0013) |
| 0071 | What phux 1.0 commits to | Proposed (builds on 0061) |
| 0072 | Prune the policy vocabulary, keep the authorization seam | Proposed (amends 0031) |
| 0073 | Login-shell semantics for service-managed pane spawns | Accepted (builds on 0055) |
| 0074 | The self-update trust boundary | Accepted (builds on 0071) |
| 0075 | Agent names are addressable, and a withdrawn name is refused | Proposed (builds on 0021, 0040) |
| 0076 | Prompting an agent is acknowledged; waiting on one is event-driven | Proposed (builds on 0053, 0046) |
| 0077 | The agent read surface: sources, soft wrap, and truncation | Accepted (builds on 0022) |
| 0078 | Harvesting alternate-screen history | Proposed (builds on 0077) |
| 0079 | Fatal-signal terminal restore | Accepted |
| 0080 | Socket lifecycle and instance isolation | Accepted (amends 0055) |
| 0081 | Overlay auto-listen and one-command pairing | Accepted (builds on 0037, 0031) |
| 0082 | Retire the CI metrics store; the run page is the dashboard | Accepted (supersedes 0047) |
| 0083 | In-place supervisor unit reconcile | Accepted (builds on 0080) |
| 0084 | Starting an agent in an existing shell | Accepted (builds on 0042) |
| 0085 | Hook-sourced agent state is detector evidence | Accepted (builds on 0040, 0046) |
| 0086 | The pooled libghostty render trio lives in phux-protocol | Accepted |
| 0087 | Elastic status-bar space is row-wide slack, not slot layout | Proposed (builds on 0071) |
| 0088 | Adopting a live server into supervision | Accepted (builds on 0055, 0080) |
| 0089 | The sidebar is a bounded attention inbox, not a structural list | Accepted (amended by 0112) |
| 0090 | Predictive echo returns to the alt screen via confirmation-gated display | Accepted |
| 0091 | The certificate names the advertised address, once, at generation | Accepted (builds on 0031) |
| 0092 | The coordinator owns durable work | Proposed (amends 0009) |
| 0093 | --remote user@host is a resolution ladder, not a new transport | Accepted |
| 0094 | Per-pane scrollback is bounded in bytes, by phux, explicitly | Accepted |
| 0095 | Blackbird is a peer ledger, not a phux client | Accepted (builds on 0040) |
| 0096 | Performance telemetry is always on, in-process, and one command away | Accepted |
| 0097 | Durable coordinator is a separate bounded endpoint | Accepted (forward-compat; builds on 0092, still Proposed) |
| 0098 | Workload proof and closed-scope authority | Accepted (forward-compat; amends 0031) |
| 0099 | CI: one aggregate merge gate, immutable action pins, and shared lane setup | Accepted |
| 0100 | The TUI is its own crate | Accepted (builds on 0020) |
| 0101 | The settings page edits the file | Accepted (builds on 0023) |
| 0102 | Resources: the server serves kinds; Terminal is the first | Accepted (supersedes 0016, 0030) |
| 0103 | Agent session resource and producer-fed streams | Accepted (amends 0040) |
| 0104 | Parent bindings are L1 lifecycle | Accepted (builds on 0102) |
| 0105 | Sessions can outlive their last window | Accepted (amends 0063) |
| 0106 | Identity is the serving user; whoami reports it | Accepted (builds on 0003) |
| 0107 | Satellite sessions are listed, never adopted | Accepted (builds on 0066) |
| 0108 | A hub relays host queries to satellites per request | Accepted (builds on 0107) |
| 0109 | Late kills are conditional on instance and attachment | Accepted (builds on 0007) |
| 0110 | A showing peer is re-shown at launch only in front | Accepted (amended by 0111) |
| 0111 | How a front restore is judged | Accepted (amends 0110) |
| 0112 | Sidebar navigation stays put while status changes | Accepted (amends 0089) |
| 0113 | Opt-in next channel from green main | Accepted (builds on 0074) |
| 0114 | Cockpit closes terminals and detaches windows | Accepted (builds on 0105, 0107) |
When to write an ADR
- Picking between viable approaches with long-term consequences.
- Closing off a design space (deciding against something).
- Anything you’d want to explain to a new contributor on day one.
When NOT to write an ADR
- Bug fixes.
- Refactors that don’t change behavior.
- Anything purely internal to a single function.
Format
The template, the Status: vocabulary, the 150-line cap, and the
supersede-don’t-amend rule are defined once, in
docs/CONVENTIONS.md under “ADR template”. Copy
the template from there; this file carries only the index.