Process model
One server per user hosts every session for that user; clients are separate processes attached over a Unix socket.
Full source summary
One server per user hosts every session for that user; clients are separate processes attached over a Unix socket. The single phux binary contains both halves and dispatches by subcommand; an attach auto-spawns a server if none is listening. Runtime paths live under $XDG_RUNTIME_DIR/phux/; persistent per-user state — logs, TLS material, token store — lives under $XDG_STATE_HOME/phux/.
The runtime path resolution lives in
phux-server/src/runtime/mod.rs: the
socket is $XDG_RUNTIME_DIR/phux/phux.sock when that variable is set,
otherwise /tmp/phux-$UID/phux.sock. The parent directory is created
mode 0o700.
The persistent per-user state directory is real. It resolves via
phux_server::telemetry::state_dir() in
phux-server/src/telemetry.rs
to $XDG_STATE_HOME/phux/ (falling back to $HOME/.local/state/phux/
when XDG_STATE_HOME is unset). Its current inventory:
$XDG_RUNTIME_DIR/phux/phux.sock # SOCK_STREAM, perms 0o700 dir
$XDG_STATE_HOME/phux/ # per-user state dir (telemetry::state_dir)
├── server.log # THE canonical server log, both spawn paths
│ # (telemetry::server_log_path)
├── client-<pid>.log # per-pid client/TUI logs
├── remote-tokens # versioned remote credential store (ADR-0031)
├── remote-cert.pem # auto-provisioned TLS cert (ADR-0031)
├── remote-key.pem # auto-provisioned TLS key (ADR-0031)
├── service-wrapper.sh # `phux service install --restore` wrapper
└── workspace.json # `--restore` workspace snapshot
Server logging: a hand-started foreground phux server logs to stderr
(plus an optional PHUX_LOG file tee). Both detached spawn paths — the
auto-spawn daemon and a phux service-installed unit — redirect the
server’s stderr to the one canonical server.log above, resolved
through telemetry::server_log_path() so writers and readers
(phux service logs) can never disagree. The startup line carries
pid + version + socket to attribute interleaved writers.
The single phux binary contains both server and client logic; the
subcommand dispatches. phux server runs the daemon in the foreground;
phux (no args) becomes a client and lazily spawns a server if none is
listening on the socket. The auto-spawn follows tmux’s convention so a
user never has to start a daemon by hand.
Noninteractive coordinator startup
Native consumers such as Cockpit can invoke the same startup owner without entering the TUI:
phux --socket /absolute/path/to/phux.sock server --ensure
--ensure is availability-only: reuse a live server or auto-spawn one
with the same session-name template and spawn-on-attach policy as naked
phux, then exit. It does not attach, handshake, or reconcile a running
coordinator’s binary version. Pass the consumer’s selected socket
explicitly so a development binary’s profile default cannot select a
different coordinator. Flag contract, exits, and the 10-second deadline:
phux server.
Terminal engine timers
Inside the server, a PTY-backed Terminal engine (resource::terminal, the
per-resource actor of ADR-0014) runs two independent
timers on its select!: the state-sync tick that paces output emission to its
consumers, and a second, slower agent-state detector tick
(ADR-0046) that
re-derives the pane’s phux.agent/v1 record from the PTY’s foreground process,
the OSC title, and the live screen, and publishes the privacy-bounded
phux.pane-occupant/v1 foreground basename/shell answer from the same process
query. The detector is a different surface from an AgentSession resource: it
runs on the Terminal, and a live AgentSession child outranks it on the
evidence ladder. The detector timer is the sole driver of
that work — PTY bytes never wake it — so a chatty pane costs no extra
detection. It is constructed only for a PTY-backed engine, only when a rule set
loaded, and it publishes through its own mpsc channel to a per-terminal drain
task that owns the metadata write. No new process, no new thread.
Status
Predictive local echo
Predictive echo is implemented as an opt-in client feature. It renders a conservative set of likely keystroke results with an underline, keeps the...
Render layering: ratatui chrome over libghostty pane interiors
The phux TUI uses two renderers on disjoint screen regions. libghostty paints pane interiors on the hot path so kitty graphics, sixel, OSC 8, and the Kitty...