Give two teams the same language model and ask each to build an agent. One ends up with something that finishes tasks, stops when it should and leaves a readable record. The other gets an agent that loops, forgets its goal and occasionally does something alarming. The model is identical; the difference is everything around it. That surrounding software is the agent harness, and this page explains what it contains and why it deserves as much attention as the model.
A working definition
An agent harness is the runtime that turns a model's text output into actions. It decides what the model sees, which tools it may call, what happens when it calls one, when the run stops and what gets written down. A short way to put it: the model proposes, the harness decides.
A harness has six jobs.
- Run the loop: send context to the model, read the reply, execute any tool calls, feed the results back, repeat.
- Expose tools: describe them to the model, validate the arguments it sends, run them and return the output.
- Assemble context: choose which instructions, history, documents and memories go into each model call.
- Enforce permissions: allow, refuse or hold each requested action for a person.
- Apply limits: time, steps, tool calls, spend and output size.
- Keep a record: every request, decision, tool run and outcome, in order.
Coding agents in a terminal, desktop assistants, browser agents and enterprise workflow products all contain a harness, even when nobody calls it that. The definition of an AI agent describes the agent from the outside; this page is about the machinery inside.
The loop, in code
Stripped to its core, every harness runs something close to this:
context = build_context(goal, instructions, memory)
while True:
reply = model.generate(context)
if reply.is_final:
return finish(reply) # check acceptance criteria first
for call in reply.tool_calls:
verdict = policy.check(call) # allow, hold for a person, or refuse
if verdict.allowed:
result = tools.run(call, timeout=verdict.timeout)
else:
result = verdict.explanation
trail.record(call, verdict, result)
context.append(call, result)
if limits.exceeded(trail):
return stop("limit reached", trail)
Most of the engineering hides in the helper functions. What does finish check before it accepts a final answer? What does the model see when a tool fails: a stack trace, a short error, or nothing? Does a refused call come back as an explanation the model can work with, or does the run crash? A harness that feeds errors back clearly lets the model recover. One that swallows them produces agents that repeat the same broken call until a limit stops them.
Tools: the agent's hands
A tool reaches the model as a name, a description and a parameter schema. The description is effectively part of the prompt: vague descriptions produce vague tool use, and two tools with overlapping descriptions produce an agent that picks between them more or less at random.
Good harnesses keep the tool list short for each task, validate arguments before running anything, cap and truncate output so one huge result cannot flood the context, and return errors in a form the model can act on. Tools can be built into the harness, run as shell commands (see what a CLI is), or come from external servers through a protocol such as MCP. However a tool arrives, the harness is what runs it, so the harness is where its use is controlled.
Context: what the model sees each turn
The model keeps nothing between calls. Each turn, the harness rebuilds the input: system instructions, the goal, tool definitions, the conversation so far, tool results, retrieved documents and any stored memories. Long tasks outgrow the context window, so the harness has to compress, usually by summarizing older steps or dropping bulky tool output.
Two details decide whether this goes well. First, summaries must keep pointers to evidence: a summary that says "the contract renews automatically" without the file and page has quietly turned a finding into an assertion. Second, text that came from a tool (a web page, an email, a file) must be marked as data, not as instructions. If the harness mixes them, a sentence inside a document can steer the agent. That attack, prompt injection, is largely a harness problem rather than a model problem.
Permissions: where trust is decided
A model can ask for anything. Whether it gets it is the harness's call, and this is the part that most separates a demo from something you can deploy. Useful permission designs share a few traits.
- Each tool or action has a mode: run freely, hold for approval, or refuse.
- The person approving sees the exact call with its arguments, not the model's description of it.
- An approval covers one attempt and is checked again at execution time, so a yes cannot be replayed later.
- Credentials stay with the harness, stored as references, and never enter the model's context.
- Connecting a tool and authorizing a task to use it are separate decisions.
The kinds of action that deserve a pause are fairly stable across domains: sending things out, deleting, exporting data, scheduling recurring work, acting in a live session, changing the agent's own instructions and delegating to another agent. The seven action classes explains each one.
Limits, stopping and recovery
An agent without limits does stop eventually, either because the goal is met or because something outside it runs out. The harness should make sure it is the first. Enforced limits on wall time, tool calls, steps and spend turn runaway runs into short, explainable stops. A spend ceiling in particular should halt work and say why, not just send an alert afterwards; putting a ceiling on spend goes into the details.
Longer work also needs durability. If the process dies halfway, a good harness resumes from a recorded state instead of starting over and repeating side effects such as a second email. When durable execution is not available, the honest response is a visible refusal, not progress that only looks real. Finally, there should be one stop control that halts new work immediately, with resuming treated as a deliberate act that is attributed to a person.
Why the harness matters as much as the model
Model choice gets most of the attention, yet many of the questions a reviewer actually asks are answered by the harness alone.
| Question | Answered by |
|---|---|
| Can it delete files or send email? | The tool list and permissions |
| What does it do when a tool fails? | Error handling in the loop |
| Can a document hijack it? | How context separates data from instructions |
| How much can one run cost? | Limits and the spend ceiling |
| What exactly happened yesterday? | The trail |
| How is it stopped? | The stop control |
Models also change more often than rules should. If your approvals, limits and audit live in the harness rather than in prompt wording tuned for one model, they survive a model swap intact. Governance that survives a model change makes that argument in full.
GoCux as a harness for company work
GoCux puts these responsibilities into a company workspace. Each piece of work is a work order with a goal, the scope it may touch and acceptance criteria, plus bounds on wall time and tool calls. The order moves through queued, running, awaiting decision and done. Consequential actions wait in the awaiting-decision state until someone on the team decides, and a rejection goes on the record without releasing the work. Credentials are held on the server as references rather than in the browser. Work draws on visible credits under a daily cap, a single stop control halts new work and anything with an outside effect, and every step joins one trail the team can read. Model routing happens behind a boundary inside the service; what you control is what you write on the work order. The Task page shows the work order and governance describes the gate.
Questions to ask about any harness
- Which tools can the agent call in this task, and who decided that list?
- Which actions are held for a person, and does the approver see the exact call?
- Does an approval expire after one attempt?
- Where are credentials stored, and can the model ever read them?
- How is text from tools kept apart from instructions?
- Which limits are enforced, and what does the agent report when it hits one?
- What happens to a half-finished run if the process restarts?
- Can you read the full trail of a run, including refused and rejected steps?
The answers tell you more about how an agent will behave in production than a model comparison will.
Bring this workflow into your workspace.
Set the scope. Review the evidence. Approve the steps that need it.