Designing the Command Chain That Turns Agents Into Accountable Work
Designing the Command Chain That Turns Agents Into Accountable Work
Two of your agents pick up the same task. Both edit auth/session.ts. The second one’s write lands on top of the first, silently erasing it. A third agent reads the merged mess, can’t tell the change is incoherent, and stamps it “approved.” The run reports success. A day later it breaks in production — and when you open the logs to find out who decided to ship it, there is no one. There’s a swarm of green checkmarks and no author. You added agents to do more, and what you got was less work you can trust and zero accountability for the work you can’t.
That is the failure naive multi-agent setups produce, and adding headcount makes it worse, not better. The problem you actually have to solve is not “how many agents” — it’s the command chain: who proposes, who is allowed to apply, what each agent must hand the next one, and where an uncertain agent stops the line instead of guessing. This is a design document for that chain. If you architect agent systems or run an orchestration layer, you should walk away with a concrete spec — roles, handoff contracts, a propose-vs-apply boundary, and escalation paths — that converts a pile of capable agents into output you can sign your name to.
One agent can’t grade its own paper — and a swarm has no author
Hand one agent “implement the feature.” It writes the code, judges the code, and ships the code — using the same reasoning for all three. The model that misread the spec is the model deciding whether the spec was met; the blind spot that produced the bug is the blind spot evaluating it. Self-verification is the structural flaw, and no amount of “be more careful” prompting removes it.
The intuitive fix — spin up more agents — replaces one flaw with three. Without a chain, parallel agents collide on shared state, each confident it holds the latest version; “review” becomes one agent rubber-stamping another’s output because nobody told it to look for problems; and when something breaks, the run is a flat list of successes with no edges between them, so the postmortem dead-ends at “the agents did it.” More agents multiplied the throughput and the failure surface, and bought you no accountability.
The chain wins for one reason worth stating plainly: the agent that checks the work is never the agent that did it. Everything else in this document is machinery to make that separation hold under load.
Roles: one job each, and a structural split between proposing and applying
Give each agent a narrow charter. Narrow roles are easier to evaluate, cheaper to improve, and far easier to trust than one agent wearing every hat. The chain we run in practice is five roles deep before anything touches the tree:
- Roadmap ingests the open issues and failure counts and emits a prioritized, ordered backlog — what to build and why.
- Tech-lead turns each backlog item into an executable task: id, goal, files in scope, acceptance criteria, the assigned worker, the reviewers, dependencies — and, critically, the escalation policy for that task. It decides what runs now and who runs it; it does not write code.
- Implementer (the proposer) writes the diff for one task and nothing else.
- Reviewer (the critic) is prompted to find problems — scope creep, missing tests, incorrect logic. An agent told to find faults catches what an agent told to ship will rationalize away. For a harder change, an adversary runs alongside it, hunting the worst edge case rather than the average one.
- Tester (the verifier) writes a focused test for the behavior that actually changed, not a suite that re-asserts what already worked.
The load-bearing constraint isn’t the role count — it’s the split between the agents that propose and the authority that applies. The implementer, reviewer, and tester argue among themselves and converge on a candidate diff, but none of them can write it to the tree. Application is a distinct act reserved for a gate — today a human, later a policy check — which is what makes “approved” mean something: a recommendation from a role, not a deployment by whoever finished last.
Handoff contracts: specialization only pays off if the seam is real
Two agents that pass an unstructured blob between them are a monolith with extra latency and an extra failure point. The check only happens if the handoff names what the sender must provide and what the receiver is obligated to inspect — and refuses the handoff when a required field is missing.
{
"handoff": "implementer -> reviewer",
"taskId": "fleet-2026-00318",
"contract": {
"must_provide": ["diff", "files_touched", "test_plan", "assumptions"],
"reviewer_must_check": ["correctness", "scope_creep", "missing_tests"],
"verdict": ["approve", "revise", "escalate"],
"on_missing_field": "reject_handoff"
}
}
on_missing_field: reject_handoff is the entire mechanism. If the implementer hands off with no test_plan, the chain stops at the seam rather than letting an unverified change slide one role downstream where it’s harder to catch. A contract that rejects an incomplete handoff is the line between a chain and a swarm: the swarm passes anything; the chain passes only what the next role can actually evaluate. And because each handoff serializes through a contract, two agents can’t both be mutating the same file at the same instant — the collision that started this paper is closed off by the same discipline that makes review meaningful.
The handoff also carries the shape of the work, which is why the layered flow matters: each stage receives a known artifact and guarantees a known artifact to the next, so a receiving agent never has to reverse-engineer what it was handed.
Propose-then-verify: nothing reaches the tree without a check it didn’t author
The default posture of the whole chain is propose-only. Run the tech-lead’s /run without a dispatch flag and it returns the plan, the ready and blocked tasks, and the escalation policy — and dispatches nothing. The agents produce diffs and recommendations; the working tree is untouched until a separate, deliberate act applies them.
# propose-only — returns the task plan + escalation policy, dispatches nothing
curl -sS -X POST http://fleet.local/run \
-H 'content-type: application/json' \
-d '{"openIssues": "<issues>", "failureCounts": {"compile_type_error": 2}, "width": 6}'
# LIVE — fan ready tasks out to their assigned workers (deliberate, not the default)
curl -sS -X POST http://fleet.local/run \
-H 'content-type: application/json' \
-d '{"openIssues": "<issues>", "failureCounts": {"compile_type_error": 2}, "width": 6, "dispatch": true}'
dispatch:true is the toggle that lets the chain act, and keeping it opt-in is the propose-vs-apply boundary expressed as one parameter — converting an approval into a write is the gate’s job and the gate’s job alone. It’s also where you catch a worker handed work it can’t do: a task owned by an agent with no live worker comes back marked needs_operator, surfaced rather than silently dropped. Apply nothing the chain can’t account for, and account for everything before you apply it.
Escalation: the contract that lets an agent stop the line
An agent with no way to say I don’t know doesn’t pause when it’s uncertain — it guesses, and reports the guess as a result. Confident failure is the default behavior of a model with no exit. So every task carries an escalation policy authored up front by the tech-lead, not improvised mid-run. It names the triggers — an ambiguous spec, conflicting requirements, a check the agent can’t satisfy, low confidence on a costly action — and the destination, which is the next role up or straight to the human gate.
Escalation has its own quality bar: escalation precision, the share of escalations that were actually warranted. Too low and the chain cries wolf until its humans rubber-stamp every alert; too high and you’ve quietly rebuilt the monolith that never asks for help. You tune toward warranted-only. And the policy degrades safely under failure: when a reviewer or adversary is down or times out, that role becomes a skipped turn the run records explicitly — the chain completes with a noted gap instead of hanging or pretending the check ran.
Attribution: every decision traceable to the agent that made it
The swarm’s unanswerable question — “which one did it?” — has a one-line answer in a chain: every step emits a record of its input, its output, and its decision, stitched by a correlation id so the whole run reconstructs end to end.
{
"eventType": "ChainStepCompleted",
"taskId": "fleet-2026-00318",
"step": "reviewer",
"input": { "diff_sha": "a1c9f2", "from": "implementer" },
"decision": "revise",
"reason": "no test covers the empty-input path",
"confidence": 0.71,
"escalated": false,
"correlationId": "2f17f6c2-1a3c-4d9f-a7b1-1142f81c4d01",
"completedAt": "2026-06-22T15:20:12Z"
}
With this in place, decision-traceability coverage becomes a number you hold to — the share of steps whose input, output, and decision are reconstructable. A bad change is then attributable to the reviewer that approved without a test covering the empty-input path, with the diff sha it saw and the confidence it acted on — not lost in a flat wall of green. The same correlation id carried across roles is both the audit trail and the proof that two agents weren’t authoring the same change at once.
These metrics move together, and they trade off, which is the real reason to keep the chain minimal:
- Errors caught before apply~30%70–85%Quality / critic + verifier
- Escalation precision40–55%80–90%Risk / tuned triggers
- Self-approved applies100%0%Accountability / role split
- Decision-traceability coverage<50%100%Attribution / step logging
- End-to-end chain latencyunboundedbudgetedCost / minimum chain
A reference command chain you can build
Here is the chain end to end. Each rung is a role; the dashed rung is the gate where authority stops being the fleet’s and becomes the applier’s.
- 01Dispatchroadmap orders the backlog
- 02Plantech-lead scopes the task + escalation policy
- 03Proposeimplementer writes the diff — applies nothing
- 04Reviewreviewer finds problems · contract-checked
- 05Verifytester covers the changed behavior
- 06Applygate checks the trace & writes the tree
A failure makes the design clearer than any success. A small task — a CSS-and-markup tweak to one component — went into the chain. The router saw “UI” and assigned it to visual-design agents that render screenshots to do their job; those agents needed a browser-capture service they weren’t wired to, so they failed, the review step’s model backend timed out behind them, and the run came back having produced nothing usable. A pure text diff had been routed to a team that needed a camera. The lesson is not “agents are fragile.” It’s that the failure was attributable — the step log named the routing decision as the bug, not the agents — and that two of this paper’s contracts would have caught it: a handoff never checked against the agents’ real capabilities, and a step that should have escalated “I’m not wired for this” instead of failing into a timeout. The agents were fine; the chain design was the bug, which is exactly the work this document is about.
What we covered
A swarm of agents will happily produce more work than you can verify and leave no one to answer for it. The command chain is how you get the throughput of many agents and keep a single, recoverable answer to “who decided this” — narrow roles that check each other through contracts, an escalation path so uncertainty stops the line, a step log so every decision has an author, and a gate so nothing reaches the tree that the chain can’t account for. Build that, and your agents stop being a swarm you hope works and become a team whose work you can apply on purpose.
References: roadmap → tech-lead → worker fleet command chain · implementer/reviewer/tester propose-only model · escalation-policy design · correlation-id step tracing · NIST AI RMF (govern / map / measure / manage) · human-in-the-loop control patterns.