phux docs
architecture

System shape diagram

phux is a libghostty-backed control plane that serves resources.

evolving document
Full source summary

phux is a libghostty-backed control plane that serves resources. The canonical state of every resource lives server-side behind a kind engine; clients attach over one frame codec on any of five byte streams and keep local replicas for rendering. This sketch shows the path from a Terminal's PTY through the server and the wire to a client's screen, and where a producer-fed AgentSession joins it.

┌──────────────┐                     ┌────────────────────────────┐
│     PTY      │  shell / agent      │  agent harness shim        │
│   (child)    │  process            │  (`phux agent emit`)       │
└────────┬─────┘                     └──────────────┬─────────────┘
         │ VT bytes                                 │ JSONL records
         ▼                                          ▼ APPEND_RESOURCE_OUTPUT
┌────────────────────────────────────────────────────────────────────┐
│   SERVER (one per user, one current-thread runtime + LocalSet)     │
│                                                                    │
│   ServerState (std::sync::Mutex; never held across an await)       │
│     registry (sessions, windows, resources + parents) · id bridge  │
│     L3 metadata store · leases · ResourceTable (ResourceHandles)   │
│                                                                    │
│   one spawn_local task per resource = ResourceCore + kind engine   │
│   ┌──────────────────────────────┐   ┌──────────────────────────┐  │
│   │ Terminal engine              │   │ AgentSession engine      │  │
│   │ (resource::terminal,         │◄──│ (record ring; parent =   │  │
│   │  ADR-0014)                   │   │  the Terminal)           │  │
│   │  - libghostty Terminal       │   │  append + JSONL bootstrap│  │
│   │  - PTY reader/writer threads │   └──────────────────────────┘  │
│   │  - input encoders            │                                 │
│   │  - bootstrap cuts (ADR-0070) │                                 │
│   │  - state-sync + detector tick│                                 │
│   └──────────────────────────────┘                                 │
└───────────────────┬────────────────────────────────┬───────────────┘
                    │ per-connection                 │
                    │ FrameReader / FrameWriter      │
                    ▼                                ▼
       ┌────────────────────────────────────────────────────────┐
       │  one frame codec, five byte streams                    │
       │  UDS · WebSocket · QUIC · WebTransport · SSH-stdio     │
       │                                                        │
       │  server → client: BOOTSTRAP_* / RESOURCE_OUTPUT bytes, │
       │                   lifecycle, EVENT, metadata           │
       │  client → server: INPUT_* atoms (Terminal kind only),  │
       │                   commands, metadata, append           │
       └──────────────┬─────────────────────────┬───────────────┘
                      │                         │
                      ▼                         ▼
┌────────────────────────────────┐   ┌──────────────────────────────┐
│  TUI client (phux-tui)         │   │  headless consumers          │
│                                │   │  phux agent verbs, phux-mcp, │
│  session kernel                │   │  phux-web, Cockpit via FFI   │
│  (phux-client-core)            │   │  (same kernel, no ratatui)   │
│   - libghostty replica per     │   └──────────────────────────────┘
│     Terminal-kind resource     │
│   - predictive echo            │
│  ratatui chrome                │
│   - layout tree, status bar,   │
│     sidebar, keybindings       │
│   - L3 metadata rendering      │
└────────────────┬───────────────┘

          terminal screen

Key invariants

Canonical state (server)

Each served resource is one spawn_local task: a generic ResourceCore (output sequence and broadcast, event fan-out, cancel token, control mailbox) embedded in the engine for its kind. The runtime holds a Send + Clone ResourceHandle per resource in the ResourceTable and reaches Terminal-only channels through ResourceHandle::terminal(). For the Terminal kind the engine owns the libghostty_vt::Terminal: the full parsed grid, modes, parser continuation, and retained history, fed by the PTY and supervised on the LocalSet (threading.md). Sessions and windows are grouping metadata over resources, not a collection tier (data-model.md).

Local replica (client)

A client keeps its own libghostty_vt::Terminal per attached Terminal-kind resource as a replica for rendering. It is never the source of truth: it renders, caches what was painted last frame, reconciles predictions when server bytes arrive, and serves scrollback search and selection locally. Both engines are the same libghostty parser; nothing re-encodes in the middle (ADR-0013).

The frame seam, not a trait

There is no Transport trait. The server’s accept loop is generic over a listener that yields a FrameReader / FrameWriter pair per connection; the client holds one enum of each behind its Connection; the hub’s satellite links have their own pair. Above the seam nothing names a stream type. Details in transport.md.

Data direction

  • PTY -> server -> wire -> client: VT bytes (Terminal output), after a per-client capability rewrite on the synthesized profiles and untouched on the native profile (ADR-0070).
  • Client -> wire -> server -> PTY: structured input events (key, mouse, focus, paste), encoded to PTY bytes on the server’s input lane.
  • Producer -> wire -> server -> subscribers: for a producer-fed kind, appended records fan out as opaque output bytes under that kind’s codec (ADR-0103).

The wire is asymmetric: one direction is bytes, the other is structured events. That is the core invariant from ADR-0013.


Scopes

ScopeLivesCarries
ResourceServer (L1 wire)Id, kind, optional parent, lifecycle, ordered output stream, bootstrap, events
Terminal (kind 0)Server (L1 facet)PTY, canonical grid, cols/rows/title/cwd, structured input
AgentSession (kind 1)Server (L1 facet)Provider, native id, derived state, appended JSONL records; always a Terminal child
Session / WindowServer registry + TUI (L3 metadata)Grouping, layout tree, focus
PaneTUI clientA Terminal-kind resource in a layout slot

The wire defines resources and their facets. The TUI defines sessions, windows, and panes as one way to arrange Terminal-kind resources. A headless consumer speaks L1 plus whatever L3 keys it chooses.


Cold-read digest

  1. Start top-left: the PTY emits VT bytes; a harness shim emits records.
  2. Into the server: one engine per resource owns canonical state.
  3. Across the seam: one codec, five streams; bytes one way, structured events the other.
  4. Client side: a libghostty replica per Terminal-kind resource mirrors the server for rendering.
  5. Chrome: ratatui decorates the grid with layout, status bar, sidebar.

Status

No remaining target-versus-shipped gaps in the sketched shape. The AgentSession engine, APPEND_RESOURCE_OUTPUT, and parent-cascade CloseReason::ParentClosed all run in this tree. Product-wide gaps live in ../CONCEPTS.md.

GapTodayOwnerTracked

See also

View exact source