The Harness
The model is the engine. The harness is the rest of the car — the loop that drives it, the tools it can reach, the context plumbing, the brakes, the instruments. Same engine, wildly different vehicle.
This manual covers the whole machine: what each subsystem does, how to build it, when to add it, and why the same model behaves so differently inside different harnesses. Below is a harness, running. Everything in this document is color-coded to these five subsystems.
Why harnesses exist
A language model is a text predictor with no hands, no memory of your systems, and no way to check its own work. A harness is the software wrapped around it that supplies all three — and it turns out that software determines most of what the agent can actually do.
Strip the vocabulary away and a harness is four things: a loop that calls the model repeatedly instead of once; tools that let its output cause real effects; plumbing that decides what the model sees each turn; and controls that decide what it's allowed to do and when it's done. Chat interfaces are minimal harnesses (one turn, no tools). Coding agents are heavy harnesses (hundreds of turns, dozens of tools, compaction, sandboxes, test loops).
The reason "harness" became the word of the moment: teams kept discovering that swapping the harness moved results as much as swapping the model. The same frontier model that meanders in a bare chat window ships working code inside a well-built coding harness — because the harness feeds it test output, lets it retry, keeps its context clean, and stops it when it's done. Capability lives in the pair, not the model.
How we got here
The agent loop
Every harness — from a 50-line script to Claude Code — is one while-loop wearing different amounts of armor. Learn the loop cold and every framework becomes readable, because they're all decorating this.
# the whole field, in one loop — colors match the manual's legend history = [system_prompt, tool_definitions, user_task] while True: reply = model(history) # ① one inference if reply.tool_calls: for call in reply.tool_calls: if not gate.allows(call): # ② permission check result = ask_human(call) # or block outright else: result = execute(call) # ③ real side effects history += [call, result] # ④ feed result back else: # model thinks it's done if verified(reply): return reply # ⑤ check, don't trust history += [critique(reply)] # send it back to work history = compact(history) # ⑥ manage the window if budget.exceeded(): return escalate() # ⑦ stop conditions
Seven numbered lines, seven design decisions — and the rest of this manual is those lines expanded. Notice what the loop implies:
- The model never acts. It emits a request to act. Your code executes. Everything you control about safety and reliability lives in that gap.
- Results are just more context. The model "perceives" the world only through what you append to history. Garbage tool output in, garbage decisions out.
- Stop conditions are yours to write. Turn caps, token budgets, wall-clock limits, cost ceilings, "no progress in N turns." A loop without them is an outage generator.
The instruction layer
The system prompt is the harness's configuration file written in prose. Production prompts aren't one paragraph of vibes — they're a layered document where each layer has a job, and each missing layer has a signature failure.
The rule of thumb that separates hobby harnesses from production ones: steer with code when you can, prose when you must. "Never call delete_db in prod" written in the prompt is a suggestion the model will occasionally ignore under pressure; the same rule written as a gate in code is physics. Prompts steer judgment (tone, priorities, when to ask vs. act). Code enforces invariants (permissions, budgets, formats).
- Instructions compete with everything else in the window. A 6,000-token prompt the model half-follows loses to a 1,500-token prompt it fully follows. Cut until every sentence has changed behavior in a trace you've read.
- Positive beats negative. "Cite the file path for every claim" outperforms "don't make things up." Models follow patterns better than prohibitions.
- Examples are the strongest steering tokens you own. One worked example of a perfect tool call or output format outperforms three paragraphs describing it.
- Version it like code. The prompt is a build artifact: diff it, review it, and eval every change (Module 07). Silent prompt edits are how regressions ship.
Tool design
A tool is a function you expose plus a description the model reads. That description is not documentation — it's part of the prompt, consulted at decision time, every turn. Most harnesses are won or lost here, not in the system prompt.
The model chooses tools the way you'd choose from a menu written by a stranger: entirely from the names, descriptions, and parameter hints. It can't read your source. So the schema is the entire interface — and vague schemas produce an agent that guesses, thrashes between similar tools, and hallucinates parameters.
Design rules that generalize
- Name by intent, scope by task.
search_ordersbeatsquery_db. If two tools overlap, the description must say when to pick each — or the model will alternate between them at random. - Errors are teaching moments. A stack trace teaches nothing;
{"error":"date_range too wide","hint":"max 90 days — split the query"}lets the model self-correct on the next turn. Design error returns for a model reader. - Budget the output. Every byte a tool returns is context you pay for (Module 04). Return the 20 rows the task needs with a
total_matchescount, never the 10,000-row dump. - Fewer, sharper tools. Past a couple dozen tools, selection accuracy degrades. Consolidate (
file_read/file_write/file_list→ onefiletool with anactionenum) or gate tool visibility by task phase. - Mark side effects. Distinguish read-only tools from world-changing ones in the schema itself — your gate layer (Module 05) keys off exactly this.
Context management
The context window is the agent's entire perceived universe, and it's a finite budget that every subsystem spends from. Long-running agents don't die from bad reasoning — they die from context mismanagement.
Two facts drive everything in this module. First: in a loop, context compounds. Every tool result, every retry, every file read stacks into history — a 40-turn session can eat a six-figure token window on results alone. Second: quality degrades before capacity runs out. Models attend less reliably to material buried in a huge window ("context rot"), so an agent at 90% capacity isn't almost-fine — it's already reasoning worse.
The wider toolkit
- Just-in-time retrieval beats preloading. Don't stuff every maybe-relevant document in up front — give the agent search/read tools and let it pull what the current step needs. Lighter window, fresher attention.
- Compaction is lossy — test the loss. A summary that drops the one constraint that mattered ("customer said don't email them") is worse than truncation. Treat your summarizer as a component with its own evals (Module 07).
- Memory files are the cheapest long-horizon trick. A plain markdown file the agent reads at start and appends decisions to (
NOTES.md,CLAUDE.md) gives persistence across sessions with zero infrastructure — and you can read it, which matters for debugging. - Cost is a context problem. Loops multiply tokens: 30 turns × a fat window is real money per task. Compaction and output-budgeted tools (Module 03) are your cost levers as much as your quality levers.
Gates & permissions
The model requests; your code disposes. Gates are the layer that decides — per action, per environment — whether execution is automatic, announced, approved by a human, or refused. This is where agent safety actually lives.
Score every tool call on two axes: reversibility (can you undo it?) and scope (who or what does it touch?). Reading a file is reversible and private — automate it. Sending an email is irreversible and external — a human sees it first. Deleting production data is irreversible and systemic — the harness shouldn't even own that capability. The matrix below encodes the pattern:
Reversible, private, no external blast radius — gating this would only train your team to click "approve" without reading.
Patterns that hold up
- Allowlist, don't blocklist. Enumerate what's permitted; everything else fails closed. Blocklists lose to creativity — yours and the model's.
- Draft, don't send. For anything external (email, posts, messages), the agent produces the artifact and a human fires it. You keep 95% of the leverage and 0% of the "it emailed the whole client list" incidents.
- Sandbox first, always. Give the agent a disposable environment where AUTO is safe, and promote actions outward only with evidence. Cheap sandboxes are the highest-ROI safety spend in the field.
- Budgets are gates too. Token ceilings, dollar caps, wall-clock limits, max-turns — quantitative gates that stop runaway loops no rule anticipated.
- Audit everything. Every call, every gate decision, every human override into an append-only log. When something goes wrong, the trace is your only forensics.
- Approval fatigue is a failure mode. Gate too much and humans rubber-stamp; the gate becomes theater. Ruthlessly automate the safe stuff so attention is spent where it counts.
Verification
Generating is easy; knowing it's right is the hard part. The single biggest reliability upgrade in any harness is refusing to accept the model's "done" — and checking instead.
The organizing idea is the generator–verifier gap: tasks where checking is much cheaper than doing are the tasks agents crush. Code is the flagship case — tests and compilers are free, instant, incorruptible critics — which is exactly why coding agents matured years ahead of everything else. The engineering corollary: you can often make a task agent-ready by making it checkable — demand structured output you can validate, define acceptance tests up front, decompose fuzzy work into steps with crisp pass/fail edges.
Compilers, test suites, linters, type checkers, schema validators. Free, instant, zero false authority. Route their raw output straight back into context — this feedback loop is the agentic coding revolution.
Domain rules as code: "totals reconcile," "no PII in output," "response cites a source for every figure." Cheap to write, brutal at catching plausible-but-wrong.
A second model grades against a written rubric — for the fuzzy qualities (tone, completeness, reasoning) nothing deterministic can score. Powerful, but it's a model: it drifts, flatters, and needs its own eval (Module 07) before you trust it.
The scarce resource. Spend it where stakes are highest and automation is weakest — sampled, not universal, and always downstream of the cheaper rungs above.
Task success
Cost per task
Latency
Verification off: fast, cheap, and you're shipping the model's first draft with its confidence as your only quality signal.
Evals
An eval is a repeatable test of the whole harness: same tasks in, scored outcomes out, run on every change. Without one, "we improved the prompt" is a mood. With one, it's a diff.
Harness evals are not model evals. Model benchmarks (MMLU, coding leaderboards) tell you about the engine. Your eval tests your car: your prompt, your tools, your compaction, your gates, on your tasks. The recipe is unglamorous and universal:
- A golden set — 10 to 50 real tasks with known-good outcomes. Start with the failures that made you swear; those are your regression tests forever.
- A grader per task type — deterministic where possible (exact match, tests pass, schema valid), an LLM judge with a written rubric where not. Judges get spot-checked against human grades before you trust them.
- Multiple runs per task. Agents are stochastic: a task that passes 6 of 10 runs is a coin flip in production. Track pass rates, not pass/fail.
- Run on every change — prompt edit, tool rename, model swap, compaction tweak. The harness is a system; any change can regress any behavior.
- Read traces. Scores tell you that it broke; the transcript tells you where. The core practitioner skill of this whole field is reading agent traces the way a mechanic listens to an engine.
BLAST RADIUS
Architecture patterns
Five shapes cover essentially every agent system in production. Each is the plain loop from Module 01, multiplied or specialized — pick by task shape, not by ambition.
The landscape
Every option on the market is one of four routes. Named tools below are the early-2026 snapshot — names churn quarterly; the four routes haven't moved in years.
ROUTE ARaw loop — own everything
A provider SDK, your ~100-line loop, your tools. Every behavior is yours to see and change.
ROUTE BAgent frameworks & SDKs
Libraries that ship the loop plus the hard extras: durable state graphs, retries, streaming, tracing, handoffs.
ROUTE CReady-made harnesses
Buy the whole car; bring tasks. Extend through sanctioned seams — MCP servers, skills, hooks, config — instead of forking.
ROUTE DPlumbing & protocols
The layer under all routes: standard tool wiring, model gateways, and local serving.
| Route | You write | You get | Watch out |
|---|---|---|---|
| A · Raw loop | Everything (~100+ lines) | Total control, total understanding | You rebuild retries, tracing, persistence yourself |
| B · Framework | Graph/config + tools | Durability, observability, patterns | Abstraction debugging; framework churn |
| C · Ready harness | Config, MCP servers, skills | Years of harness engineering, day one | Their opinions are your constraints |
| D · Plumbing | Config + endpoints | Model portability, local options | Lowest-common-denominator features across providers |
Picking the model(s)
- Tool-calling reliability beats leaderboard IQ. An agent lives or dies on emitting valid, well-chosen tool calls turn after turn. Test that specifically — it varies more across models than reasoning scores suggest.
- Loops multiply cost. Per-token price × 30 turns × fat context is the real bill. This is why routing and pipelines mix tiers: cheap models for easy stages, frontier for the hard step.
- Local models earn their place when privacy, cost-at-volume, or offline operation matter — and modern open-weight models handle tool calls well enough for pipeline stages and drafts. Serve them behind an OpenAI-compatible endpoint and your harness won't know the difference.
- Long-context quality ≠ long-context size. Two models with the same window degrade differently when it's full. Eval at realistic fill levels, not on toy prompts.
Cost control
- Prompt caching is the #1 cost lever for loops. An agent re-sends the same system prompt and tool definitions every single turn — exactly the stable prefix providers cache at a fraction of full price. Keep that prefix static (no timestamps, no per-turn edits near the top) and a 30-turn session stops paying full freight thirty times for the same tokens.
- Route by tier. Frontier models for planning, diagnosis, and review; a cheaper tier for the mechanical middle — formatting, extraction, easy pipeline stages. A gateway (Route D) makes the split a config line instead of a rewrite.
- Cap in tokens and dollars. Token budgets miss price changes and model swaps; dollar budgets miss runaway context growth. Set both, per run and per day — budgets are gates that work while humans sleep (Module 05).
RECOMMENDED STARTING POINT
Failure modes
Agents fail in patterns, and the patterns repeat across every stack. Learn the six below and you can diagnose most sick harnesses from a single trace read.
Context rot
- Symptom
- Late-session quality slide: forgets its own findings, re-reads files, contradicts earlier decisions.
- Cause
- Window stuffed with stale tool output; attention degrades before capacity runs out.
- Fix
- Compact continuously, budget tool outputs, offload detours to sub-agents (Module 04).
Doom loop
- Symptom
- Same failing action, slight variations, forever. Token bill climbs; nothing changes.
- Cause
- No progress detection; error output too vague to learn from.
- Fix
- Turn/cost caps, repeated-action detection, error messages with hints (Module 03), escalate-to-human as a stop state.
Tool thrash
- Symptom
- Wrong tool, wrong parameters, or ping-ponging between two similar tools.
- Cause
- Overlapping or vague schemas; too many tools in scope at once.
- Fix
- Sharpen descriptions, merge overlapping tools, add "use X for…, use Y for…" disambiguation, trim the toolbelt per phase.
Confabulated success
- Symptom
- "Done! All tests pass." Narrator: they did not pass. The most dangerous failure — it looks like success.
- Cause
- Exit on the model's self-report instead of evidence.
- Fix
- Verified exits only (Module 06): the harness re-runs the check itself and compares, never trusts the transcript.
Prompt injection
- Symptom
- Agent "obeys" text found inside a webpage, email, or file — exfiltrates data, takes unrequested actions.
- Cause
- Untrusted content enters the same channel as trusted instructions, and the model can't reliably tell them apart.
- Fix
- Treat fetched content as data, least-privilege tools, gate all outbound actions (Module 05), never combine private data + untrusted input + an open send channel without a human in the loop.
Approval fatigue
- Symptom
- Humans rubber-stamp every gate prompt without reading. The gate is now theater.
- Cause
- Over-gating safe actions until attention is exhausted.
- Fix
- Automate the reversible, reserve approvals for irreversible+external, batch low-stakes confirmations.
Build order
Every subsystem in this manual is optional until a specific symptom appears — then it's mandatory. Building them before the symptom is how projects die of infrastructure. Earn each component.
The bare loop
Model + two tools + a 10-turn cap + print every message. Nothing else. Get one real task end-to-end today.
WHEN: day one. Always start here — even if you'll adopt a framework later, this teaches you to read it.Verification
One deterministic check wired back into the loop — tests, a schema validator, a reconciliation. Exit only on evidence.
WHEN: the first time it says "done" and it isn't.Gates
Allowlist + approval step + budget caps + an audit log.
WHEN: the first tool with side effects beyond a sandbox. Non-negotiable timing.The eval
Ten golden tasks, graded, multiple runs, kept forever. Your license to change things.
WHEN: before your first "improvement" — not after your first regression.Context machinery
Compaction, output budgets on tools, a memory file.
WHEN: sessions pass ~20 turns, or the agent starts forgetting its own work.Patterns
Pipeline stages, a router, or sub-agents — whichever the task shape demands (Module 08).
WHEN: one loop in one window measurably can't hold the job.Operations
Versioned prompts and configs, stored traces, eval-in-CI, cost dashboards. The harness becomes a maintained system.
WHEN: anyone besides you depends on it.Knowledge check
Ten questions, one per load-bearing idea. If you can answer these cold, you can teach this material — each explanation is a line you can reuse in front of a room.
Glossary
- Agent
- A model run in a loop with tools and feedback, pursuing a goal across multiple turns rather than answering once.
- Harness
- All the software around the model: loop, tools, context plumbing, gates, verification, evals. The subject of this manual.
- Agent loop
- The cycle of assemble context → infer → gate → execute tools → feed results back, until a verified exit or a stop condition.
- Tool / tool call
- A function you expose to the model plus the structured request it emits to invoke it. The model requests; your code executes.
- Tool schema
- The name, description, and parameter spec the model reads to choose and fill a tool call. Functions as part of the prompt.
- MCP
- Model Context Protocol — the open standard (2024) for exposing tools/data to any compliant harness. Turned tool wiring into an ecosystem.
- System prompt
- The harness's standing instructions: identity, environment, tool guidance, policies, procedure. Configuration written in prose.
- Context window
- The finite token budget of everything the model can see in one inference — its entire perceived universe.
- Compaction
- Summarizing older history into a brief to reclaim window space while preserving decisions. Lossy — test the loss.
- Context rot
- Quality degradation as the window fills: the model attends less reliably to buried material well before the hard limit.
- Sub-agent
- A worker spawned with a fresh context to absorb a context-heavy subtask, returning only a distilled report.
- Memory file
- A plain file (e.g. NOTES.md) the agent reads at start and appends decisions to — cheap persistence across sessions.
- Gate
- A per-action permission decision in code: auto, notify, approve, or forbid — keyed on reversibility and scope.
- Sandbox
- An isolated, disposable environment where autonomous action is safe by construction. The cheapest safety you can buy.
- Verifier
- Any check the harness runs on outputs: tests, validators, policy rules, an LLM judge, sampled humans. Exit on evidence, not self-report.
- Generator–verifier gap
- Tasks where checking is far cheaper than doing are the tasks agents excel at. Explains why coding matured first.
- LLM-as-judge
- A second model grading outputs against a written rubric. Powerful for fuzzy qualities; needs its own eval before you trust it.
- Golden set
- Your saved real tasks with known-good outcomes — the regression suite for the whole harness.
- Trace
- The full transcript of a run: every message, tool call, result, gate decision. The primary debugging artifact of the field.
- Prompt injection
- Untrusted content (webpage, email, file) steering the agent because it shares the channel with trusted instructions.
- Orchestrator
- A lead agent that decomposes work, briefs sub-agents, and merges their reports (pattern P4).
- Stop condition
- Harness-owned limits — turns, tokens, dollars, wall clock, no-progress — that end a run no matter what the model wants.
The Agent Harness Kit
This manual teaches how the machine works. The other two thirds put your hands on it — same voice, same doctrine, zero filler:
Single HTML file · self-contained · all instruments run locally in this page
Fonts load from Google Fonts when online; system fallbacks offline. Built to be taught from — project it, fork it, hand it out.