phux docs
concepts

How phux works

phux is a terminal multiplexer. Your shells live in a background server.

stable document
Full source summary

phux is a terminal multiplexer. Your shells live in a background server. You split them into panes, detach, and they keep running. Each pane is a live terminal object on a wire, so the TUI, Cockpit, a script, or an agent attach to the same one. Nobody screen-scrapes. Nobody holds a second copy.

      your programs: zsh, vim, htop, an agent's shell

                          │  PTY

 ┌─────────────────────────────────────────────────┐
 │ phux server -- keeps running when you leave     │
 │                                                 │
 │ libghostty terminal: the real one. Screen,      │
 │ scrollback, and modes live here, so they        │
 │ survive detach and feed every attach.           │
 └───────────────┬──────────────────▲──────────────┘
                 │                  │
     output goes │                  │ input comes back
     down as raw │                  │ up as structured
     VT bytes,   │                  │ key, mouse, and
     verbatim    ▼                  │ paste events
 ┌──────────────────────────────────┴──────────────┐
 │ attach: TUI, CLI, web, Cockpit                  │
 │ several clients share one live terminal;        │
 │ detach does not copy it                         │
 └─────────────────────────────────────────────────┘

The server holds the terminals. The TUI, CLI, web, and Cockpit attach to those same ones. Detach does not copy.

Resources

A resource is a server-owned, addressable thing. Every resource has:

  • a kind and a stable id;
  • a lifecycle: spawned, then closed with a reason (Exited, Killed, ParentClosed, ServerShutdown);
  • an ordered, opaque output stream with a codec, and a bootstrap a consumer loads before live bytes;
  • a kind-defined input channel;
  • a tagged event stream;
  • metadata, and an optional parent set at spawn and immutable.

Terminal is the first kind: a PTY child and a libghostty engine, with columns, rows, a title, and a working directory. Operations that only make sense there — typed input, resize, screen reads — are refused on any other kind.

AgentSession is the second kind, and this checkout serves it. The server advertises RESOURCE_KINDS; the runtime creates the resource; phux agent session open|close, phux agent emit, and phux agent log are the producer and reader verbs; %name resolves one. It is the structured event stream of an agent harness, bound to the Terminal the agent runs in. Closing the parent closes the child; closing the child never touches the parent.

phux agent show is a different surface: it reads agent state from a pane, not from an AgentSession resource.

Sessions, windows, panes, and splits are not a lifecycle tier. “Pane” stays a TUI and CLI word for a Terminal-kind resource in a layout slot, expressed as metadata and client logic.

The wire

The wire carries four things:

  • Identity. A ResourceId is Local { id } or Satellite { host, id }. A hub retags inventory with satellite ids; it does not merge remote session or window models. Selectors render as @42 and prod-box-3/@42.
  • Lifecycle. Spawn with a kind and an optional parent; close with a reason; parent cascade; atomic KILL_RESOURCES.
  • Bytes. Opaque per-kind output (bootstrap and live). Structured input atoms for a Terminal; appended records for an AgentSession. Both ends run the engine for the kinds they show; the wire is not a second screen model.
  • Metadata. Opaque key-value pairs. The server stores them; it does not interpret them.

There is no L2 collection tier. Group membership is metadata plus client logic; atomic teardown is a single L1 operation. See spec/L2.md.

The byte-level codec is spec/appendix-encoding.md. L1 is spec/L1.md; metadata is spec/L3.md.

Consumers are peers

The reference TUI, the headless CLI, the browser client, and Cockpit are peers. None has protocol-level standing: if a consumer needs a capability the wire does not provide, the answer is an ADR that extends the spec, not a consumer-shaped hook (ADR-0017).

A consumer that wants structured state carries the engine for the kinds it shows. One that does not render a kind lists it and draws none of it.

Maturity

The protocol is 0.9.0, pinned in phux-protocol and mirrored by spec/; a CI gate keeps the two in sync. Spec leads the code.

This checkout serves both resource kinds. Confirm with phux status --json: a server that advertises RESOURCE_KINDS has AgentSession. Older brew or curl releases may not.

The long arc lives in vision.md. This page owns the Status table below; other docs link here rather than restating the gaps.

Status

Target-versus-shipped gaps as of the last review. Each row names the ADR that owns the target and the bead that tracks the work.

GapTodayOwnerTracked
Working-directory and command-boundary events as an L1 Terminal-facet frameTERMINAL_EVENT has no codec entry. cwd_changed, command_started, and command_finished reach consumers only through the SUBSCRIBE_RESOURCE_EVENTS gate path.ADR-0015phux-ue2r
On-disk output journal and crash recoveryThe server keeps every resource in memory. Nothing is journaled and there is no recovery flag.ADR-0092phux-p91i
Workload authentication enforcementThe phux-workload/v1 profile is allocated in the spec. The reference server accepts no proof and enforces no scope matrix.ADR-0098phux-cockpit-p1q.11.2

Where to go next

You want toRead
Run itQUICKSTART.md
Understand the wire bytesspec/README.md
Understand how the server is builtarchitecture/README.md
Drive it from an agentconsumers/agents.md
Use the browser clientconsumers/web.md
Use Cockpitconsumers/cockpit.md
Understand the TUI surfaceconsumers/tui.md
See why we decided X../ADR/README.md
Read the long arcvision.md
Contribute../CONTRIBUTING.md
View exact source