System reference · Part 4
The driver and its hosts
The stateless driver, what it refuses to do, the one-fix review loop, claims and parking, the interactive and headless hosts, and the autonomy dial.
What the driver is
The driver, .claude/scripts/pipeline-driver.sh, is a stateless pass over durable state. It reads the tree, works out what is ready, does one thing per node, and exits. Nothing important lives in the process, so killing it costs nothing and resuming it is the same code path.
The consequence worth understanding is that a person doing a step by hand between invocations is absorbed for free. The driver never tracks a sequence and never replays a history. Each pass compares what each node has recorded against what the evidence implies, and closes the gap by asking the gate — never by re-implementing the gate's logic. "All children closed but the container still records delegate" becomes one children_terminal question. A review done by hand becomes one review_verdicts question. The gate passing is the evidence.
A pass runs read, decide, act, exit. The read produces one snapshot holding every node in scope with the manifest embedded, so the decision runs over exactly one document. The decide step is a pure core: snapshot in, action list out, no side effects, no clock, no tracker access. It can be run against a canned snapshot and is identical on re-run, which is what makes it testable. Every effect in the act step goes through the transition script.
The read is one tree read per snapshot. The driver lists the whole store once and shows every node in scope, plus every ancestor of each scope root, in one multi-id show; every per-node fact is derived from those two calls, the manifest and the spec files on disk. Kind and effective autonomy come from one call to the transition script's tree-facts verb over that read, which applies the same walkers as the single-bead kind and autonomy verbs, so those rules keep a single owner. Because a multi-id show silently omits a bead it cannot find, the read compares what came back with what it asked for and escalates any shortfall as a vanished bead. Nothing is kept between snapshots: a pass builds one snapshot per cycle, and each reads the tree afresh, so the tracker stays the only state. A new per-node fact must come from the tree read or from tree-facts, never from a per-node tracker call; the reconcile suite counts the calls one snapshot makes and fails above two.
Every rest says why. A rest is a node the pass leaves waiting: for a person, behind a blocker, under another holder's claim, dead-lettered, serialized behind a sibling, or for an attended host. That last rest falls on a bead whose spec's file_scope lands on the enforcement surface when the pass would hand its work to a headless session, which the surface guard denies; the driver reads the surface from the guard itself (--print-surface), spends no attempt, and the cockpit runs the work in-session. Every rest the core decides carries a one-line reason, and a held human gate names the autonomy level that held it. Where a proposal waits on a person, the rest also lists that person's answers (approve, revise, park), in the same field a failed review uses for its per-finding decision. The pass ends by naming each resting node with its step and reason, once as a line of narration and once in the envelope's resting list, so a reader never has to dig through bead notes to learn what is owed.
What the driver will not do
Six refusals, each protecting something specific:
- It will not advance a human-gated step. With a proposal pending it waits. With no proposal it may dispatch the step's work, because doing work is not approving it. The exceptions are the autonomy dial's: a gate the node's level relaxes, and a held gate whose proposal has gone unanswered past the level's silence window (The autonomy dial, below).
- It will not auto-complete a step whose floor list is empty. An empty list means no deterministic evidence exists, and completing would be advancing on nothing.
- It will not act on a node another holder has claimed. It claims first, always; a refused claim means another holder has the node. A claim never expires and only its holder or a person removes it, so the driver rests the node and names the claim rather than taking it over, however old it is. The driver never clears a claim.
- It will not guess idempotency. Every dispatchable step declares how a killed attempt resumes — either discard the partial work and rerun clean, or inspect what exists and continue. A dispatchable step that declares neither escalates.
- It will not dispatch work on a node whose declared blocker has not landed. A
blocksedge in the tracker says that the blocker's work must land before this node's may start, and a bead has landed when it is closed. Such a node comes to rest with a reason naming the blockers. Only theblocksedge gates: a parent-child edge would deadlock the whole tree, because every child carries one and a container stays open until its children close. The gate stops new work from starting and never withdraws work already recorded, so a node whose agent has already proposed its artifact still waits on its human, not on the blocker. - It will not spend more than the manifest's fix rounds. When a floor declares that a fix is owed, the driver dispatches the step's fix command at most
fix_roundstimes — one, for review — and only under an autonomy level that holds the fix licence. At the cap, or without the licence, the node rests for a person, naming the failing axes and the per-finding decision. There is never a third review round.
A step with both a floor and a command
The floor is asked first. That ordering is what makes hand-done work integrate for free. If the floor refuses, the refusal is durable, so the next pass reads it and dispatches the work the floor named.
That last clause is a correction to earlier behaviour, and it is worth recording because the failure it fixes was invisible. Previously the floor branch preceded the command branch unconditionally, and a refusal only ever produced another identical decision. The review step declares exactly that shape — both a floor and a command — so an unattended run could never get a reviewer spawned. Each pass asked the floor, was told no, recorded the node as ready, and ended having done nothing. The outer loop saw "ready", started another pass, and after sixteen identical passes hit its repeat limit and reported the limit rather than a fault. It looked like a stall rather than a bug. The reviewer was never spawned, not once.
Refuse-then-dispatch alternates without ever counting a failed attempt. That is deliberate: a wave-mode leaf waiting on a human merge refuses on every pass and must not be abandoned as broken.
When the review fails the current code — one fix, then a person
Refuse-then-dispatch used to infer which work a refusal demanded from the shape of the step: the step declares a command, so the command must be what is owed. For the review step that guess was wrong in one case that mattered. When the latest review fails an axis and it read the code at the project's current head, the reviewer has already judged exactly this code, and running it again can only return the same verdict. On 8 October 2026 an unattended run spent two review rounds on one commit that way, then parked the piece as broken after its dispatch attempts ran out. It looked like an expensive step rather than a defect, because a review being run is what the review step is supposed to look like.
The floor now says which work its refusal demands. A failure on the current code opens the refusal with a short token declaring that a fix is owed and naming the failing axes; a failure on older code, or no usable review at all, carries no token and still means "run a review". The driver records the token as two fields of the exit record (owed= and axes=), and the decision core chooses by it:
- No owed work — the step's own command, exactly as before.
- A fix owed — the review step's fix command,
.claude/commands/coding-planner/remediate.md, dispatched at the same step. Nothing rewinds, because the piece really is at review: its review is unfinished. The fix agent addresses the CRITICAL findings on the existing task branch, commits, updates the walkthrough and stops; WARNING findings go to the pull request for a person. The dispatch needs a licence from the autonomy dial (below), and it is capped by the review step'sfix_roundsin the manifest, which is one. - A person owed — nothing is dispatched at any level. The findings ledger's refusals carry this token: a carried CRITICAL left unanswered, answered with a word outside the three, still standing at a passing close-out, or answered against a different predecessor. A fix cannot discharge any of them, because nothing says the code is wrong, and another review would inherit only what the unaccounted review carries, so a dropped finding would be laundered rather than recovered.
The cap is what makes the loop end. The fix moves the head, so the next refusal is staleness and the reviewer runs once more as round two, judging the round-one findings plus the fix. A pass sends the piece on to its pull request and clears the fix-round count. A second failure, or a fix that changed nothing, finds the one round already spent, and the piece rests for a person with the failing axes, the spent round and a decision per finding: fix it, accept it with a note, or file it as its own piece of work. The round is spent at dispatch: the driver records it before the fix agent runs, and if that record cannot be written it does not dispatch the fix at all and escalates instead. A fix agent commits before it finishes, so a round counted only on success could be lost when the agent then failed or the driver was killed, leaving the code changed with the round unspent and a second fix to follow. The count lives in its own field, never in the attempt counter, so resting never parks a piece as broken.
A rest here is a re-ask, not a memory. Each pass still asks the floor, so a person who fixes the code or writes a passing review by hand is absorbed on the next pass, and the rest is always recomputed from the world.
Claims, attempts, and parking
Before the driver acts on a node it writes a claim on it, naming the pass that holds it: pipeline.lease reads holder=<token> since=<iso>. The key keeps its old name; the record has no expiry, and nothing compares it with the clock (the lab's no-lease ruling of September 2026). The holder releases its claim when it finishes acting. Another holder's claim, of any age, refuses a new claim, so a pass that finds one rests the node running, names the holder, the time and the clear command, and offers the person two answers: wait, or clear the claim. That is deliberate: a dispatched agent session can run for hours, and a claim that expired would let a second pass take it over and start a second agent in the same worktree while the first was still working.
A claim left behind by a pass that died therefore stays until a person judges the claimant dead and clears it: .claude/scripts/pipeline-transition.sh release --bead <id> --clear --reason "<why>". The clear notes the holder, since, who cleared it and why. It is refused alongside --holder, without a reason, and in a dispatched session (VOX_AFK=1), because a claim is cleared by a person's judgment and never by an agent. It records no exit and counts no attempt. The clear is the kick: the next pass finds the node unclaimed and acts on it from its recorded state, and a dispatch the dead claimant had begun resumes under the step's declared resume semantics. A record in the older shape, with expiry fields and no since, reads as a plain claim by its holder "since an unrecorded time"; the expiry fields mean nothing.
Failed attempts are counted per step and cleared on success, and no other exit counts toward the limit. When attempts reach a configured limit the node is parked in a dead letter state until a person clears it.
Ready siblings under one parent whose specs declare overlapping file scope are serialised: the first dispatches and the rest wait behind it, named. Undeclared scope overlaps nothing.
A dependency wait looks like that and resolves quite differently, and the difference is the one that matters operationally. A serialised sibling is waiting on this loop: the sibling that won dispatches now, and the one behind it goes on a later pass, so the pass reports ready and the runner keeps going. A node waiting on a declared blocks edge is waiting on that blocker reaching closed, which takes a review, a landing and a human merge — no number of passes will clear it. The driver counts a dependency wait as blocked rather than ready, so a frontier where every open node is dependency-blocked rests instead of spinning the headless runner to its pass cap.
The hosts
The driver does not decide how an agent gets spawned; that is host wiring. Two hosts exist.
The interactive cockpit is a command file instructing a session to host one driver: invoke a pass, render the typed result plus the per-node reasons for anything at rest, ask the person at human gates — the gate is the asking, and the answer is what moves the run on — relay any steering, and invoke the next pass.
The headless runner exports a dispatch seam pointing at an executor, invokes the same pass, loops while the result says work is ready, and stops when every branch is blocked. It carries a spin guard: at a configurable pass cap it refuses loudly rather than looping, because the shape that needs it is an agent exiting successfully without ever recording work done, which moves no attempt counter.
Given --queue <epic>, the headless runner does not end when its root's tree rests. It asks the transition script's read-only queue verb for the epic's queue (beads discovered from the trees it drove, then the order recorded on the epic by set-queue, then the epic's ready execution:afk descendants by priority), takes the first bead it has not already taken, enters it with queue-enter (the task door at the epic's effective autonomy, wave when nothing sets one, PRP waived under the standing ruling) when no door has touched it, and drives it the same way. It ends when the queue offers nothing untaken, and its final envelope lists every bead that waits on a person, with the driver's reason or the reason the queue gave for not taking it. An escalated tree stops only that tree; the run exits 2 at the end so the escalation is not lost. A second cap, --max-beads, bounds the trees one run drives. A surface bead is not recognised here: it has usually not been specified when it is taken, so the driver's own rest for it is what reaches the envelope.
Neither host reimplements the loop. Without any host configured, dispatch actions are reported rather than performed.
Both hosts report from the same read-only verb, pipeline-driver.sh digest --root <epic> [--since <time>] [--json], which reads one tree, runs the decision core over it and prints what landed, what waits for a person and why, what is running and what the work discovered, writing nothing, so any session can answer "what has been done" from the beads alone.
The autonomy dial
Built, and narrow by design. A campaign — or any node under it — can carry a named autonomy level, written by the mode verb and validated against a table the manifest declares. Four levels: two relax nothing (hold and hitl, which differ only in what silence does, below); one lets an unattended run advance past the spec-authoring and implementation gates; one additionally relaxes the fan-out and integration gates, the last only when the campaign has an integration branch, because integrating unattended is licensed only where a mistake cannot reach main. A node's effective level is its own, else its nearest ancestor's, else nothing — resolved when the driver takes its snapshot, through the transition script's tree-facts reader over the snapshot's one tree read, so the decision core stays a pure function of recorded state. The integration-branch condition is the step's relax_requires in the manifest, and a value the scripts do not know never counts as met: the driver escalates and complete refuses a dispatched session.
Two things the dial can never do. It never touches a floor: every deterministic check runs identically at every level, because the dial removes a person's hand from advancement, never evidence from a gate. And it never acts silently: every advance under a relaxed gate carries a note naming the level and the node that supplied it, so the audit trail always shows where a human was absent.
A question that gets no answer stops holding. The lab decided in November 2026 that asking is good but that the pipeline continues when no answer comes. So each level also carries a silence window, in a third table beside the level table, autonomy.silence: a number of seconds, or null for never. A gate the level holds, on a step some level may relax, with a proposal pending, stops holding once that proposal has gone unanswered for longer than the window. propose records when the proposal was made (pipeline.proposed), the driver's snapshot carries that date and the snapshot's own clock, and the decision core compares them, so the core stays a pure function of recorded state. The driver then advances the gate through complete --on-silence, which recomputes the same rule from the bead's metadata, the manifest and its own clock before it writes, and refuses when the rule does not hold. The flag only asks; a dispatched session whose gate is silent passes without it, because the dial now treats that gate as relaxed for the node. The transition note reads advanced on silence under autonomy level <L> from <node>: window <W>s, proposal <artifact> recorded <date> at step <s> went unanswered for <N>s, and the pass envelope lists each such advance under advanced_on_silence. The windows are hitl four hours, wave and deep two hours, and hold never: four hours lets the owner see a question raised in a working session, and work left at hitl overnight is moving again by morning. Some gates never advance on silence: the steps no level may relax (generate-design and create-prp, because the plan is the authority later work is delegated against), a step whose relax_requires is unmet (an unknown or malformed value is never met), a terminal step (integrate, whose own verb checks a dispatched caller against the dial alone and never reads the silence window), a node with no dial at all, and a deferred node.
Which level work enters at. The lab decided at the same time that the pipeline runs without stopping for confirmation. Work therefore enters at the loosest level it allows: a lone task and a campaign without an integration branch at wave, a campaign with one at deep. hitl is kept for work the owner asks to watch, and hold for work the owner says must wait. The sessions that host the driver follow the same ruling: a gate the dial holds is asked once and recorded on the bead while the session works elsewhere, work found mid-run is filed as beads and worked next, and a session that finishes its scope starts the next task. The router skill's Operating Posture and drive.md step 6 carry the rules.
The dial also grants one capability that is not a gate relaxation: the licence to dispatch a review fix with nobody watching. The review step has no human gate to relax — its checkpoint is a deterministic floor — so the licence lives in a second table beside the level table, autonomy.licences, where the middle and loosest levels hold it and the strictest holds none. Under the strictest level, or with no dial set at all, a failing review rests for a person instead of being fixed. The review floor itself runs identically at every level; only the dispatch is licensed.