Agent harnesses
“Harness” became standard vocabulary in agentic job descriptions around 2025, and it is worth being able to define precisely because it names the part of an agent that is not the model.
What a harness is
The harness is everything around the model call. The model does one thing - given a context, produce the next tokens. Everything that makes that useful is harness:
harness
+- loop call, run tools, call again
+- dispatch schema, routing, results back
+- context what stays in the window
+- state history, scratchpad, memory
+- controls stop conditions, budgets, retries
+- I/O streaming, approvals, loggingClaude Code is a harness. So is Cursor, the OpenAI Agents SDK, LangGraph’s
runtime, and the while stop_reason == "tool_use" loop you wrote yourself.
Swapping the model underneath a good harness usually still works; swapping the
harness changes the product entirely.
The insight behind the term: as models improve, the harness becomes the differentiator. Two teams calling the same model get very different results based on what their harness feeds it and how it recovers from mistakes.
The loop, concretely
Every harness has this at its centre:
async def run(task: str, tools: list[Tool]) -> str:
msgs = [{"role": "user", "content": task}]
for step in range(MAX_STEPS):
reply = await model(msgs, tools=tools)
if not reply.tool_calls:
return reply.text
msgs.append(reply)
for call in reply.tool_calls:
msgs.append(await dispatch(call))
raise StepBudgetExceeded(task)Ten lines, and the interesting engineering is in what surrounds them.
MAX_STEPS is not defensive decoration - without it a model that keeps calling
a failing tool loops until you notice the bill.
What separates a real harness from that sketch
- Context management. The message list grows every step and eventually exceeds the window. A harness compacts: summarise old turns, drop tool outputs that no longer matter, keep the task statement pinned. See Context engineering.
- Tool error handling. A tool that raises should return an error message to the model, not crash the loop. Models recover from “file not found” if you let them see it.
- Approvals. Consequential actions pause for a human. That gate lives in the harness, not the model.
- Observability. Every step traced, so a wrong answer can be replayed. Without this an agent failure is unfalsifiable.
- Budgets. Steps, tokens, wall-clock and money, each with a ceiling.
Harness versus framework versus platform
The distinction interviewers probe, because the words get used loosely:
| Term | Supplies |
|---|---|
| Harness | The loop and context management |
| Framework | A harness plus abstractions |
| Platform | A harness plus hosting |
LangGraph gives you a harness expressed as a state graph. The Anthropic SDK’s tool runner is a minimal harness over tools you define. Managed agent platforms supply the harness and run it, including the sandbox where tools execute.
The practical question is who owns the loop: you, a library in your process, or a vendor’s server.
Build or adopt
Write your own when the control flow is genuinely yours - a fixed pipeline with one model call per stage is not an agent and needs no framework. Reach for an existing harness when you need the parts that are tedious and easy to get subtly wrong: compaction, retries with tool-error feedback, streaming, and resumable state.
The honest position for an interview: most production “agents” are workflows with one or two model calls, and a harness is warranted when the number of steps genuinely cannot be known in advance. Saying that shows judgement rather than enthusiasm - see What is an agent.
Evaluating a harness
Harness changes are as consequential as prompt changes and are usually shipped with less testing. Compaction that drops the wrong turn, a retry policy that masks a real failure, or a step budget set too low all degrade quality without any prompt edit.
So the harness belongs in the eval suite: fix the model and the prompt, vary the harness, and measure task completion. Otherwise you are tuning it by anecdote - see The eval and observability tooling.
Related
Interview angle 6
- “What is a harness?” - everything around the model call: the loop, tool dispatch, context management, state, stop conditions and I/O. The model produces tokens; the harness makes that into a system that completes tasks.
- “Why does it matter?” - as models improve, the harness becomes the differentiator. Two teams on the same model get very different results depending on what their harness feeds it and how it recovers from tool errors.
- “What is in a harness beyond the loop?” - context compaction when history exceeds the window, tool errors returned to the model rather than crashing, human approval gates, per-step tracing so failures are replayable, and budgets on steps, tokens and money.
- “Harness, framework or platform?” - a harness is the loop and context management; a framework adds abstractions over it; a platform also hosts it and runs the tools. The real question is who owns the loop - you, a library in your process, or a vendor.
- “Would you write your own?” - for a fixed pipeline, yes, and it is not really an agent. Adopt one when you need compaction, tool-error retries, streaming and resumable state, which are tedious and easy to get subtly wrong.
- “How do you test a harness?” - put it in the eval suite. Hold the model and prompt fixed, vary the harness, measure task completion. Compaction dropping the wrong turn degrades quality with no prompt change and is otherwise invisible.