Vibe Engines
YouTube

Vibe Engines is free, interactive AI engineering & system design — runs in your browser. Pick a learning path

System Design

Design an Agent Harness

Step 1 / 9

Learn system design by building the harness engineers use to supervise agents doing delivery work.

The numbers to beatno shelldesigned tools onlyone workspaceper taskscoped credsnever production

The whole design, in writing

Every step of the build above, written out: the problem each piece solves, the option that was taken and the ones that were not, the numbers, and how it fails in production.

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.

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.

EngineerAgent
New in this step: Engineer, Agent. · swipe to pan the diagram

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.

Why this piece earns its place

A run needs an owner the moment it can fail in more than one way, and the planner is the only component positioned to be it. An agent that cannot succeed does not stop — it keeps calling tools, re-reading the same file, and spending tokens on a task that was impossible the day it was written. So every run carries a step and token budget, and that budget belongs to the task, not to the config: a typo fix and a wide refactor cannot share a ceiling without one of them being wrong. Budget exhaustion also needs to be its own terminal state, distinct from failed verification, because the follow-ups differ — one says the unit was decomposed badly, the other says the change was wrong. This is also the only component that knows how many runs are in flight, so the ceiling on concurrent agents sits here, along with the decision to re-dispatch a spent unit rather than let the agent retry inside its own loop, where a second attempt is indistinguishable from the first. Skip all of it while you are one engineer with one agent; you are the lifecycle. Once there are queues, retries and abandoned runs, that policy exists whether or not anyone designed it, and undesigned it lives in slightly different copies inside every caller.

What the new pieces do

Engineerclient
No longer writing every line — specifying, reviewing the diffs that matter, and improving the harness when a class of failure repeats. The job moves from producing code to producing the system that produces it.
Agentservice
The model in a loop: read context, call a tool, observe, repeat. Capable exactly to the extent the tool surface allows, and no further.

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.

Agentplans · edits · runsTool Surfacenarrow · designedSandboxisolated workspace
New in this step: Tool Surface, Sandbox.

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

  1. A prompt is guidance, not a control. It fails under an unusual input, an injected instruction in a file it reads, or a long enough loop — and none of those are edge cases in practice.

  2. A real control and the wrong layer. By then the agent has already run whatever it ran; the diff shows you the code it wrote, not the requests it made or the data it touched.

  3. 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.

Why this piece earns its place

A tool’s output is model input, so tool design is context design. A search tool that returns every match in a large repository does not fail — it quietly evicts the agent’s earlier reasoning from the window, and the run degrades into re-deriving what it already knew. So every tool returns a bounded page, and truncation has to be visible: the tool states how much it withheld, because an agent handed a silent subset concludes the thing does not exist and writes a second copy of it. Error text is the same story in reverse, since it is the agent’s only feedback channel — a tool that fails with permission denied produces a retry loop, while one that names the missing capability produces a correction. Budget the sandbox too: a cold container plus a dependency install can cost more wall-clock than the agent’s own work, so the start-up is worth engineering — pre-built images, dependencies baked in, containers made ready before a task arrives. Warm has to mean ready, never reused: a pooled workspace is still handed to exactly one task and destroyed with it, and sharing one across tasks buys a few seconds and rebuilds the corruption this step exists to prevent. A broader surface is defensible for read-only agents, where nothing they do is durable.

  • no shelldesigned tools only
  • one workspaceper task
  • scoped credsnever production

What the new pieces do

Tool Surfaceservice
Read file, write file, run tests, search the repo, open a pull request. Explicitly designed, individually logged, and deliberately without a general shell — capability is granted, never assumed.
Sandboxservice
One ephemeral workspace per task — its own worktree, its own container, its own scoped credentials — discarded on failure. Makes a bad run cost nothing and lets many agents run at once.

Back of the envelope

designed tool surface
capability is granted, not assumed
ephemeral workspace per task
discardable failure
scoped, short-lived credentials
no production access
every tool call logged
with arguments and result size

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.

Requestticket · customer askPlannerdecomposes to units
New in this step: Request, Planner.

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.

Why this piece earns its place

Two forces set the size of a unit and only one of them is obvious. The ceiling is verifiability. The floor is fixed cost: every unit pays for a fresh workspace, a context retrieval and a full verification run, so decomposing past that point spends more on overhead than on the work, and starves each unit of the surrounding code that made the change coherent in the first place. Units are also not independent, and the dependency graph is what teams discover late. If one unit needs an interface another has not built yet, you either sequence them and lose the parallelism that justified the harness, or you fix the contract up front and let both run against it — decide that while you are decomposing, not while you are merging. Then decide the harder one: what happens when five units pass and two do not. If units merge independently, a half-built feature is now on the main branch behind nothing, so the merge target and the flag are chosen at the same moment the units are written.

  • acceptance conditionper unit
  • no condition→ back to a human
  • tests firstthen the agent

What the new pieces do

Requestclient
A bug report, a customer request, a backlog item. Almost never specified well enough for an agent — turning it into verifiable units is the harness’s real work.
Plannerbackend
Splits a request into tasks small enough that success is machine-checkable, each with an explicit acceptance condition. If it cannot produce one, the task goes back to a human rather than forward to an agent.

Back of the envelope

each unit has a machine-checkable done
test, schema or eval
unverifiable tasks are refused
not attempted
the spec is the deliverable
the engineer’s highest-value output

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.

Agentplans · edits · runsVerificationagent cannot reach
New in this step: Verification.

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

  1. The claim and the code come from the same source. A model asked whether it succeeded reports success at a rate uncorrelated with actual success, and it is the subtle failures it misses.

  2. 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.

  3. Useful as an extra signal and not a substitute — two models sharing a failure mode agree with each other confidently. A deterministic check is not a matter of opinion.

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.

Why this piece earns its place

Where verification runs is settled. What it measures is not, and that is the half that bites. An agent optimises against whatever the gate checks, so a thin suite does not merely fail to catch bad work — it steers the agent toward work that satisfies a thin suite, again and again in the same module, which from the outside reads as the model being weak in that area. The gate is a specification whether or not anyone wrote it as one. Flakiness also changes character. A human re-runs a flaky test and shrugs; an agent takes the red as ground truth and starts repairing code that was already correct, or retries until it goes green and merges something that never worked. Quarantining flakes stops being hygiene and becomes a prerequisite. And verification latency sets the agent’s iteration rate, so a slow suite does not just delay a merge — it caps how many corrections the agent gets to make before its budget is spent. The fix belongs on the runner rather than in the loop: shard the suite, order it so the checks nearest the diff report first, and stream that first red back early. The feedback arrives sooner, and the thing selecting and executing the checks is still something the agent cannot touch.

  • external runneragent cannot configure
  • deterministicnot a second opinion
  • claim ≠ evidencealways re-run

What the new pieces do

Verificationservice
Tests, type checks, lint, build and evals, executed on a runner the agent cannot configure, skip or edit. The agent’s own report of success is never the evidence.

Back of the envelope

verification outside the agent’s reach
the one hard boundary
tests, types, lint, build, evals
all of them, every run
self-report treated as a hint
never as proof

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.

EngineerRequestPlannerAgentTool SurfaceSandboxVerificationReview Queue
New in this step: Review Queue. · swipe to pan the diagram

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.

Why this piece earns its place

Routing by risk makes the queue survivable; the next failure is the reviewer. Reviewing a colleague’s pull request works because you shared the design conversation that preceded it. With an agent diff there is no prior, so a change that arrives as code alone forces the reviewer to reconstruct intent from the implementation — the slow path this whole system exists to avoid. Send the evidence with it: the acceptance condition the unit was given, the verification output, the context it was grounded in. The second-order failure is the one no dashboard shows. Once the queue grows past what a person can genuinely read, the approval rate drifts toward everything while throughput, latency and merge rate all keep looking excellent. So watch the rejection rate, per reviewer: someone who never rejects is either being handed only safe work or has stopped reading, and those two need different repairs. In a pre-production repository with no customers you can skip most of this and lean on revert — the day customers arrive, that stops being true quietly.

  • auto-mergereversible + covered
  • named humanschema · auth · money
  • queue by risknot by volume

What the new pieces do

Review Queuecache
Routes by blast radius rather than by volume: reversible, well-covered changes auto-merge; schema, auth, money and anything touching a customer environment require a named human.

Back of the envelope

blast-radius classification per path
decides the route
auto-merge needs coverage evidence
not just green tests
customer-environment changes always reviewed
no exceptions

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.

Agentplans · edits · runsTool Surfacenarrow · designedReview Queuerouted by riskRepo Contextgrounded retrieval
New in this step: Repo Context.

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.

Why this piece earns its place

Written conventions are a second source of truth beside the code, and the two drift. When they do the agent follows the old rule confidently and produces something consistent enough to pass review, until someone who remembers says “we stopped doing that last year”. So treat prose as the fallback and move every convention that can be made executable into a lint rule, a type or a codemod — which moves it out of context, where it is a suggestion, and into verification, where it is enforced and cannot rot without failing loudly. The other constraint is budget. Retrieved context competes with the agent’s own working state for one window, so a generous retrieval leaves less room to reason and pushes the earliest instructions away from where the model attends. That makes context the first thing anyone trims when runs get expensive, usually without measuring what it was buying. Which is why the thin case has to be designed rather than discovered: an agent handed nothing relevant still writes code, and that run looks exactly like a good one until somebody reads it. A retrieval that comes back weak should push the task into the reviewed class or hand it back, on the principle that refuses an unverifiable unit: thin retrieval says this repository has not been described well enough for the change being asked of it.

  • conventionsretrieved per task
  • prior decisionsand their reasons
  • retrieved textis data, not instruction

What the new pieces do

Repo Contextdata
Conventions, ownership, prior decisions and the shape of the codebase — retrieved per task. The difference between an agent that writes plausible code and one that writes code that belongs in this repository.

Back of the envelope

task-scoped retrieval
not the whole repository
decisions and their rationale
so the agent does not undo them
retrieved content delimited
injection is a live risk in a repo

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.

Agentplans · edits · runsVerificationagent cannot reachReview Queuerouted by riskLedgerevery action recorded
New in this step: Ledger.

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.

Why this piece earns its place

The audit case gets the ledger funded; the second use is what makes it worth the storage. Every run with its verification result is a labelled example — this task shape, this context, these tool calls, passed or failed — so the ledger turns the agent is bad at migrations from an anecdote into a query, and it is what tells you which tool to build next rather than guessing. Three practical notes. Write it as the run happens rather than at the end, because the records worth reading are the runs that looped, timed out or were cancelled, and none of those reaches a tidy final step. Keep the bodies out of the record: a read tool returns whole files and a long run returns many of them, so hold hashes and references and put the payloads in cheap object storage, or the ledger costs more to keep than the work it describes. And it inherits the access controls of the code it quotes — prompts, retrieved source and diffs together are a way to read a repository nobody granted you, so this is not a log everyone can grep. Underneath all of it: the harness writes the record, never the agent. A history the agent supplies has exactly the standing of its own report of success.

  • model + prompt versionper run
  • every tool callrecorded
  • approvernamed

What the new pieces do

Ledgerdata
Prompt, model version, every tool call, the diff, verification results and the approving human. Retained like any other production audit trail, because someone will eventually ask what the agent did on the 14th.

Back of the envelope

full run record
prompt, context, tools, diff, result
model and prompt versions
the fields that explain behaviour change
retained to policy
this is an audit trail

You did it

You just designed an agent harness.

EngineerRequestPlannerAgentTool SurfaceSandboxVerificationReview QueueRepo ContextLedger
The finished design, end to end. · swipe to pan the diagram

Everything you assembled, in order

  • 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.

Where an interviewer pokes next

Getting the boxes right is the easy half. These are the questions that separate a candidate who drew the diagram from one who has run the thing. Answer each one out loud before you open it.

  1. Why is the unit of work "the largest verifiable chunk" rather than a feature?

    Because an agent handed an unverifiable task produces work that a human must read line by line to trust, and reading a plausible diff carefully is slower than writing the code. Once each unit carries an explicit machine-checkable acceptance condition — a failing test that must pass, a schema that must validate, an eval that must clear — the harness can confirm success without human attention, and human attention becomes the scarce resource you spend deliberately. This reframes what an engineer does: the highest-value output is no longer the implementation, it is the specification and the acceptance condition. It also gives you a clean refusal rule. If the planner cannot state how success would be checked, the task goes back to a human rather than forward to an agent, which prevents the most expensive failure mode — plausible work on an unbounded problem.

  2. Why is a narrow tool surface stronger than a careful system prompt?

    Because a prompt is guidance and a tool surface is a control. Prompts fail under unusual inputs, long loops, and — critically — instructions embedded in content the agent reads, which in a code repository is a live risk rather than a theoretical one. A tool surface fails only if you built the tool. If there is no tool that deletes a bucket, no amount of persuasion produces a deleted bucket. It also makes the system explicable: a security reviewer asking what the agent can do gets an enumerated list rather than an assurance. The cost is real — designing tools is slower than granting shell access, and each one needs a name, a schema, a description and a log line — but it is the only version where the blast radius is a statement of fact.

  3. Why can the agent never verify its own work?

    Two reasons, and the second is the fatal one. First, a model asked whether it succeeded reports success at a rate uncorrelated with actual success — and the cases it gets wrong are the subtle ones, which are also the ones a human skimming a diff misses. Second, and structurally: if the agent can reach the verification layer, it can change it. Editing a test so it passes, weakening an assertion, or skipping a suite are all reasonable-looking actions for a system optimising to complete a task, and any of them silently converts your gate into a green tick with no meaning behind it. So verification runs on infrastructure the agent cannot configure, skip or edit, and the agent’s report is treated as a hint that tells you where to look. Every other trade-off in this design can be tuned for speed; this one cannot.

  4. How do you decide what an agent may merge without a human?

    By blast radius, not by size or confidence. The route is a property of what the change touches: reversible edits in well-covered, low-risk areas can auto-merge on green verification, while schema migrations, authentication and authorisation, anything involving money, deletions, and anything touching a customer environment always require a named human approver. The classification lives with the paths, gets reviewed like any other config, and is deliberately conservative at the start. This ratio is also the whole supervision economics: how many agents one engineer can oversee is set almost entirely by what fraction of changes can safely bypass review, which is a function of your test coverage and your risk classification rather than of the model. Improving coverage in a high-traffic area is therefore a direct throughput investment.

  5. What changes when this harness runs at a customer rather than internally?

    Three things get stricter. The tool surface must run with the requesting user’s permissions rather than a service account holding everyone’s access, or a read tool becomes an exfiltration path. The sandbox must sit inside the customer’s boundary — in a no-egress environment that means mirrored registries, vendored dependencies and a model that can run without reaching the internet at all. And the ledger stops being an internal nicety: it becomes evidence a security reviewer will ask to see, with retention set by the customer’s policy rather than your default. The review routing also changes shape, because "touches a customer environment" is no longer a special case at the edge of the classification — it is most of what the harness does, so the auto-merge fraction is smaller and the economics are correspondingly different.

Check yourself — the answers, and why

Eight steps in, these are the calls you should be able to make cold. Pick one, then read why.

  1. In an agent harness, the unit of work should be…

    An unverifiable task produces plausible work a human must read line by line — slower than writing it.

  2. The strongest constraint on what an agent can do is…

    Capability comes only from tools. No tool, no capability — regardless of what the model decides.

  3. The agent reports that all tests pass. That claim is…

    If the agent can run or edit the check, the check measures nothing. This boundary is not negotiable.

  4. A review queue should be routed by…

    Reversible and well-covered can auto-merge; schema, auth, money and customer environments cannot.

  5. One ephemeral workspace per task exists mainly to…

    Shared checkouts corrupt each other in ways that look like model failure; isolation makes a bad run free.

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.

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.

The qualities that shape everything

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-checkable over 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 surface over 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 reach over 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 radius over 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 task over 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.

The answer, out loud

What a strong answer to “Design an Agent Harness (AI-Supervised Delivery)” sounds like, first question to last trade-off. It is about 7 minutes of talking; the whiteboard and the interviewer fill the rest of the 45. Read it aloud once, then close the page and give it yourself.

  1. 0–3 min

    What this system is actually for

    Before I draw anything I want to be clear about the problem, because it is not “make the agent better”. One engineer with a coding agent is already faster at the task in front of them. What does not scale is an organisation of them: generation stopped being the constraint, and what limits throughput now is how quickly you can establish that a change is correct. A human reading a plausible diff carefully is the slowest possible answer to that. So I would design for verification, not for prompting.

  2. 3–8 min

    The skeleton, and where the human sits

    I would start with three pieces. A planner that turns a request into tasks, the agent itself — a model in a loop, reading context, calling a tool, observing — and an engineer who supervises rather than authors. I would keep the planner as its own component even while it is thin, because a run needs an owner: something that holds the budget, can cancel, and decides whether a unit that ran out of steps is dispatched again or stops there. The engineer’s job here is specifying work and improving the harness when a class of failure repeats, not reading every line.

    Built in step 1: An agent, a repo, a task
  3. 8–14 min

    Bound it before anything else

    Next I would bound what the agent can do, with tools rather than with a prompt. A prompt is guidance; a tool surface is a control. The agent is exactly as capable as the tools I wrote, and neither its own reasoning nor an instruction sitting in a file it reads can widen that. In a repository the second one is a live risk, not a theoretical one. So: read, write, run tests, search, open a pull request, and no general shell, so a new capability is a piece of work rather than something it already had. Then every task runs in its own sandbox — an ephemeral worktree and container with scoped, short-lived credentials, discarded on failure. That isolation makes a bad run cost nothing, and cheap failure is what lets me run many agents at once.

    Built in step 2: Tool surface and sandbox
  4. 14–21 min

    Decompose until a machine can check it

    Now the part where harnesses actually fail. “Add multi-currency support” is a request an agent will happily attempt and nobody can verify without reading everything it wrote. So 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. The unit of work is not a feature or a file, it is the largest chunk whose success a machine can confirm. And the refusal is explicit: if the planner cannot say how success would be checked, the task goes back to a human. Writing that condition is now the highest-value thing an engineer does.

    Built in step 3: Decompose until success is checkable
  5. 21–27 min

    The one line I would not move

    Then the boundary everything else rests on. The agent reports that it fixed the bug and the tests pass, but both statements came from the same system, so they are one claim, not two: a system wrong about the change is wrong about its account of it in the same breath, and asking again adds nothing. Worse, structurally: if the agent can reach verification it can change it, and editing a test or skipping a suite are reasonable-looking moves for something optimising to finish a task. So tests, types, lint, build and evals run where the agent cannot configure, skip or edit them, and its own claim is a hint that tells me where to look. Every other trade-off here I would tune for speed. This one I would not.

    Built in step 4: Verification the agent cannot reach
  6. 27–33 min

    Spend review where being wrong is expensive

    With that in place the question is who looks at what. Reviewing every diff makes the harness slower than doing the work by hand; reviewing none puts an unsupervised agent on the schema. Both are the same mistake — treating every change as equally risky. So I would route the queue by blast radius: reversible, well-covered changes in low-risk areas auto-merge on green, while schema migrations, authentication, money, deletions and anything touching a customer environment need a named human. And I would be precise about “well covered”: the route reads the coverage of the code being changed, not just the colour of the run — otherwise auto-merge becomes the default for whatever nobody wrote tests for.

    Built in step 5: A review queue routed by risk
  7. 33–39 min

    Ground it, and write it all down

    Two pieces left. Context: without the repository an agent writes plausible code in the wrong style, re-implements a helper that already exists and undoes a convention three teams depend on. So I retrieve per task — conventions, ownership, prior decisions and the reasons behind them — and treat everything retrieved as data, never as instruction. Plausible is not the bar; consistent is. Then the ledger: prompt, model version, retrieved context, every tool call, the diff, the verification result and the approving human, retained like any other production audit trail. The moment agent output reaches a customer it carries the same evidence requirements as anything else we ship.

    Built in step 6: Context: code that belongs in this repo
  8. 39–45 min

    The trade-off, and what I would do next

    So, the trade-off I would name: every constraint here costs throughput today and buys the ability to run many agents tomorrow. Designed tools are slower to build than shell access, a workspace per task costs setup time, and external verification means running everything twice. You are paying all of it to make being wrong cheap, and if you do not pay it the harness is an expensive way to generate diffs with a green tick on them. With more time I would go two places. Cost per task: a run has a real price, and I want the signal that a unit is not worth dispatching before the budget is spent, not after. And model changes: replay recorded tasks against a new model version and compare outcomes, so an upgrade is a measurement rather than a week of reading the mood of the room.

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
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
NextIncidents, On-Call & SLAs for FDEs Next in “Become a Forward Deployed Engineer” · step 47 of 63

Explore the topic

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

More System Designs