# The harness around the model

A model can propose an action. An agent harness decides what that proposal means, whether it may run, what state to save, and when to ask the model again.

Suppose a developer asks: “Fix the parser bug and run its tests.” The model might request a file read. Your program executes the read and sends the result back. The model then requests an edit and a test command. Those requests are data until the harness dispatches them to real code.

The small loop is easy to recognize. Most of the engineering lives around it.

## One task, several model requests

![Agent loop: user input leads to context preparation and a model response. Tool calls are validated and authorized; permitted tools run, and their outcomes return to context. Invalid or denied calls also become results. Without tool calls, the harness checks pending input and stop rules, then continues or finishes.](../guide/assets/agent-loop.svg)

This is a teaching abstraction, not a claim that every implementation uses this exact control structure. Codex organizes work around session tasks and sampling steps; pi exposes a reusable loop with lifecycle hooks; Goose composes ordered state-machine operations; Sidekick coordinates a native loop or external runtime through events, durable turns, and workflow workers. Their chapters show the actual implementations.

Use these terms throughout the guide:

| Term | Meaning here |
| --- | --- |
| Model request | One request to a model provider, possibly streamed. |
| Tool call | A model-produced name, arguments, and identifier that the harness resolves to executable behavior. |
| Tool result | The outcome associated with that identifier, including failure or denial. |
| Run | Work initiated by user input, potentially containing many model requests and tool calls. |
| Session | Conversation state and metadata that can outlive a run. |
| Context | The portion and representation of state sent in the next model request. |
| Harness | The runtime that coordinates model requests, tools, state, policies, and external clients. |

“Turn” is deliberately not a universal unit here. Each project uses it differently. Compare lifecycle boundaries before comparing metrics such as turns per task.

## Walk through a repair

This trace is illustrative. It was not executed as a benchmark.

| Step | Model or user behavior | Harness responsibility |
| --- | --- | --- |
| 1 | User asks for a parser fix. | Select instructions, tools, model, and conversation context. |
| 2 | Model requests `read_file("parser.ts")`. | Resolve the tool, validate its arguments, check access, execute, and associate its result with the call ID. |
| 3 | Model requests an edit based on the file contents. | Check the edit's preconditions and execute the mutation under the configured policy. |
| 4 | Model requests a test command. | Manage a process, collect bounded output, propagate cancellation, and report success or failure accurately. |
| 5 | Test fails and the model proposes a second edit. | Continue with the observed failure in context. A failed command need not be a failed run. |
| 6 | Tests pass and the model writes an explanation. | Apply stop rules, account for queued input, finalize state, and notify clients. |

The harness does not know that the fix is correct just because the model says it is finished. The test result is evidence; the model's conclusion is an interpretation of that evidence. Evaluation of task quality is separate from the runtime's ability to execute a valid loop.

## Five boundaries worth learning

### Proposed action to executed action

A schema describes what arguments are valid. It does not grant permission. An approval decision authorizes an action under a policy. A sandbox limits what the process can actually access. These are three separate mechanisms.

For example, a shell command may be valid JSON, approved by a user, and still fail because the operating system denies access to a path. Conversely, a custom extension can bypass an application-level check if it holds direct host access. Always locate the enforcement point.

### Live events to saved state

A UI can display a tool result before the persistence layer has committed it. A process crash in that gap may leave the UI and resumed conversation disagreeing. Saving a conversation also does not prove that an interrupted external action is safe to repeat.

For an email send, the process might crash after delivery but before recording success. Replaying the tool may send a second email. Idempotency means that repeating an operation with the same identity does not repeat its effect; it needs support at the effect boundary, not just a transcript file.

### Full history to model context

A session can contain more information than fits in the next request. Compaction replaces some history with a shorter representation; truncation simply removes or bounds content. Both influence what the model knows. They must preserve enough tool-call/result structure for the provider to accept the request.

The saved original history, the current model context, and the user-visible conversation can therefore be different views. Ask which one a resume, fork, or compaction operation updates.

### Concurrent work to ordered history

Two reads can finish in the opposite order from their calls. A UI may want to display each result immediately, while the transcript may need a deterministic order. Two edits to the same file introduce another problem: they may invalidate one another's assumptions.

Concurrency is a scheduling decision. It requires reasoning about effects, not just wrapping tool calls in `Promise.all` or its equivalent.

### One run to many participants

Steering adds new input while work is active. Follow-up queues defer input until a later boundary. Cancellation requests that active work stop. Multi-agent delegation creates additional agent runs. Multi-player collaboration lets multiple humans or clients participate in shared work. These solve different problems.

A server accepting two connections is a useful primitive for multi-player support. It does not establish user identity, ownership of approvals, conflict resolution, or a shared editing experience. The advanced chapter evaluates those separately.

## Read the implementations in a useful order

Start with [pi](../snapshots/pi/482c1381a00d/chapter.md) to study a clearly exposed loop and its hooks. Then read [Goose](../snapshots/goose/34a222e3f2b9/chapter.md) to see ordered operations and effects express control flow. Read [Codex](../snapshots/codex/8c076942cb70/chapter.md) for task lifecycles, tool scheduling, policy enforcement, and client coordination. Read [Sidekick](../snapshots/sidekick/463d653124e1/chapter.md) to see event-driven orchestration across a shared service, workers, and external runtimes. This is an educational reading order, not a product ranking.

Then use the [comparison](comparison.md) and [advanced topics](advanced-topics.md) to follow one concern through all four. The [builder's lab](build-a-harness.md) turns the comparison into design exercises.
