Harness: pi (v3)
One of the three harness files a loop root reads beside the contract, published unchanged from the public export of the copy my own agents read.
- Source
- agent-docs/sources/loop/harness-pi.md
- Revision
- 0f4fd35
Read at launch with the contract and the charter.
Runtime and launch
-
Models: codex-lb
gpt-6.1-sol,gpt-6-astraonly; the guard blocks model, thinking and run-deadline overrides. -
Launch with the context’s loop-pi launcher. The message names the contract, this file, the charter, the closeout path and the
Standing:file with its sha256:You are the root. Read $PROTOCOL_SOURCE/sources/loop/contract.md, $PROTOCOL_SOURCE/sources/loop/harness-pi.md and <abs charter path> in full. Write <abs closeout path> last, then reconcile and reply (contract section 12). Standing: <abs path> sha256=<hex> -
Launch runs the preflight and snapshots the remote for the audit. A cross-repo charter needs
loop-pi-preflight <repo>andloop-pi-audit add <repo>first. -
Continuation arms on “You are the root” plus one closeout path. A wrong host or repository, a changed charter, or a
Standing:line that differs from the charter’sstanding:key refuses the launch. A Standing file that is missing or fails its sha256 still arms, with no grants and aloop-standing-rejectedincident. -
Recovery is automatic. After a provider error, a stalled request or a request-ceiling abort, continuation resumes the root. A quota error gets two retries (owner input resets), then stops; authentication, policy and context-length errors stop at once. Never relaunch yourself.
-
The loop-state extension records dispatch, return, watch and heartbeat events in
codex/state-<date>-loop<N>.jsonlautomatically. You write none of them;loop-state digest <log> --jsongives live lanes. The state log and lane-patch capture parse the brief’s first non-empty line,Lane: <id> · Task: <ID> (<title>) · Tier: routine|guarded(no·inside the title); a header that does not parse drops that lane from both.
Root load
LANES.mdstays the contract’s one line per live lane: add it with oneprintf '%s\n' ... >>at dispatch and delete it at land or park, in abashcall you already make (never one runningloop-gate-lock). Never rewrite it or add status prose;DECISIONS.mdis append-only. InQUEUE.mdmove rows between sections in place.- Combine the routine mandatory section 5 reviews since the last one into one
reviewerlane (Task: none (land review)) after landing; guarded reviews stay before landing, with the security brief. Edit the runLANE.mdCodeRabbit line so task lanes skip it; the root, or the compose lane its brief names, runs it once on each landing’s composed tree.
Routes
| Role | Agent | Model / thinking |
|---|---|---|
| implementation (default) | worker |
sol / medium |
| judgement, compose, board batches | senior |
sol / high |
| escalation (tripwire or owner-named) | senior-escalation |
astra / high |
| review and security review | reviewer |
sol / high |
| read-only mapping, sweeps, wave drafts | scout |
sol / low |
A missing agent is a harness fault: stop and say so.
Dispatch and repairs
- Every
worker,seniorandsenior-escalationlane: asyncsubagent {agent, task, worktree: true}, the complete brief astask, withLanding: returns candidateon its own line (the tree is kept only then). loop-pi keeps the tree and runs the lane in it, so a bareloop-gate-lock <name>gates it (cd … &&is refused). Scout, reviewer:subagent {agent, task}. Noworkflow, no model or thinking override. - 19 native async slots shared by parents and children; keep about 7 free. Only
seniormay spawn children (scout,worker,reviewer), and only when the brief grants a count. Depth 2 at most. - Repair rounds and answers resume the same lane’s run with new evidence (
subagentresume, which keeps its tree). Never poll a lane’s status between wakes. - Lanes never push (the guard refuses it); only the root’s
bashrunsgit push origin main. - A new
worktree: truelane needs a clean main checkout (ignored files are fine)./loop-closeoutremoves only verified clean landed trees; lane patches go to$LOOP_PI_RUN_DIR/lane-patches/.
Waits
- Wakes: a lane return, a
watch_startexit or awake_attimer. Process every return, then end withWAITING: <what> until <deadline>; continuation arms a timer for it. - Root CI and release waits: a bounded, quiet
watch_startthat exits on every terminal state. Lanes usewatch_processwithdeadline_sup to 3600. LOOP.md’s optionalci-statusreplacesghreads.- Heavy gates run only through
loop-gate-lock <name>rows underLOOP.md## Mutexes. One name runs one leg at a time, so a composed gate’s parallel legs (contract section 6) need a row each, each started under its own watcher. If one is refused, run the legs in turn and say so. - Give any
bashcall that can run past 15 minutes atimeout, or run it underwatch_start.
Owner questions
While the owner is present, ask in a message that also makes a tool call and append the question to
QUESTIONS.md. An idle-lane wake notice (Inspect subagent updates above.) is not an owner control.
Closeout sweep
- Stop async
subagentruns; list any that will not stop. - Push landed work with the root’s
bash(git push origin main). - Stop your watchers (
watch_stop) and timers (wake_cancel), then runloop-pi-audit closeout --run-dir "$LOOP_PI_RUN_DIR" --push-log "$LOOP_PI_RUN_DIR/push-log.jsonl"and report a nonzero result under## Notes, naming each flagged move the charter authorised. Remove no lane tree yourself: list them under## Notesand ask the owner to run/loop-closeout, which you cannot call. - Write the closeout file, then run the contract’s reconcile and reply (section 12, steps 5 and 6).
Turn endings
A message with no tool call ends your turn. Never end a turn with a summary that announces the next
step, an offer to carry on, a list of decisions none of which blocks the remaining work, or a
decision that this is a good place to stop. End a turn only when the closeout is written, when
paused, or when a lane, a watch_start watcher or a wake_at timer will wake this session; when
waiting, arm wake_at and make the last line `WAITING: <what> until <YYYY-MM-DDTHH:MM[:SS]Z>`; when
paused, `PAUSED: <reason>`. Launch each lane as its own subagent call.