03.22Practice
Unattended AI coding agent runs
How AR Labs runs AI coding agents unattended: one execution contract, facts passed in, typed stops, scripted checks and every deviation logged.
On this page
AR Labs runs parts of its coding pipeline, the route every code change takes from spec to a person's merge, unattended: a script dispatches one headless agent session per step, and nobody watches. Every such run works under one written execution contract, receives facts rather than a restatement of the method, stops in one of a fixed set of recorded states, and is checked by scripts that do not care what any prompt said. We call these AFK runs, for "away from keyboard", a term taken from Matt Pocock's split between human-in-the-loop and AFK work.
The problem it prevents
Early unattended runs failed in a way that looked like success. An orchestrating agent told to run the pipeline end to end did not execute the pipeline's step procedures. It wrote its own lookalike from memory: a spec agent approximating the spec procedure, an implementer approximating the build procedure, a reviewer approximating the review procedure. The output read well. Underneath, the cross-model review had become same-model self-review, a step had advanced without the artefact that should license it, the proof manifest was missing, and the run ended because the agent wrote a paragraph saying the remaining work was noted, not because the work was done.
The cause was structural. When an agent summarises a method into a prompt for another agent, the summary comes from its own picture of the method, and that picture cannot include what it is missing. The loss is invisible at the moment of writing, because a paraphrase feels faithful while it drops the properties that matter.
How it works
flowchart TD K["A person starts the run"] --> D["Driver reads the task tree"] D --> X["Executor: one session per task and step"] X --> C["Session reads the contract and step procedure"] C --> W["Does the work, records a proposal"] W --> F["Floor checks the proposal"] F -->|"passes"| D F -->|"refuses"| B["Blocked: note, prune, continue"] B --> D D --> E["Typed exit and a report from the record"]
Method travels by reading, never by restatement. A dispatched session's prompt opens with an instruction to read the execution contract, then gives it a block of run facts, then tells it to read the step's procedure file and execute it. No dispatcher, workflow or recovery session may restate a procedure in its own words. The contract confines unattended adaptation to gate mechanics: which approvals are pre-answered, and how. Everything else the agent learns from the same files an attended session reads.
Facts, not instructions. The run facts block carries resolved values only: the task and its title, the working folder, the authority document, the branch to land on, the delivery mode, the autonomy level, any standing rules that bind the project, and the branch name. Each value is looked up by a script at dispatch, never guessed. A fact that says "see section 4" is a pointer, not a fact, and the contract treats emitting one as a defect in the dispatcher.
An authority document stands in for the person. Every run names the approved campaign plan it works under. Where the autonomy level lets the run approve its own spec, the rule is mechanical: the spec is approved if and only if it stays inside the plan's constraints. A new dependency, a schema change or wider scope is a block with a note, never a judgement call.
Blocking is a state, not a stop. When a step cannot proceed, the agent appends a structured note (BLOCKED: <gate> — <cause> — <what unblocks it>), the driver prunes that branch of the task tree, and the run carries on with independent work. Nothing waits idle for a person who is not there.
Typed exits. Each pass of the driver ends in one of a fixed set of states: done, waiting on a person, waiting on another running holder, ready for more work, out of action budget, escalated, or idle. Each attempt at a step records success, refused, failed, escalated or dispatched. Three failed attempts at one step park that task in a dead-letter state until a person clears it. The run ends when no work is ready; the final report is a by-product of that, never a reason to stop.
Exit status is not evidence. A headless agent session exits with status 0 whatever its last command returned. So a blocked attempt writes its failure to a result file beside the session, and the driver reads that file. Without it, a session that summarised a failure and exited cleanly would be recorded as a success.
Declared resume behaviour. Each step declares whether a killed attempt's partial output may be inspected and continued, or must be discarded and redone. The executor refuses to dispatch a step without a declaration rather than let the agent guess. Delivery checks first whether it has already happened, because merging twice or opening a second pull request is real damage.
Bounded effort in both directions. The regression run before review has a ten-minute ceiling; an unattended agent stops it there itself and records which suites passed, failed or did not finish, instead of rerunning into the same ceiling. A failing review licenses at most one dispatched fix round, which may address critical findings only; a second failure rests the task for a person with the failing axes named.
Deferred, never dropped. Checks that need a human sense, such as how a voice sounds, go on a deferred-verification list on the task and in the report. Every pre-answered gate and every other adaptation the run actually exercised is recorded too. An unrecorded deviation breaks the contract even when the adaptation was allowed.
The machinery is out of reach. A guard hook denies an unattended session any edit to the pipeline's own scripts, procedures, hooks and settings, and the executor fingerprints those files before and after each session, so a change is recorded whether or not the agent mentions it. A task whose spec touches that machinery rests until an attended session takes it up. See harness engineering.
What a run never does
An unattended agent never closes a task, never merges to main, never forces a close and never writes the pipeline's state fields directly. Tasks close when a scripted check proves the reviewed commit landed on its target branch. In the default mode that happens only after a person merges the pull request, so the person's merge is the boundary, expressed as evidence rather than as an instruction.
A worked example
Illustrative example, with generic task names. A campaign to add notifications to an app has three ready leaf tasks and runs overnight at the wave autonomy level, which lets agents approve their own specs within the plan and dispatch one review fix.
notif-1.1, the tracer bullet, runs spec, build and review cleanly, opens a pull request and rests at delivery, waiting for a person to merge.notif-1.2's spec needs a new message-queue library the plan never mentioned. That is a variance from the authority document, so the agent recordsBLOCKED: spec approval — new dependency not in the plan — a person approves the dependency or revises the plan, and the driver moves on.notif-1.3's review returns a critical finding on the Spec axis. The driver records the fix round, dispatches a fix agent that corrects only that finding on the existing branch, and a second review passes.
In the morning the report, generated from the task records rather than any session's memory, lists two pull requests to merge, one question about a dependency with the agent's recommended answer, and one deferred check: whether the notification sound is too loud.
Where it came from
The split between human-in-the-loop planning and unattended implementation follows Matt Pocock's workflow. The by-reference rule, the typed exits, the authority document and the enforcement of the machinery are our own, each added after a recorded failure. Our research on driver execution models shaped the driver as a reconciler that re-reads durable state on every pass.
Referenced by 06
- ProjectsAI agents at AR Labs: the agents we run and what each doeslinks here in its text
- EngineeringHow AR Labs engineers software with AI coding agentslinks here in its text
- EngineeringAct or ask: when an AI agent should ask permissionlists this as related
- EngineeringHuman-in-the-loop gates for AI coding agentslists this as related
- EngineeringMulti-agent orchestration for AI coding agentslinks here in its text
- ResearchAI agent orchestration driver: reconciliation loops versus eventslinks here in its text