Decision Records
Architecture Decision Records
TL;DR. 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.
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 | Greenfield relative to zmx / zmosh | Accepted |
| 0006 | Input event types mirror libghostty’s API | Accepted |
| 0007 | Mosh-class transport semantics and satellite forward-compat | Accepted (forward-compat); impl deferred to v0.2+ |
| 0008 | Re-export libghostty-vt’s input/style types directly | Accepted |
| 0009 | phux is a protocol substrate; Mux is a product (no overlap) | Accepted |
| 0010 | Frontend-agnostic server; tmux control mode reserved as compat | Accepted (forward-compat); CC adapter not on the roadmap |
| 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 |
| 0013 | Libghostty bytes on the wire; structured input remains | Accepted (supersedes 0002) |
| 0014 | Server-side per-terminal actor pattern (!Send Terminal on a LocalSet) | Accepted |
| 0015 | Protocol layering: L1 substrate / L2 collections / L3 metadata; federation + automation as cross-cuts | Accepted |
| 0016 | TerminalId is the wire identity for a managed terminal; PaneId is removed | Accepted |
| 0017 | The reference TUI is one consumer among several, with no protocol-level privileges | Accepted (refines 0010) |
| 0018 | The wire is lazy state synchronization of libghostty Terminal state; ADR-0013’s pass-through bytes is the degenerate case | 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 verbs ride the generic COMMAND envelope; selectors resolve client-side; no session/window on the wire | Accepted (builds on 0017) |
| 0023 | Config UX: pure-config; defaults are a live embedded base layer; scaffold is a commented projection that never overwrites | Accepted (TUI-local, builds on 0017) |
| 0024 | The wire protocol owns its input atoms (phux-defined), so the codec builds on wasm32 | Accepted (amends 0008) |
| 0025 | Browser web client over a WebSocket transport; reuses the wire codec + libghostty engine, no reimplementation | Accepted (builds on 0017, 0024) |
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.
Template
# NNNN — Short title
Status: Proposed | Accepted | Deprecated | Superseded by ADR-NNNN
Date: YYYY-MM-DD
## Context
What is the situation that calls for a decision?
## Decision
What was decided.
## Rationale
Why this and not the alternatives.
## Tradeoffs
What we give up.
## Alternatives considered
Brief sketch of the other candidates and why they lost.