$ cat
Harness, Loop, Graph
Most agent systems don’t fail because the model is weak. They fail because the agent finished a four-hour task and nobody can say what it changed.
The tools return inconsistent shapes. State vanishes between runs. The agent retries and learns nothing from the last attempt. The work branches in ways nobody can inspect after the fact. Then the postmortem says the model wasn’t good enough, and someone books a meeting about upgrading it.
Wrong diagnosis. There are three engineering layers around a model, and almost every production failure sits squarely in one of them.
- The harness gives the model somewhere to work.
- The loop gives the work a way to prove itself.
- The graph gives the process an explicit route.
They overlap in code. In a small system all three live in one file, which is why they feel interchangeable. They aren’t. Each one fails in its own way, and the fix for one is useless against the other two.
Harness
The harness is everything that would still be on your architecture diagram if you deleted the model.
A model turns input into output. It cannot hold project state, run a test suite, read a file safely, respect a permission, or resume tomorrow where it stopped tonight. Every one of those is something you build.
What’s actually in one:
Context — system instructions, retrieved knowledge, task policies, the standing operating procedures the agent shouldn’t have to be told twice.
Action surface — the tools. APIs, shell, browser, database, MCP servers, specialist agents. This is the part people get wrong by adding to it.
Persistence — files, checkpoints, session state, progress logs, git history. Anything that has to survive a context window ending.
Execution control — timeouts, retry ceilings, token and cost budgets, model routing, handoffs, approval gates.
Safety — isolated environments, least-privilege permissions, allow lists, secret handling, the human authorisation step for anything irreversible.
Observability — traces, tool inputs and outputs, state transitions, cost, latency, and whether the run did anything at all.
Harness work becomes unavoidable the moment a task outlives one context window. An agent working for hours can’t rely on conversation history, because the conversation is going to end. It needs artifacts a fresh session can pick up cold: a file that says what’s done and what remains, commits that preserve working states, checkpoints before anything risky.
That isn’t a better prompt. It’s a better place to work.
Loop
Every tool-using agent already has a small internal cycle: think, call a tool, read the result, continue. That’s the runtime, and you didn’t design it.
Loop engineering starts when you deliberately build the cycle around that. The agent produces something. Something checks it. The failure comes back as a usable signal. It tries again under a rule that says when to stop.
The check can be mechanical — tests pass, schema validates, links resolve, numbers reconcile, the build compiles. Or it needs judgment — the argument is complete, the tone fits, the evidence supports the claim, the change is scoped right. Either way the rule is the same:
Loop on evidence, not on confidence. “The agent says it’s done” is a claim. “The tests pass, the sources resolve, and a reviewer that never saw the author’s reasoning approved the diff” is evidence.
A production loop needs six things, and skipping any one of them is how loops turn into cost leaks:
- Trigger — what starts a cycle. A request, a schedule, a webhook, a failed test, a new document.
- Goal — a state you can test for. Not “keep improving.”
- State — what the next attempt needs to know without replaying everything that came before.
- Evidence — what actually proves the goal was met.
- Feedback — a short, specific account of what failed. This is the part that makes the retry worth paying for. A retry against a boolean is a slower way to fail.
- Stopping rule — success, attempt ceiling, budget exhausted, timeout, or escalation to a human.
Loops stack. The agent loop does the work. A verification loop checks the work. An event loop wakes the system when new work arrives. An improvement loop reads production traces and changes the harness itself.
This is the difference between a loop and a prompt. A prompt decides what happens during one model call. A loop decides what happens after it.
Every retry, grader, and reviewer costs latency and money. Add a loop when failing costs more than checking.
Graph
The graph answers a different question. Not how should the agent work but what is allowed to run next.
Work becomes nodes. Permitted transitions become edges. State moves through it. That gets you fixed sequences, conditional branches, parallel fan-out, joins, bounded cycles, recovery paths, and human interrupts — all inspectable, because they’re declared rather than emergent.
What you’re actually deciding when you build one:
Node boundaries — which work is plain code, which is a model call, which is a specialist agent, which is a human.
State schema — what each node may read and write, and how parallel results merge without clobbering each other.
Routing — which evidence moves work forward, back, sideways, or into escalation.
Concurrency — what runs in parallel, what has to wait at a join.
Cycles and exits — where retries are legal, how many, and what makes a cycle guaranteed to terminate.
Durability — where execution checkpoints, and how it resumes after a crash.
A graph earns its complexity when the process has real branches, parallel specialists, approval steps, recovery routes, or stateful handoffs between different kinds of worker. It does not earn it merely by having several steps. If one capable agent with three tools can do the job, a graph adds structure and no value.
The expensive version of this mistake: formalising the workflow before anyone has watched the work happen. You get a clean diagram that encodes assumptions nobody tested. Run a simple harness first, read the traces, then formalise the paths that turned out to be stable.
The table that matters
| Symptom | Layer | What to fix |
|---|---|---|
| Loses progress between sessions | Harness | Durable state, not longer context |
| Can’t reproduce a failure | Harness | Traces of tool inputs and outputs |
| Picks the wrong tool constantly | Harness | Fewer, narrower, better-documented tools |
| Says it’s done when it isn’t | Loop | An evidence check that isn’t the model’s opinion |
| Retries the same wrong thing | Loop | Feedback with the specific error, not a boolean |
| Runs up cost with nothing to show | Loop | A stopping rule and a budget ceiling |
| Steps run out of order | Graph | Declared transitions |
| Parallel work overwrites itself | Graph | A state schema with merge rules |
| No path for a failed step | Graph | An explicit recovery route |
| Irreversible action fired unreviewed | Harness | An approval gate before the action |
Find the layer that owns the symptom. Fix that layer.
How they nest
Take something ordinary: an agent that drains a queue of bug reports and opens a pull request for each one.
The harness is what it works in. A checked-out repo in an isolated worktree, so a bad run can’t touch main. The ability to run the test suite and read what failed. Git, so each attempt leaves a diff rather than a description of a diff. A file recording which issues are done, because this will outlive any single context window. Permission to open a draft PR and no permission to merge one.
The loop lives inside one issue. Write a failing test, change the code, run the suite. If it fails, the specific error goes back in — not “that didn’t work.” Stop on a passing suite, on the fourth attempt, or on a budget ceiling, whichever comes first. And the check that makes it honest: confirm the test fails without the fix, so a test that asserts nothing can’t pass for free.
The graph is the route between issues. Triage, then fix, then review in a context that never saw the fixing agent’s reasoning, then either open the PR or route back with the reviewer’s objection. Three failed attempts exits to a human instead of looping. Ten issues can fan out in parallel because each one owns its own worktree, which is a harness fact the graph is allowed to depend on.
Now look at what nests. The graph runs inside the harness. The loops run inside single nodes of the graph. And the loop’s stopping rule is only meaningful because the harness can run tests and the graph declared where an exhausted attempt goes.
Take away the worktrees and the parallel fan-out stops being safe. Take away the test runner and the loop has no evidence, so it terminates on the model’s opinion. Take away the declared escalation and a stuck issue silently consumes the budget for every other one.
Same system, three different ways to break it.
The four expensive mistakes
Building the graph first. Forty nodes drawn from an imagined process before anyone watched a strong agent attempt the work. Trace first, formalise second.
Letting the maker grade itself. Self-review shares every blind spot with the original attempt. Use a mechanical check where one exists, a reviewer in a separate context where it doesn’t, and a human for anything you can’t undo.
Defining the loop as “keep trying.” An unbounded retry isn’t reliability. Every cycle needs fresh evidence, an attempt ceiling, and a named escalation.
Treating the harness as a warehouse. Every tool you add makes selection harder. Every extra permission widens the blast radius. Give the agent the smallest environment that can finish the job.
The checklist
Harness. Are the tools narrow, documented, and observable? Is state durable across sessions? Are permissions least-privilege? Can an operator pause, inspect, and resume a run? Can you reconstruct any important action from traces?
Loop. What evidence proves success? What feedback goes back after a failure? How many retries are allowed? What happens when the budget runs out? Where is a human required?
Graph. Which paths must be deterministic? What can run in parallel? What state is shared? Where are the joins, approvals, and recovery routes? Which cycles are legal and how do they terminate?
Operations. Are cost and latency monitored? Is failure rate visible per node and per tool? Is human intervention measured? Do you know the task-level success rate in production, as opposed to the eval score?
None of the three replaces the others. A perfect graph won’t save an agent that loses its state. A perfect harness still burns money if the loop has no evidence and no stopping rule. A strong loop becomes hard to operate once branches, parallel work, and approvals are buried in ad hoc code.
The useful thing isn’t the vocabulary. It’s that the next time something breaks you have three places to look before you blame the model — and the model is usually the most expensive of the four things to change.