
What a harness is
The article opens with a rule: any time you find the agent making a mistake, you take the time to engineer a solution so that it never makes that mistake again. And with a diagnosis: we have spent two years arguing about which model is smartest, when the model is only one input into a running agent. The rest is the harness: the prompts, tools, context policies, hooks, sandboxes, subagents, feedback loops and recovery paths.
Osmani's thesis is that a decent model with a great harness beats a great model with a bad harness. He says he has watched it play out in his own work over and over. He takes the definition from Viv Trivedy, whom he credits with coining the term harness engineering:
Agent = Model + Harness. If you’re not the model, you’re the harness.
A harness is every piece of code, configuration and execution logic that isn't the model. A raw model is not an agent; it becomes one when the harness gives it state, tool execution, feedback loops and enforceable constraints. Concretely, it includes:
- Prompts: the system prompt,
CLAUDE.md,AGENTS.md, skill files and subagent prompts. - Tools: tools, skills and MCP servers, with their descriptions.
- Bundled infrastructure: filesystem, sandbox and browser.
- Orchestration: subagent spawning, handoffs and model routing.
- Hooks and middleware for the deterministic parts: compaction, continuation and lint checks.
- Observability: logs, traces, and cost and latency metering.
Simon Willison reduces the loop part to its essence: an agent is a system that "runs tools in a loop to achieve a goal". The skill is in designing both things, the tools and the loop.
That is a lot of surface area, and it is yours, not the model provider's. Claude Code, Cursor, Codex, Aider and Cline are all harnesses. The model underneath is sometimes the same, but what you experience is dominated by what the harness does. The loud debate is on the model side; most of the leverage, Osmani says, sits on the other.
If you want Trivedy's full derivation, I covered it in The anatomy of an AI agent.
It's not the model, it's the configuration
There is a pattern many engineers fall into: the agent does something dumb, the model gets the blame, and the problem is filed under "wait for the next version". The harness mindset rejects that default, because the failure is usually legible:
| What went wrong | What you change in the harness |
|---|---|
| The agent didn't know about a convention | You add it to AGENTS.md |
| It ran a destructive command | You add a hook that blocks it |
| It got lost in a 40-step task | You split it into a planner and an executor |
| It kept "finishing" broken code | You wire the typecheck into the loop as back-pressure |
HumanLayer puts it this way: "it's not a model problem. It's a configuration problem." They call it a skill issue.
Osmani also picks up a data point that shows up in both Trivedy's write-up and HumanLayer's: on Terminal Bench 2.0, Claude Opus 4.6 running inside Claude Code scores far lower than the same model in a custom harness, and Trivedy's team moved an agent from Top 30 to Top 5 by changing only the harness. The article gives no scores.
The explanation he offers is that models are post-trained coupled to the harness they were trained against. Moving them into a different one, with better tools for your codebase, a tighter prompt and sharper back-pressure, can unlock capability the original harness was leaving unused. It is the opposite of "just wait for GPT-6": the gap between what today's models can do and what you see them doing is largely a harness gap.
The ratchet: every mistake becomes a rule
The most important habit, according to Osmani, is treating agent mistakes as permanent signals. Not as anecdotes, and not as "bad runs" to retry. He calls it the ratchet, the toothed wheel that only turns one way.
His example: the agent ships a PR with a commented-out test and he merges it by accident. That is an input, and it produces three changes:
- In
AGENTS.md: "never comment out tests; delete them or fix them". - In the pre-commit hook: it greps the diff for
.skip(andxit(. - In the reviewer subagent: a commented-out test is a blocker.
The discipline works in both directions. You only add a constraint when you have seen a real failure, and you only remove it when a more capable model has made it redundant. Every line in a good AGENTS.md should be traceable back to a specific thing that went wrong.
That is why Osmani calls this a discipline rather than a framework: the right harness for your codebase is shaped by your failure history. You can't download it.
From behaviour to piece
To design a harness, the framing from Trivedy that Osmani finds most useful is to work backwards: start from the behaviour you want (or want to fix) and derive the piece that delivers it. If you can't name the behaviour a component exists to deliver, it probably shouldn't be there.
| Behaviour you want | Harness piece |
|---|---|
| Working with real data durably | Filesystem and Git |
| Writing and executing code | Bash and code execution |
| Executing without breaking anything | Sandboxes with good default tooling |
| Remembering and learning new things | Memory files, web search and MCP |
| Performing over long contexts | Compaction, tool-output offloading and skills |
| Long-horizon work | Ralph loops, planning and verification |
The most foundational primitive, and an underrated one because it is boring. A model can only operate on what fits in its context. With files, the agent gets a workspace to read data, code and docs, a place to offload intermediate work, and a surface to coordinate with other agents and with people. Git adds versioning: tracking progress, rolling back errors and branching experiments.
The main loop is a ReAct loop: the model reasons, acts through a tool call, observes and repeats. But the harness can only execute the tools it has logic for. Either you pre-build one for every possible action, or you give the agent bash and let it build what it needs. Osmani compares it to teaching someone a single kitchen gadget versus handing them the kitchen.
Bash is only useful if it runs somewhere safe. Running agent-generated code on your laptop is risky, and a single local environment doesn't scale to many parallel agents. A sandbox allows command allow-lists, network isolation and environments created and torn down per task. A good one ships with language runtimes and packages, Git, test CLIs and a headless browser: that is what lets the agent observe its own work and verify it.
A model knows nothing beyond its weights and its context, so the only way to add knowledge is to inject it. The harness loads AGENTS.md on every start; when the agent edits it, what it learned carries into the next session. It is a crude but effective form of continual learning. For what didn't exist at training time, web search and MCP tools like Context7 bridge the cutoff.
Osmani stresses that the model doesn't configure its execution environment: deciding where the agent runs, what is available and how it verifies its output are all harness-level calls.
Context rot
Context rot is the observation that models get worse at reasoning and completing tasks as the context window fills up. Context is scarce, and a harness is largely a mechanism for spending it well. The article lists three techniques that show up repeatedly, plus a fourth that Anthropic adds:
- Compaction. When the window is close to full, the harness summarizes and offloads older context so the agent can keep working. Letting the API error is not an option in production.
- Tool-output offloading. From a 2,000-line log, the harness keeps the head and the tail in context and stores the rest in a file the agent can read on demand.
- Skills with progressive disclosure. Loading every tool and MCP at startup degrades performance before the first action. Skills reveal instructions and tools only when the task calls for them.
- Full context reset. For really long jobs, the harness tears the session down and rebuilds it from a compact hand-off file. Anthropic is explicit that compaction alone wasn't enough. Osmani compares it to onboarding a new engineer.
Long-horizon work
This is the hardest thing to get right. Today's models stop early, decompose complex problems poorly and lose coherence when the work stretches across several context windows. The harness has to be designed around all three.
A hook intercepts the model when it tries to exit and re-injects the original prompt into a fresh context window. Each iteration starts clean but reads the state the previous one left on the filesystem. It turns a single-session agent into a multi-session one.
The model decomposes the goal into steps, usually in a plan file on disk, and the harness reminds it how to use that file. After each step it verifies: hooks run the test suite and loop failures back to the model with the error text, or the model reviews its output against explicit criteria.
Anthropic reports that splitting generation and evaluation into separate agents works better than self-evaluation, because agents tend to grade their own work too kindly. Osmani compares it to GANs, but for prose.
Related to the last one is the sprint contract: generator and evaluator agree on what "done" means before any code is written. Osmani says that, in his own workflows, writing down the done-condition before starting has caught more scope drift than any prompt change. That is his experience, not a measurement.
Hooks: the enforcement layer
Hooks separate "I told the agent to do X" from "the system enforces X". A hook is a script that runs at a specific point in the lifecycle: before a tool call, after a file edit, before a commit or on session start. They are for the things the agent should never forget but often does:
- Check types, lint and tests after every edit, and surface the failures.
- Block destructive commands:
rm -rf,git push --force,DROP TABLE. - Require approval before opening a PR or pushing to
main. - Format on write, so the agent doesn't spend tokens on whitespace.
The principle Osmani takes from HumanLayer is that success is silent and failures are verbose. If the typecheck passes, the agent hears nothing. If it fails, the error text is injected into the loop and the agent corrects itself. That makes feedback almost free in the common case and directly actionable when something goes wrong.
AGENTS.md and tools
For Osmani, the rulebook at the root of the repo is still the highest-leverage configuration point, because it lands in the system prompt on every turn. Conventions go there: package manager, test framework, formatting, "never touch /legacy", "always use our logger". He gives two lessons:
- Keep it short. HumanLayer keeps theirs under 60 lines. Every line competes for attention, and the more rules there are, the less each one matters. A pilot's checklist, not a style guide.
- Earn each line. A rule should trace back to a specific past failure or a hard external constraint. Otherwise it is noise. Ratchet; don't brainstorm.
The same discipline applies to tools. Each tool's name, description and schema are stamped into the prompt on every request. Osmani holds that ten focused tools outperform fifty overlapping ones, because the model can keep the whole menu in its head.
HumanLayer also flags a security concern: since tool descriptions populate the prompt, any MCP server you install is trusted text the model will read. A sloppy or malicious MCP can prompt-inject your agent before you have typed anything.
What it looks like in production
The clearest public picture of a mature harness, for Osmani, is Fareed Khan's breakdown of Claude Code's architecture. It is an estimate, not an official blueprint. The master agent loop sits at the centre, with seven layers around it:
| Layer | What it contains |
|---|---|
| Input | User interface, session manager and permission gate |
| Knowledge | Skill registry, context compressor, task graph and memory store |
| Integration | MCP runtime and external servers |
| Execution | Tool dispatch, streaming runtime and prompt cache |
| Output | Verified task results |
| Observability | Event bus and background executor |
| Multi-agent | Subagent spawning, teammate mailboxes, FSM protocol, autonomous board and worktree isolator |
Almost every concept above shows up there as a named component. Context injection is the knowledge layer. Loop state lives in the memory store and the worktree isolator. Destructive-action hooks sit behind the permission gate. Subagent context firewalls are the entire multi-agent layer. And the tool dispatch registry is where both MCP servers and bash plug in.
Harnesses don't shrink, they move
The naive story is that a better model makes the harness obsolete: if the model can plan, no planner; if it stays coherent over long tasks, no context resets. There is some truth in it. According to Osmani, Opus 4.6 largely killed "context anxiety" (Sonnet 4.5 used to wrap up work early as it approached what it thought was its limit), and all the scaffolding he was writing against that failure six months ago is now dead code.
But the ceiling moved with the model. Tasks that were out of reach are now in play, and they bring their own failure modes: now you need a multi-day memory policy, a harness that coordinates three specialized agents, or evaluators for design quality in generated UIs. Anthropic puts it like this:
Every component in a harness encodes an assumption about what the model can’t do on its own.
When the model learns to do something, that piece is no longer holding anything up and should come out. When it unlocks something new, new scaffolding is needed to reach the new ceiling.
There is also a loop between harness design and training, which Trivedy names explicitly: a useful primitive is discovered in the harness, standardized into the product, used when training the next generation, and the new model gets better at exactly that primitive.
Today's agent products are post-trained with the harness in the loop. That is why Opus 4.6 feels different inside Claude Code than inside another harness, and why changing a tool's logic sometimes causes strange regressions. A truly general model wouldn't care whether it edits with apply_patch or str_replace, but co-training creates overfitting.
Two practical consequences follow: a harness is a living system, not a config file you write once; and the "best" harness isn't necessarily the one the model was trained inside, but the one designed for your task.
Harness as a service
Another idea from Trivedy is Harness-as-a-Service: we are moving from building on a model API, which gives you a completion, to building on a harness API, which gives you a runtime. The Claude Agent SDK, the Codex SDK and the OpenAI Agents SDK all point that way: they ship the loop, the tools, context management, hooks and sandbox primitives, and you customize them.
The default path used to be building everything: your own loop, your own tool calling, conversation state and approval flow. Now it is picking a harness framework, configuring it along its four pillars (system prompt, tools, context and subagents) and putting your effort into the prompts and tools of your domain. That is what makes the skill issue tractable: you don't rebuild the agent every time something fails, you tune a configuration surface that is already well factored.
And it is the best argument for starting messy. The line is Trivedy's:
Good agent building is an exercise in iteration. You can’t do iterations if you don’t have a v0.1.
Where this is going
Put the top coding agents side by side (Claude Code, Cursor, Codex, Aider, Cline) and they look more like each other than their models do. The models are different; the harness patterns are converging. Osmani doesn't think that is an accident: the industry is finding the pieces of scaffolding that actually bear the load.
Trivedy frames three open problems:
- Orchestrating many agents working in parallel on a shared codebase.
- Agents that analyze their own traces to find and fix harness-level failures.
- Harnesses that assemble the right tools and context just in time for each task, instead of being pre-configured at startup.
With that last one, Osmani says, the harness stops being static config and starts looking more like a compiler.
What is data and what is opinion
The article is an opinionated synthesis, and it is worth keeping things apart:
- Terminal Bench comes without numbers. Opus 4.6 scoring "far lower" inside Claude Code and the Top 30 to Top 5 jump are third-party results (Trivedy and HumanLayer) that Osmani cites without scores.
- "A decent model with a great harness wins" is the author's thesis, backed by his experience. It is not a measurement.
- Ten tools versus fifty is also an opinion, not an experiment.
- The 60 lines are HumanLayer's practice, not a general rule.
- The Claude Code diagram is Fareed Khan's estimate.
- The rule that opens the article is shown as a quote, but with no attribution on the page.
There is also a detail that doesn't match in the article's last figure. Its alt text describes the loop between harness and training, but the image shows something else: "The harness doesn’t shrink. It moves.", across three model generations. The loop is only in the text.
In short
The agent is the model plus the harness, and the harness is yours. When the agent fails, the useful question isn't which model comes next, but which harness piece would have prevented the failure: a line in AGENTS.md, a hook, a sandbox, a separate evaluator. And when the model improves, the harness doesn't go away: you take out the pieces that no longer hold anything up and add the ones the new ceiling needs.
Every agent mistake is a signal to tighten the ratchet: add a rule when something fails, and remove it when the model no longer needs it.
Which specific failure does each line of your AGENTS.md come from?
Sources
- "Agent Harness Engineering", by Addy Osmani, April 19, 2026.
- On harnesses in this blog: The anatomy of an AI agent, the Viv Trivedy article Osmani builds on, and The harness is the product.
- The video, on my channels: English and Spanish.