“The loop is the small part. Call the model, run whatever tools it asked for, append the results, call it again, stop when it says it’s done or I hit a cap. That’s fifteen lines, every team’s version looks the same, and the Tool Runner or the Agent SDK will write it for me.
The harness is the loop plus everything that decides what the model sees, what it can touch and when it’s allowed to stop: the instructions and context it loads, the tools and permissions, the guardrails on risky calls, the checks that tell it whether it actually finished, the state it leaves for the next run, and the turn and budget limits.
That’s the part I engineer, because the model is the same for everybody and the harness is where the results come from. When an agent declares victory early, the fix is a test that decides ‘done’, not a better prompt. When it forgets conventions, it’s standing instructions. Each piece answers a failure I’ve actually seen.
And I don’t hand-write the loop just to get control — approval gates, result rewriting and run limits are already hooks in the SDKs.”
The deep dive — diagrams, tradeoff tables, and the follow-up trap
The loop sits inside the harness
Same model, same fifteen lines for every team. What differs is the boundary around them.
The loop is fifteen lines; the harness around it is where the results come from
Build each part from a failure you have seen
Add a part when the failure shows up, not before, and re-test them all when you change models. The last column names where each part lives in the Agent SDK and Claude Code.
Failure
Part
Lives in
Declares “done” early
Feedback: tests decide done
a Stop hook that runs the suite; a feature list that starts failing
Forgets the house rules
Context: rules loaded every session
CLAUDE.md, loaded every session, kept short
Runs something dangerous
Access rules, gates
deny rules, can_use_tool / PreToolUse, a sandbox
Drowns in its own context
Context: isolation
a subagent for side work; server-side compaction
Redoes work after a restart
State
progress file and a git commit per session; a run ledger
Spins or overspends
Limits
max_turns and a dollar cap per run
REAL SYSTEM
Illustrative example: a team’s coding agent on Opus 5.5 finished 58 of 120 tasks on its internal eval (48%). Swapping the model for Fable 5.1 — 2.5× the price per token — took it to 65 (54%). Keeping Opus 5.5 and adding two harness parts instead, a Stop hook that runs the tests and a progress file each session starts from, took it to 85 (71%). The loop code did not change in either experiment.
FOLLOW-UP TRAP
“So to engineer the harness you write your own loop?” — No. The Tool Runner and the Agent SDK give you the loop and still let you own the harness: can_use_tool and PreToolUse for approvals, PostToolUse to rewrite a result, max_turns and max_budget_usd for limits; Managed Agents adds hosting. Hand-write the loop only for control flow the hooks cannot express.