pi-headless¶
Provenance¶
- Source:
.spec/spexcode/spec-cli/sessions/harness-adapter/pi-headless/spec.md - Source SHA-256:
879cbb9de612ac1e2193bc5055f09ffe85c1f128fb9e52dd8c80e1b203245ebe
pi-headless¶
pi's -p form is an independent harness adapter with id pi-headless, not a mode of the interactive pi
adapter. It keeps pi's materialized surface exactly, but replaces the interactive runtime with a resident
controller in the session's tmux window. It uses pi's default text output; --mode json is deliberately not
used because it can hang on the supported local runtime.
The adapter is literal object composition over piHarness for shim, contract, skills, trust, slash commands,
events, and session identity. Its runtime is record-backed: while the governed session record exists and is not
explicitly stopped it reports online; a missing controller, child, or rendezvous listener is surfaced by
delivery as a loud transport error. Human stop tears down the runtime and marks the retained record stopped,
so it reads offline until resume clears the marker and relaunches the same conversation. Its text output
remains a transport detail; the note timeline is the terminal-free conversation.
The controller starts a fresh turn with pi -p --session-id <id> <prompt>. A delivery first probes pi's
rendezvous socket. When a listener is present, the existing deliverViaRendezvous protocol sends
sendUserMessage(..., deliverAs: steer) into the live turn. When the listener is proven absent, the controller
spawns pi -p --session <id> <msg> to wake the exact saved conversation; --session-id is never used for this
path because it can silently create a new session. The controller remains resident so the tmux window is a
stable home for later deliveries and resumes.
The resident controller is a normal session-owned leaf, not a shared adapter runtime: launch registers its PID, whose argv carries the governed session id. Terminal close therefore has one finite proof chain: the identity-checked leaf and its target tmux session are gone, then both the controller socket and pi rendezvous listener must reject a connect probe before cold filing can commit. A live or unproven listener keeps the row intact; a readable record with those four target resources gone has no adapter-specific refusal left and proceeds through the ordinary worktree, branch, and record removal.
Each controller child reports a non-zero exit through the shared [[harness-adapter]] turn-outcome seam. The active
undeclared record therefore becomes error with the pi turn's exit code, while zero exits and an agent-authored
declaration that landed before teardown remain authoritative. Record-backed online still describes a controller
that can accept a later delivery; it no longer masks the failed turn.