03.14Practice
Harness engineering for AI coding agents
Harness engineering at AR Labs: each recurring AI coding agent mistake becomes a hook or check, so rules that matter are enforced, not remembered.
On this page
Harness engineering is how AR Labs keeps AI coding agents (AI agents that write code, such as Claude Code or Codex) from repeating their mistakes. An agent's harness is everything around the model that shapes what an agent does: the agent program, its instructions, skills, hooks, tools and checks. Harness engineering is the practice of changing that environment whenever an agent makes a mistake, so the mistake cannot recur. At AR Labs a rule that matters starts as written guidance and, once it has been broken, moves into a script that enforces it. The anatomy of a coding agent harness takes the harness apart piece by piece; this page is about changing it.
The problem it addresses
An instruction in an agent's context is not the same as an instruction the agent follows. Under pressure to finish, a trained habit can beat a written rule, and in unattended runs nobody is watching to notice. We found this directly: the coding pipeline's stage gates (spec before implementation, cross-model review before close) once lived only in prose, and unattended runs skipped them without any error.
Where the term comes from
Mitchell Hashimoto named the practice in his February 2026 post "My AI Adoption Journey", describing it as the idea that "anytime you find an agent makes a mistake, you take the time to engineer a solution such that the agent never makes that mistake again", through better standing instructions and through tools that make the wrong path unavailable. Vivek Trivedy of LangChain gave it a formula in "The Anatomy of an Agent Harness": "Agent = Model + Harness." Simon Willison, Anthropic's engineering blog and Birgitta Böckeler on Martin Fowler's site have written about the same discipline.
The layers
flowchart TD I["Rules loaded by file type"] --> C["Command files, run by reference"] C --> H["Pre-action hooks"] H --> F["Floors on every step"] F --> R["Cross-model review"] R --> P["A person merges"]
- Instructions. Short rule files that load when an agent touches matching files, so a coding rule loads for source files and not for prose. They explain why a rule exists.
- Command files, executed by reference. Each pipeline step has a written procedure, and agents are required to open and follow it, never to work from a remembered version. When agents reconstructed a procedure from memory, steps fell out silently; in recorded cases the walkthrough, the proof manifest and a status transition went missing.
- Hooks. Scripts run automatically around an agent's action. The ones here run before a tool does, and can block the action and say why.
- Floors. Scripted proofs that a step's work exists before the step may close, for example that a reviewed commit has really landed on its target branch (see the pipeline).
- Independent review by a different model in a fresh context.
- A person, at the plan and at the merge.
The diagram above orders the layers as a change meets them, from guidance an agent can skip to a person's merge. The figure, shared with the anatomy page, shows the parts of the harness those layers are built from: rules and commands entering the context window, hooks around every tool call, and floor scripts that check the world without a model.
Three guards, each from a recorded problem
The pipeline guard. Because prose gates were skipped, a hook now watches every command that changes a bead (one tracked task in the Beads issue tracker). It refuses force-closing a parent with open children, cascading deletes, the retired custom status names, creating children outside the fan-out step, and moving a task into implementation while a task that blocks it is unmerged or while files in its spec's declared scope have changed since the spec was written. Humans have an override for repairing state; agents meeting a gate do not use it.
The enforcement-surface guard. An unattended session once met a bug in a gate script and fixed it in place. The fix was correct, but nothing recorded it, and a process whose checks can be edited by the process being checked cannot rely on those checks. We now treat the gate scripts, the pipeline manifest, the step procedures, the hooks themselves and their registration as an enforcement surface. What happens on an edit depends on who is watching. In an unattended session, an edit there is denied. In an attended session it is allowed but loudly audited, with a log line and a warning in the transcript the person is reading, because a blanket denial started blocking work a person had asked for. The executor also fingerprints the surface before and after each unattended session, so tampering shows up even if a hook is bypassed.
The worktree guard. Edits to a project's primary checkout are denied, with the correct worktree path in the denial. See worktree isolation.
How we write a guard
{
"hooks": {
"PreToolUse": [
{ "matcher": "Edit|Write|MultiEdit",
"hooks": [{ "type": "command", "command": "bun .claude/hooks/guard-edits.ts" }] }
]
}
}A few design rules recur across our hooks:
- State the problem at the top of the file. Each hook opens with the incident that produced it, what it blocks and what it deliberately does not catch.
- Choose failure behaviour on purpose. The pipeline guard fails open: a parse error allows the command, because a guard must never break normal work, and only a confirmed missing artefact denies. The worktree guard fails closed once it has identified a protected checkout, because an edit there is the exact harm it exists to stop.
- Match invocations, not mentions. A command is inspected only when the program it runs is the one being guarded. A commit message or a note that merely names a command is never matched.
- Say what a heuristic misses. Screening shell commands for writes is a heuristic, and the hook's own header says what it cannot catch and which other layer covers that gap.
- Keep one copy of the truth. The list of guarded paths lives in one place that the hook, the driver and the executor all read, so they cannot disagree.
Proportional checks
A harness can make verification so heavy that it stalls the work it protects. Our research found that large engineering organisations, including Google, Meta and Anthropic, split verification into a fast gate that runs only the tests a change can affect and a slower full run afterwards, and that the only well-sourced budget for the gate is about ten minutes. Our regression gate applies that ceiling (see test-driven development).
Adopting it
Keep a log of every agent mistake you correct by hand. When a correction recurs, ask whether a script could have refused the action. If it could, write the hook, put the incident in its header, and leave the written rule in place to explain why the hook exists. The prose explains; the hook guarantees.
Referenced by 10
- ConceptsWhat we believe about AIlinks here in its text
- ConceptsThe Loop: how AR Labs workslinks here in its text
- ConceptsThe harness paradoxlinks here in its text
- EngineeringHow AR Labs engineers software with AI coding agentslinks here in its text
- EngineeringAgentic engineeringlinks here in its text
- EngineeringGit worktree isolation for parallel AI coding agentslists this as related
- EngineeringAct or ask: when an AI agent should ask permissionlists this as related
- EngineeringUnattended AI coding agent runslinks here in its text
- EngineeringAnatomy of a coding agent harnesslinks here in its text
- ResearchHarness engineering for AI agents: origins and sourceslinks here in its text