What Is a Harness?
A raw language model takes text and returns text. It cannot read a file, run a test, remember yesterday, or know when to stop. A harness is the software that gives it those abilities — and the boundaries that make them safe.
The model is one component
It is tempting to talk about “the agent” as if it were a model checkpoint. It is not. An agent is a system:
Six systems appear in almost every harness:
- Loop — the repeated cycle of observing state, choosing an action, executing it, and deciding whether to continue.
- Tools — typed functions the model can call: read a file, search a repository, run a command, query an API.
- Context — what the model sees on this turn: system instructions, tool schemas, conversation history, retrieved files, tool results.
- Policy — what the model may do, where, and under whose authority. Approvals, sandboxes, allowlists, budgets.
- State — durable facts, checkpoints and an event log that survive a crash or a context compaction.
- Observability — traces, costs, evals and replay, so you can understand what happened.
A chatbot is a harness with a loop of one turn and no tools. A coding agent is a harness with a loop, file and shell tools, a workspace, permissions and a test runner. The model may be the same. The behavior is not.
Why harness engineering exists
Frontier models are increasingly good at reasoning within a single response. But real work is not a single response. It is:
- reading a repository,
- forming a hypothesis,
- making a small change,
- running the tests,
- reading the failure,
- revising the change,
- checking the diff,
- and stopping when the work is actually done.
That is a loop over an environment. The model supplies judgment. The harness supplies the environment, the memory and the guardrails.
Harness engineering is the discipline of designing that environment. It includes prompt and context design, but it is not only prompting. It is also software architecture, security, observability and evaluation.
The harness in the wild
The same pattern appears in every coding agent:
| Harness | Loop | Tools | Policy | Distinctive idea |
|---|---|---|---|---|
| Claude Code | plan/act/verify | file, shell, search, MCP | permission modes, sandbox | skills, hooks, subagents |
| OpenAI Codex | plan/act/verify | shell, file, web | approval modes, sandbox | cloud tasks, code review |
| OpenCode | plan/build agents | file, shell, search, MCP | per-agent permissions | open-source, provider-agnostic |
| Aider | edit/verify | file edit, git, tests | mostly local | repository map, edit formats |
| Cline | plan/act | file, terminal, browser, MCP | per-action approval | IDE-native UX |
| OpenHands | event loop | shell, browser, file | sandboxed runtime | open platform for agents |
The details differ, but the questions are identical: What can the model see? What can it do? What happens when it is wrong? How do you know it finished?
The harness is a contract
A useful way to think about a harness is as a contract with four clauses:
- Capability: here are the tools you can use, with typed schemas and clear errors.
- Context: here is the information relevant to the task, and here is how it will be maintained.
- Authority: here is what you may do without asking, what requires approval, and what is forbidden.
- Completion: here is what “done” means, and here is how we will verify it.
Most agent failures are a violation of one of these clauses:
- A tool is missing or badly described (capability).
- The relevant file was compacted away (context).
- The agent had write access it should not have had (authority).
- The agent stopped when the model said “done,” not when the tests passed (completion).
When an agent behaves badly, ask which clause failed. The answer is usually more specific than “the model is bad.”
What a harness is not
- It is not a prompt. A system prompt can describe a workflow, but it cannot enforce a sandbox, persist state, or run a test.
- It is not a model. A better model may reduce errors, but it will not fix a missing verification step or an over-broad credential.
- It is not a framework. Frameworks provide building blocks. A harness is the specific runtime you build for a specific kind of work.
- It is not autonomy for its own sake. The goal is reliable work, not the appearance of independence.
A minimal example
Imagine a harness for fixing a failing test. In pseudocode:
state = { repo, task, tests: "not run", files: [] }
context = system_prompt + tool_schemas + task + repo_map
loop up to max_steps:
action = model(context)
if action is a tool call:
result = policy_check(action) then execute(action)
state = update(state, action, result)
context = append(context, result)
if action is "finish":
if verify(state): return success
else: context = append(context, "verification failed")
That is the whole shape. The interesting parts are in the details:
- What is in
repo_map? - Which tools exist, and what do their errors look like?
- What does
policy_checkallow? - What does
verifyactually check? - What happens when the context fills up?
- How do you replay a failed run?
Every lesson in this track is an exploration of one of those questions.
The two failure directions
Harnesses fail in two opposite ways:
Too little structure. The agent has tools but no loop discipline, no verification, no state. It wanders, repeats itself and declares success. This is the “demo agent” failure.
Too much structure. The agent is wrapped in a rigid workflow that cannot handle variation. It follows a checklist into a wall. This is the “brittle automation” failure.
Good harness design finds the middle: enough structure to make progress and verify it, enough flexibility to handle the messy reality of real tasks.
Next: the agent loop — the smallest unit of agency, and the place where most failures actually happen.