A language model can propose an action. It cannot, by itself, open your repository, run a test, remember yesterday’s session, ask for approval before deleting a file, or decide that a task has produced enough evidence to stop.
The software that makes those things possible is the agent harness.
The term sounds more mysterious than the machinery. A harness is a runtime around a model. It prepares the model’s working context, describes available tools, executes approved tool calls, records what happened, and calls the model again. It also decides what the model may touch, when a human must intervene, how sessions are stored, and how requests are translated for different model providers.
That distinction matters. People often compare agents as if the model were the whole product. In practice, the same model can feel precise in one agent and reckless in another because the harness controls the environment in which the model operates.
Model, agent, and harness are different things
These three terms are frequently collapsed into one:
- A model maps an input context to an output. That output may contain text, structured data, or a request to call a tool.
- An agent is the task-performing system a user experiences.
- A harness is the software runtime that turns model outputs into an ongoing, controlled process.
A compact equation is useful:
agent = model + harness + environment
The environment includes the files, APIs, applications, credentials, sandboxes, people, and policies the agent can encounter. The harness is the mediator. It presents a selected view of that environment to the model and interprets the model’s response.
OpenAI’s practical guide describes the basic agent ingredients as model, tools, and instructions. Anthropic describes agents as models using tools in a feedback loop. The word harness names the implementation layer that assembles and operates those ingredients.
The interface is only the front door
An agent may appear as a terminal program, an editor panel, a web chat, an email address, or a background worker. The interface collects a request and renders progress, but it does not define the agent’s core behavior.
The same harness can often support several interfaces. A coding agent might run interactively in a terminal during development and headlessly in CI. A research agent might accept a request in chat but deliver its report by email. What matters is that every interface produces an input the harness can normalize into a session.
This separation is valuable because interfaces change faster than tasks. A useful agent should not need a new reasoning architecture merely because its user moved from a terminal to Slack.
Instructions establish the operating role
Before the model sees a user’s request, the harness usually adds instructions. These can include:
- the agent’s role and objective;
- project or organization rules;
- available files and working directory;
- response and formatting expectations;
- safety boundaries and escalation rules;
- descriptions of tools and when to use them;
- relevant date, locale, account, or environment context.
These instructions are often called a system prompt, but a production harness may assemble them from several sources: built-in defaults, user preferences, repository files such as AGENTS.md, task-specific policies, and dynamically loaded skills.
Instructions are not magic policy enforcement. A sentence saying “do not touch production” is weaker than a runtime that provides no production credential. The strongest harnesses express important limits twice: once in language so the model can reason about them, and once in code so the runtime can enforce them.
Good instructions are also economical. Every repeated paragraph consumes context and competes with the task itself. A harness should load stable rules reliably while retrieving large manuals only when they become relevant.
Tools turn suggestions into actions
Without tools, a model can describe how to inspect a log. With tools, an agent can fetch the log, filter it, compare timestamps, and attach the result to a report.
A tool is normally presented to the model as a contract:
{
"name": "search_logs",
"description": "Search application logs within an allowed time range",
"parameters": {
"service": "string",
"query": "string",
"start_time": "ISO-8601 timestamp",
"end_time": "ISO-8601 timestamp"
}
}
The model sees the name, description, and parameter schema. The harness owns the implementation. When the model emits a matching tool call, the harness validates the arguments, checks authorization, runs the code, and converts the result into a message the model can inspect.
Tool quality has an outsized effect on agent quality. A vague description makes selection unreliable. A giant “do everything” tool hides meaningful choices. Unstructured errors leave the model guessing. A well-designed tool has a narrow purpose, explicit inputs, bounded output, useful failure messages, and predictable side effects.
Tools also need different trust levels. Reading a public webpage, changing a local file, sending an email, transferring money, and deleting a cloud database should not share one approval policy. The harness is where those distinctions become executable.
Protocols such as Model Context Protocol standardize how a host discovers tools, prompts, and resources from separate servers. That improves interoperability, but the host still owns consent, connection permissions, capability boundaries, and the final decision to invoke anything.
The loop is what makes the system agentic
A chatbot usually follows a short path:
user message → model → answer
An agent harness supports a longer path:
task → model → tool call → tool result → model → ... → final answer
The model is not executing tools internally. It emits a structured request. The harness pauses generation, performs the action, appends an observation, and asks the model what to do next.
In simplified pseudocode, a single-agent harness looks like this:
while (turns < maxTurns) {
const context = assemble(instructions, history, tools)
const output = await model.generate(context)
if (output.finalAnswer) return output.finalAnswer
const call = validate(output.toolCall)
await enforcePolicy(call)
const observation = await execute(call)
history.push(call, observation)
}
throw new Error("turn limit reached")
Real runtimes handle streaming, retries, multiple calls, handoffs, partial failures, cancellations, and human approvals. The essential mechanism remains the same: decide, act, observe, repeat.
A research task, turn by turn
Suppose a user asks an agent to compare nearby primary schools using recent performance data, travel time, and published admissions criteria, then deliver a spreadsheet and a recommendation.
The harness might run this sequence:
- Load the user’s location, output preferences, and research rules.
- Give the model web-search, browser, spreadsheet, and email tools.
- Let the model plan searches for official school and government sources.
- Execute the first search and return its results.
- Let the model notice missing admissions data and search again.
- Run code to normalize scores and travel times into a table.
- Return the generated spreadsheet metadata to the model for review.
- Ask for human confirmation before sending external email.
- Deliver the message and store the report in the session.
No single model response contains the finished workflow. Progress emerges from repeated calls grounded in new observations. If a source is unavailable, a spreadsheet formula fails, or the user changes the criteria, the harness preserves enough state for the model to adapt.
State gives the loop continuity
Every turn needs a usable record of what came before. At minimum, that includes user messages, model outputs, tool requests, and tool results. A mature harness may also track:
- generated files and other artifacts;
- task plans and completion checks;
- approvals and denied actions;
- token, time, and monetary budgets;
- checkpoints and resumable execution state;
- citations and source provenance;
- traces for debugging and evaluation.
Simply resending an ever-growing transcript does not scale. Context windows are finite, tool results can be enormous, and old details eventually obscure current work. Harnesses therefore compact, summarize, retrieve, or discard state.
These transformations are consequential. If compaction drops an unresolved constraint, the model may violate it later. If a tool dumps thousands of irrelevant log lines into the transcript, the next decision gets harder and more expensive. Context management is not housekeeping; it is part of the agent’s reasoning surface.
Persistent state also changes who controls the working relationship. If sessions live in an open local format, users can inspect, back up, search, export, or migrate them. If all history is trapped inside one vendor’s application, changing models may also mean abandoning the accumulated record of work.
Provider adapters make models replaceable—with limits
Model providers expose different request formats, tool-call shapes, streaming events, reasoning metadata, image rules, and error semantics. A provider adapter translates between those APIs and the harness’s internal representation.
That layer can enable useful choices:
- use a fast, inexpensive model for routine classification;
- switch to a stronger model for a difficult coding turn;
- run a private model for sensitive data;
- compare providers on the same saved task;
- continue a session after a provider outage or policy change.
Pi’s open-source packages make this split explicit: its agent core manages tool calling and state while its AI package provides a unified multi-provider API. The OpenAI Agents SDK likewise exposes model-provider integration points and supports mixing models across a workflow.
Portability is not perfect. One provider may support a hosted search tool, strict structured output, long-lived prompt caching, or a reasoning format that another does not. An adapter can normalize common concepts, but it cannot manufacture an upstream capability. Harnesses should expose capability differences instead of pretending every model is interchangeable.
Safety lives in the execution path
An agent that can act needs more than a polite prompt. The harness should provide layered controls:
- least privilege: expose only the tools and credentials required for the task;
- scoped resources: restrict filesystem paths, accounts, repositories, and time ranges;
- argument validation: reject malformed or out-of-policy tool calls;
- human approval: pause before consequential external or destructive actions;
- budgets: cap turns, time, tokens, money, and parallel work;
- sandboxing: isolate code execution and network access;
- auditability: retain requests, decisions, tool calls, results, and approvals;
- stop controls: support cancellation, refusal, failure, and escalation.
The model can help identify risk, but enforcement cannot depend on the model agreeing with itself. If a path is forbidden, the runtime should make it unreachable. If an action needs consent, the tool executor should refuse to proceed until consent exists.
This is why harness design can matter as much as benchmark performance. A slightly weaker model inside a well-scoped, observable runtime may be more useful than a stronger model connected directly to broad credentials.
A harness determines the character of an agent
Two products using the same model may behave very differently:
| Harness choice | Practical effect |
|---|---|
| Four precise tools | Easier selection and fewer invalid calls |
| Two hundred tools loaded at once | Higher context cost and more selection errors |
| Local session files | Inspectable, portable work history |
| Opaque hosted sessions | Convenient, but harder to migrate or audit |
| Approval before external writes | Slower, safer collaboration |
| Automatic execution | Faster for bounded, reversible tasks |
| Rich traces and artifacts | Easier debugging and evaluation |
| Final text only | Failures disappear behind a plausible answer |
The harness also encodes taste. Does it interrupt for every harmless command, or distinguish reversible reads from consequential writes? Does it show raw internal noise, or provide a clean progress view with evidence? Does it keep adding tools, or protect a small understandable core?
Those are product decisions, not model capabilities.
Start with the smallest loop that works
It is tempting to begin with multiple agents, dynamic tool discovery, long-term memory, and elaborate planning. Most tasks do not need all of that.
A sound progression is:
- Give one model clear instructions and a small set of tools.
- Add an explicit loop with a turn limit and observable tool results.
- Add deterministic checks for success where possible: tests, schemas, or source requirements.
- Add approval gates for consequential actions.
- Persist sessions only after deciding what must be recoverable and auditable.
- Introduce routing or multiple agents when one context genuinely becomes overloaded or responsibilities need different permissions.
Complexity in the harness creates new failure modes: hidden state, circular delegation, runaway cost, duplicated work, incompatible histories, and ambiguous ownership. Each layer should earn its place by solving a measured problem.
How to evaluate a harness
Model leaderboards tell you little about the runtime around the model. Evaluate the whole agent on real tasks and ask:
- Can I inspect exactly which instructions and tools were active?
- Are tool inputs and outputs recorded in a useful format?
- Can I restrict credentials and resources by task?
- Which actions require approval, and can those rules be changed?
- What happens after a timeout, malformed result, or provider outage?
- Can a session resume without silently losing constraints?
- Can I export sessions and artifacts in ordinary formats?
- How difficult is it to switch models or providers?
- Does the harness measure task success, not merely produce fluent text?
- Can I stop it immediately?
For coding work, use a repository with tests and deliberately introduce a failure. For research, require primary sources and verify citations. For operations, simulate a missing credential or rate limit. A good harness makes failures visible and recoverable instead of polishing them into a confident paragraph.
The model is powerful; the harness gives you leverage
The climbing metaphor works because a harness does two jobs at once. It gives a climber access to useful equipment, and it connects that climber to limits that make movement survivable.
An agent harness does the same for a model. Instructions give direction. Tools provide reach. The loop turns isolated guesses into adaptive work. State preserves continuity. Provider adapters create choice. Policy gates keep capability inside an acceptable boundary.
Most importantly, the harness is software that users and teams can inspect, modify, run locally, and own. Models will keep changing. A well-designed harness lets the workflow, history, tools, and safeguards remain under the user’s control while the engine behind them evolves.
Sources and further reading
- What Is a Harness?, Earendil’s climbing metaphor and introduction to instructions, tools, loops, translation, and user ownership.
- A practical guide to building agents, OpenAI’s guide to models, tools, instructions, orchestration, and guardrails.
- Building effective agents, Anthropic’s distinction between workflows and agents and its guidance on tool-using feedback loops.
- How the agent loop works, a concrete model–tool–result execution cycle.
- Model Context Protocol architecture, the host, client, server, capability, and security boundaries behind MCP integrations.
- Pi agent harness source, an open-source agent runtime, coding interface, and multi-provider model layer.
- Running agents, the OpenAI Agents SDK loop, stop conditions, handoffs, and model-provider configuration.
- Hacker News discussion, community discussion of the original article.

Top comments (0)