Skip to content
mnzes

What parts is an agent harness made of?

ByDiógenes MenezesLearning AI in public

12 min read

An agent harness is made of seven layers: context management, the tool catalogue, the permission system, an execution sandbox, session state, subagent orchestration and cost control. Each one settles a question the model never touches. Each one fails in a recognisable way, and the symptom is how you find out which one you’re missing.

The split is about responsibility, not files. In a small harness all seven fit in two hundred lines and none of them has a name. What the harness does is the same work whether it has seven modules or a single function; what changes is how quickly you can tell which part got it wrong.

Start with the two that carry the most weight. The context layer decides what the model sees, and the permission layer decides what it may do with that. The other five exist largely to hold those two up once the task gets long.

contexttoolspermissionsandboxsessionsubagentscostharnesswhat breaks without itwithout it: redoes finished workwithout it: the agent only talkswithout it: the incident is yourswithout it: the mistake escapeswithout it: it starts overwithout it: one window for everythingwithout it: the bill is the ceiling
Figure 1Each layer owns one decision and fails in its own way. The right column is the symptom that tells you the layer isn't there at all.

What each layer answers

Context decides what enters the window and what leaves it when space runs out. Without it the agent looks forgetful: it reruns a search it already ran, reopens a file it already read, contradicts a decision it made fifteen iterations ago. The layer never announces a discard, which is why its failures always arrive dressed up as the model being dim.

Tools decides what exists to be called, how each thing is described and what happens to an invalid argument. Without it the agent becomes a chat window: it describes, in prose, the command it would have run, then stops. A tool description is a prompt, and the format the action is requested in changes the outcome with the model held fixed. That was the central finding of the work that built an interface for the agent instead of reusing the human’s terminal1.

Permission decides what runs straight through, what stops and asks, and what is refused without asking. Without it every command is approved, which works until the first rm against a relative path that pointed somewhere else.

Sandbox decides reach: which directory, which network, how long, how much disk. Permission and sandbox are the same concern at two depths. The first is a policy you write; the second is a limit the system enforces when the policy is wrong.

Session decides what outlives the run. Without it, closing the terminal deletes the task. The model has no memory between calls: everything that looks like continuity is this layer rewriting state on every step. The cheap version dumps raw history to disk and reloads it, and it works right up until the history no longer fits in the window that reloaded it.

Subagents decides when a sub-task deserves a clean window. Without it the agent carries the noise of its own exploration to the end, and the important decision from iteration 3 shares space with the output of a grep from iteration 4. Open agent platforms already treat coordination between agents as part of the platform, at the same level as the sandbox and the interface2.

Cost decides when to stop. Step limit, token ceiling, wall-clock budget. Without it you learn the ceiling from the invoice, and the usual failure isn’t one expensive call. It’s two tools calling each other in alternation for forty iterations.

What crosses each boundary

The part nobody writes down is the shape of the data at each handoff. Layers don’t pass rich objects around: every boundary converts, and every conversion drops something.

assemblethe contextmodel picksone actionpolicyand executionoutput backto contextthe whole promptraw outputtool callonly what fits
Figure 2The model shows up once per turn. The other three steps are your code, and every arrow changes the shape of what passes — that's where information disappears.

From assembly to the model goes one string. System instructions, the tool catalogue, the history and any open files all arrive as a flat token sequence with no hierarchy. The model can’t tell a rule from a transcript; it infers that from position and from whatever formatting you picked.

From the model to policy goes a structured request: tool name plus arguments. It’s the narrowest point in the cycle and the only one where validation is cheap. An argument outside the schema can come back as an error for the model to fix, or it can kill the iteration, and those two choices produce different behaviour across the whole task.

From execution to return goes a process result: exit code, stdout, stderr, elapsed time. By now there is no structure left. It’s bytes, and it can be 200 of them or 40 million.

From return to assembly goes truncated text. This is the most destructive boundary and the least documented one. Somebody decided how many lines fit, whether the cut happens at the head or the tail, whether stderr rides along, whether the exit code survives. An agent that “tries the same thing three times” is usually being handed a version of the failure with the one line that would have solved it removed.

Take a concrete case: a failing test suite prints hundreds of progress lines and ends with the diff that matters. Cutting to the first 100 lines hands the model only the tests that passed. Cutting to the last 100 hands over the diff and hides which file was being compiled when it broke. Both policies are defensible, both produce different trajectories on the same task, and neither is usually written down anywhere.

Why the order isn’t negotiable

The layers look interchangeable in a diagram and aren’t in code.

Permission has to run before execution, and that one is obvious. The less obvious one is that truncation has to run after execution and before the next context assembly, because that’s the only moment where the full output still exists to decide from. A harness that truncates at assembly time already lost the original and is cutting blind.

Cost control has to run before the model call, not after. A ceiling checked afterwards has already been breached. That reads like a detail until you work out that a large tool catalogue plus a full history can make one call cost more than the previous five combined.

The context layer needs to know the real limit, not the advertised one. A 2024 benchmark evaluated 17 long-context models on 13 tasks and found large performance drops as length grows; among those claiming 32K tokens or more, about half held up at 32K3. The advertised number is the ceiling the API accepts, not the range in which the model still finds what you put there.

The layers leak into each other

They aren’t independent, and that’s what makes diagnosis treacherous. A common chain, with the symptom at the end of the queue:

  1. You connect three tool servers and the catalogue passes 60 descriptions.
  2. The catalogue takes more fixed space in every call, so the window hits its limit earlier.
  3. The context layer compacts sooner, and the summary drops the constraint the user gave in the first message.
  4. The agent proposes an action that constraint had ruled out.
  5. The permission layer stops and asks, and you approve without remembering the constraint either.
  6. The task finishes wrong and costs twice as much.

The symptom shows up in cost and in quality. The cause is in the tool layer, three hops back. No model swap touches any of it, which is why the same model feels better in one product than in another.

The minimum viable set

Not every layer has to exist on day one.

start withassemble the contexttwo to four toolsa step limitcan waitgranular permissionpersistent sessionsubagentsmodel routingthe sandbox is not on the "can wait" list once the commandcomes from text you did not write
Figure 3The three on the left make an agent work. The four on the right make it survive production, and none of them fixes anything in week one.

With context assembly, two to four tools and a step limit you have an agent that solves real tasks. Building that minimum from scratch is the fastest way to see where the decisions live, because every omission becomes your bug instead of an unexplained behaviour in somebody else’s tool.

Granular permission, persistent sessions, subagents and model routing can wait. All four solve problems of scale, and none of them shows up in a ten-iteration task running on your laptop.

The sandbox is the exception, and it earns the warning in the figure. While every command traces back to text you wrote, the risk is your own mistake. The moment the agent reads a GitHub issue, a web page or a file that came from outside, that content lands in the same window as the instructions and can start proposing actions. A 2023 study built an emulator to test agents against 36 high-stakes tools across 144 cases and measured failures with serious consequences in 23.9% of cases even for the safest agent in the sample4. That number comes from one specific setup and isn’t a universal rate, but it isn’t the order of magnitude of a rare event either.

Where the layer split misleads you

A layer isn’t a module. The separation is conceptual. Turning each one into its own file with its own interface, too early, produces an abstraction you have to dismantle the first time truncation needs to know how much window is left. Context and return are one decision seen from two sides.

More layers isn’t better. A 2024 paper put a number on the opposite: a fixed three-phase process, with no model choice of next step, reached 32.00% on SWE-bench Lite at US$ 0.70 per instance, ahead of the open-source agents of that period5. Part of what gets called a layer is complexity competing with a capability the model already has.

The seven don’t cost the same attention. Context and tools are everyday decisions. Subagents and model routing are decisions most teams make once and never revisit. Spreading effort evenly across all seven is the standard mistake of someone who has just read a diagram like Figure 1.

User perception isn’t a layer but behaves like one. What the agent shows while it works changes how the same trajectory gets judged. Streaming and the experience of waiting alters no decision the model makes and still decides whether a person kills the task halfway.

None of this fixes inconsistency. Layers lower the cost of each failure. They don’t turn an agent that gets six out of ten into one that gets ten.

How to assemble this in practice

  1. Write the loop before writing the layers. Assemble, call, execute, return. Four functions and a while with a counter.
  2. Put the step limit in the first commit. It’s the only layer that protects you from yourself while everything else is still wrong.
  3. Log what crosses each boundary, not what the terminal showed. The full request, the raw tool call, the complete output before the cut, and the text that came back after it.
  4. Treat truncation as a product decision. Write down how many lines fit, which end gets cut, and what signals that a cut happened. If it isn’t written down, it’s scattered.
  5. Add layers by symptom, not for completeness. Session when losing work starts to hurt. Subagents when exploration fills the window. Granular permission when confirmation has become an automatic click.
  6. Stand up the sandbox the day third-party content arrives. Not earlier, and not a week later.

What each layer costs

In tokens the bill is lopsided, and the order of magnitude is worth knowing.

Tools is the layer with the most visible fixed cost: a schema with five parameters and short descriptions usually lands between 150 and 400 tokens, and the whole catalogue is resent on every iteration. Context is the growing cost, because history only accumulates until somebody cuts it. Subagents cost in bursts, since each one pays for its own system prompt and its own catalogue.

Permission, sandbox, session and cost barely spend tokens at all. They spend latency and engineering time, which shows up on a different line: a synchronous confirmation costs seconds of a person, the most expensive resource in the set.

The ratio worth computing is fixed cost over useful cost. If the tool catalogue occupies 12K tokens and the average task uses 40K, a third of what you pay on every call is catalogue, and most of it describes tools that task will never call. Count your own before accepting any estimate, including this one: it’s two lines of code and the number tends to surprise.

Footnotes

  1. Yang et al. (2024) investigated how interface design affects agent performance and built an interface specifically for the agent, with repository navigation, verified editing and test execution.

  2. Wang et al. (2024) describe the OpenHands platform, where the execution sandbox, coordination between multiple agents and benchmark integration are declared parts of the platform rather than of the agent.

  3. Hsieh et al. (2024) evaluated 17 long-context models on 13 tasks and found sharp drops as length grows, with roughly half of those claiming 32K tokens holding performance at that length.

  4. Ruan et al. (2023) emulated tool execution with a model in order to test agents across 36 high-stakes tools and 144 cases; by their automatic evaluator, even the safest agent failed in a risky way 23.9% of the time.

  5. Xia et al. (2024) showed that a fixed localise-repair-validate process, with no autonomous choice of next step, beat the open-source agents of its time on SWE-bench Lite at a lower cost per instance.

Frequently asked questions

What are the layers of an agent harness?
Seven: context management, the tool catalogue, the permission system, an execution sandbox, session state, subagent orchestration and cost control. Context and tools decide what goes into the call. Permission and sandbox decide what leaves it and reaches the world. Session, subagents and cost decide how long any of it lasts.
What does a harness need to have to work at all?
Three things: a routine that assembles the context, a handful of tools with a validated schema, and a step limit. That's enough to solve real tasks. The other four layers exist for the day the task runs past twenty iterations, a command deletes the wrong file, or the session dies halfway through.
What's the difference between the permission layer and the sandbox?
Permission decides beforehand: this specific action runs, stops and asks, or is refused outright. The sandbox decides reach: if the action does run, how far it gets across the filesystem, the network and the clock. The first is a policy you write; the second is a limit the operating system enforces.
Can I start without a sandbox?
Only while every command comes from text you wrote yourself. The moment the agent reads an issue, a web page or a third-party file, that content becomes untrusted input and the sandbox stops being optional. A 2023 study measured high-risk failures in 23.9% of cases even for the safest agent it tested.
Doesn't an agent framework give me these layers already?
Some of them, rarely all, and almost never the ones you notice missing. Frameworks usually ship a loop, a tool catalogue and some notion of memory. Granular permission, a real sandbox, session resume and a cost ceiling tend to be left to you, and those four only hurt in production.
How do I tell which layer is causing the problem?
By the symptom, which differs per layer. An agent redoing finished work is context. An agent describing a command instead of running it is tools. A destructive command that went through is permission. A session that restarts from zero is state. A bill larger than expected is cost. Confirm in the trajectory, never the terminal.

References

  1. Wang, X. et al.. OpenHands: An Open Platform for AI Software Developers as Generalist Agents (2024)arXiv:2407.16741
  2. Yang, J. et al.. SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering (2024)arXiv:2405.15793
  3. Ruan, Y. et al.. Identifying the Risks of LM Agents with an LM-Emulated Sandbox (2023)arXiv:2309.15817
  4. Xia, C. S. et al.. Agentless: Demystifying LLM-based Software Engineering Agents (2024)arXiv:2407.01489
  5. Hsieh, C.-P. et al.. RULER: What's the Real Context Size of Your Long-Context Language Models? (2024)arXiv:2404.06654