Skip to content

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.