System Design · step by step

Design an Agent Harness

Step 1 / 9
The numbers to beatno shelldesigned tools onlyone workspaceper taskscoped credsnever production

In the interview room

How you’d open this design in an interview

Before any boxes: agree what it must do, pin the qualities that shape everything, then build — naming each trade-off as you make it. The walkthrough above is that exact order.

Functional requirements

What it must do — agree on these before drawing a single box.

  • Decompose: turn a request into units small enough that success is machine-checkable.
  • Constrain: a narrow tool surface — the agent can only do what a tool lets it do.
  • Sandbox: execute in an isolated workspace with a bounded blast radius and no production credentials.
  • Verify: a gate the agent cannot edit, cannot skip, and does not grade itself against.
  • Review: a human queue sized by risk, not by volume — cheap to approve, expensive to miss.
  • Record: a ledger of every action, input, tool call and diff, because someone will ask.

Non-functional requirements

The qualities that shape the whole design — each one names the mechanism that buys it.

Success is checkable without a human
Tasks decomposed until each has a machine-verifiable acceptance condition — a failing test that must pass, a schema that must validate, an eval that must clear.
An agent cannot do damage it was not given
Capability comes only from tools. A narrow, explicitly designed tool surface with no shell escape hatch and no production credentials.
A bad run is cheap
Isolated workspace per task — its own worktree, its own container, its own ephemeral credentials — discarded on failure with nothing to clean up.
The agent’s claim is never the evidence
Verification runs outside the agent’s reach: tests, type checks, lint, evals and build, on a runner the agent cannot configure or bypass.
Human attention spent where it matters
A review queue routed by blast radius — auto-merge the reversible and well-covered, require approval for schema, auth, money and anything touching a customer environment.
Answerable six months later
A ledger recording prompt, model version, tool calls, diffs, verification results and the approving human, retained like any other production audit trail.

The trade-offs you say out loud

Senior signal isn’t the boxes — it’s naming what you gave up and why it was the right price.

Decomposing until success is machine-checkableover giving the agent the whole feature

An agent handed an unverifiable task produces confident, plausible work that a human must read line by line — which costs more than writing it. The unit of work in a harness is not "a feature", it is "the largest chunk whose success a machine can confirm".

A narrow tool surfaceover shell access

A shell is every capability at once, which makes the blast radius unbounded and the audit trail unreadable. Designed tools are slower to build and are the only version where you can state what the agent can and cannot do — which is also what a security review asks.

Verification the agent cannot reachover asking the agent whether it succeeded

A model asked to grade its own work reports success at a rate uncorrelated with actual success, and the failures it misses are the subtle ones. If the agent can edit the test, the test measures nothing — this is the single most important boundary in the whole design.

Routing review by blast radiusover reviewing everything equally

Reviewing every diff makes the harness slower than doing the work manually, and reviewing nothing puts an unsupervised agent on the schema. Risk-routing is what makes supervision economics work: cheap changes flow, expensive ones stop.

One workspace per taskover a shared checkout

Parallel agents on one working tree corrupt each other in ways that look like model failure and are not. Isolation costs setup time per task and buys deterministic, discardable failure — which is the property that lets you run many agents at once.

What this teaches

Learn system design by building the harness engineers use to supervise agents doing delivery work. An interactive guide covering task decomposition into verifiable units, a narrow tool surface, sandboxed execution with a bounded blast radius, a verification gate the agent cannot bypass, a human review queue sized by risk, repo-grounded context, and the ledger that makes agent work auditable.

Key takeaways

  • The bottleneck moved from generation to verification — design for that, not for prompting.
  • Capability comes only from tools: a narrow designed surface, never a shell.
  • One ephemeral workspace per task makes failure cheap, which is what lets you run many agents.
  • Decompose until each unit has a machine-checkable acceptance condition, or refuse the task.
  • Verification must live outside the agent’s reach — if it can edit the check, there is no check.
  • Route review by blast radius; that ratio, not the model, sets how many agents one engineer can supervise.
  • Record prompt, model version, tool calls, diff and approver — agent work is production work.

Concepts covered

  • What is an agent harness?
  • An agent, a repo, a task
  • Tool surface and sandbox
  • Decompose until success is checkable
  • Verification the agent cannot reach
  • A review queue routed by risk
  • Context: code that belongs in this repo
  • The ledger

Design an Agent Harness (AI-Supervised Delivery) — read the full walkthrough as text

the same steps, decisions & trade-offs, for reading, reference & search

The big idea

What is an agent harness?

An engineer with a coding agent is faster at the task in front of them. An engineering organisation with agents and no harness is faster at producing work nobody has verified — and a growing pile of plausible diffs is not throughput.

Build the system around the agent: decompose requests into units whose success a machine can confirm, constrain capability to a designed tool surface, sandbox execution so failure is cheap, verify outside the agent’s reach, and route review by risk. The job moves from writing feature code to writing the system that writes it.

How to read this: We add one piece at a time, problem then fix, and the diagram grows. Hit Begin.

Step 1 · The skeleton

An agent, a repo, a task

The naive version: an engineer describes a change, an agent edits files, the engineer reads the diff. It works, and it does not scale — because the engineer is now the entire verification layer, and reading a plausible diff carefully is slower than writing it.

Stand up a Planner that hands tasks to an Agent and a human who supervises rather than authors. Everything that follows makes the agent’s output bounded, checkable, and cheap to be wrong.

The bottleneck moves to verification: Generation stopped being the constraint. What limits throughput now is how quickly you can establish that a change is correct — and a human reading diffs is the slowest possible answer.

Step 2 · Bound it

Tool surface and sandbox

Give an agent a shell and you have given it every capability at once: your credentials, your network, your production. The blast radius is unbounded, the audit trail is unreadable, and you cannot answer a security reviewer’s first question about what it can do.

Design decision: What is the strongest constraint on what an agent can do?

The call: A narrow tool surface with no shell, in an isolated workspace with scoped credentials. — Capability comes only from tools. If there is no tool to delete a bucket, the agent cannot delete a bucket — regardless of what it decides, or what a document it reads tells it to do.

Give the agent a designed Tool Surface — read, write, test, search, open a pull request — with no general shell, and run every task in its own Sandbox: an ephemeral worktree and container with scoped credentials, discarded on failure.

Isolation is what makes failure cheap: A bad run in a throwaway workspace costs nothing and needs no cleanup. That property — not model quality — is what lets you run many agents in parallel without a bad afternoon becoming an incident.

Step 3 · The real work

Decompose until success is checkable

“Add multi-currency support” is a request an agent will happily attempt and nobody can verify without reading everything it wrote. The failure is not the model — it is handing it a task with no machine-checkable definition of done.

The Planner splits a Request into units small enough that each carries an explicit acceptance condition: a failing test that must pass, a schema that must validate, an eval that must clear. If it cannot produce one, the task goes back to a human.

The unit of work is "the largest verifiable chunk": Not a feature, not a file, not a story point. This reframing is most of what separates a working harness from an expensive way to generate diffs — and writing the acceptance condition is now the highest-value thing an engineer does.

Step 4 · The boundary

Verification the agent cannot reach

The agent reports that it fixed the bug and the tests pass. Both statements came from the same system that wrote the code — and if the agent can edit the test, the test measures nothing at all.

Design decision: The agent says its change passes all tests. What do you do with that claim?

The call: Re-run verification on a runner the agent cannot configure, skip or edit. — The agent’s report is a hint; the external run is the evidence. This boundary is the single most important line in the whole design, and it is the one most often relaxed for speed.

Run Verification outside the agent’s reach: tests, type checks, lint, build and evals on infrastructure it cannot configure or bypass. The agent’s own claim is never the evidence.

If the agent can edit the check, there is no check: Everything else in this design is a trade-off you can tune. This one is not — relaxing it converts the harness into an expensive random diff generator with a green tick.

Step 5 · Supervision economics

A review queue routed by risk

Review every diff and the harness is slower than doing the work by hand. Review none and an unsupervised agent is editing your schema. Both failure modes are common, and they are the same mistake: treating all changes as equally risky.

Route the Review Queue by blast radius. Auto-merge reversible, well-covered changes in low-risk areas. Require a named human for schema migrations, authentication, money, deletions, and anything touching a customer environment.

Risk-routing is what makes the economics work: The number of agents one engineer can supervise is set almost entirely by what fraction of changes can safely bypass a human — which is a property of your test coverage and your risk classification, not of the model.

Step 6 · Ground it

Context: code that belongs in this repo

Without repository context an agent writes plausible code in the wrong style, re-implements a helper that already exists, ignores a convention three teams depend on, and reintroduces a bug someone fixed deliberately last year.

Retrieve Repo Context per task: conventions, ownership, prior decisions, the relevant slice of the codebase, and the reasons behind them. Ground the agent in what already exists before it writes anything new.

Plausible is not the bar; consistent is: The reviewable difference between a harness that helps and one that generates work is almost entirely context quality. And the same retrieval discipline applies here as anywhere: content retrieved into the context window is data, never instruction.

Step 7 · Answerable

The ledger

Six months on, a customer asks why a behaviour changed, or an auditor asks who approved a change to a calculation. “An agent did it” is not an answer anyone accepts, and reconstructing it from git history alone is impossible.

Record every run in a Ledger: prompt, model version, retrieved context, every tool call, the diff, verification results, and the human who approved it. Retain it like any other production audit trail.

Agent work is production work: The moment agent output reaches a customer, it carries the same evidence requirements as anything else you ship — and the model and prompt versions are the two fields teams forget, which are exactly the two that explain why behaviour changed.

You did it

You just designed an agent harness.

  • The bottleneck moved from generation to verification — design for that, not for prompting.
  • Capability comes only from tools: a narrow designed surface, never a shell.
  • One ephemeral workspace per task makes failure cheap, which is what lets you run many agents.
  • Decompose until each unit has a machine-checkable acceptance condition, or refuse the task.
  • Verification must live outside the agent’s reach — if it can edit the check, there is no check.
  • Route review by blast radius; that ratio, not the model, sets how many agents one engineer can supervise.
  • Record prompt, model version, tool calls, diff and approver — agent work is production work.
built for the shift from writing feature code to writing the systems that write it — decompose, sandbox, verify, review.
Finished this one? 0 / 65 System Designs done

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.