Skip to main content

HarnessChapter 06

Building a Harness

The previous five chapters describe a loop you mostly should not write. Claude Code and the managed already implement the agent loop, context economics, compaction, result curation, and prompt architecture — tuned, hardened, and maintained by people whose job is exactly that. Building your own is justified only when you need control those harnesses do not expose. This chapter is about where that line is.

What the Agent SDK Gives You

The Claude Agent SDK is the same Claude Code runs, exposed as a library. You get the loop, tool dispatch, compaction, and the system- stack — and you supply the parts that are yours:

import { query } from "@anthropic-ai/claude-agent-sdk";
 
const result = query({
  prompt: "Triage the failing CI run and open a fix PR",
  options: {
    systemPrompt: { type: "preset", preset: "claude_code" }, // keep the tuned preamble
    allowedTools: ["Read", "Edit", "Bash", "mcp__github"],
    permissionMode: "acceptEdits",
    maxTurns: 25,                 // your stop condition, not the model's
  },
});
 
for await (const msg of result) {
  // your dispatch, logging, cost accounting, side effects
}

The point of the preset system prompt is the lesson of System Prompt Architecture made concrete: keep the harness preamble you did not write, append the layers you control, and do not reimplement what is already tuned.

When Building Pays Off

Build a custom harness whenUse the managed harness when
You need a bespoke stop condition or cost ceiling per runDefault turn/cost controls are enough
The loop must embed in another runtime (a service, a CI job, a queue worker)You are working in a terminal or IDE
You need custom dispatch — your own tool execution, sandboxing, audit logBuilt-in tools plus MCP cover your tools
You are orchestrating agent teams with non-standard coordinationSubagents cover your delegation
You need the loop itself observable and replayableThe session UI is sufficient observability

If none of the left column applies, building your own loop is undifferentiated work that you will maintain forever and that Anthropic will out-improve on every release.

The Parts You Own

Even with the SDK doing the loop, three responsibilities are irreducibly yours, and skipping any one is the common failure of hand-built harnesses:

  • Stop conditions the model cannot see. Turn caps, wall-clock budgets, cost ceilings. The SDK gives the hooks; the policy is yours. A loop without an owner-imposed ceiling is a runaway by default.
  • A Safety Net. Custom dispatch means custom blast radius. Sandbox the tools, gate destructive actions, log every side effect — the managed harness does this for you; your harness does not until you build it.
  • Scaffolding before autonomy. Stand the loop up with logging, replay, and a kill switch before you let it run unattended. This is Scaffold First at the infrastructure layer: the observability is not a follow-up, it is the precondition.

Anatomy of One Owned Run

Scroll through a single iteration of a hand-built loop. The SDK owns the model call; everything highlighted is code you wrote — and code you now maintain.

  1. 01

    Assemble the request

    The SDK builds the model request from your system-prompt preset and tool definitions. Your only job here is configuration — but a misconfigured preset or tool schema is your bug, surfacing 25 turns later as confused behavior.

  2. 02

    Enforce your stop policy

    Before dispatching, your loop checks the ceilings the model cannot see: turns elapsed, wall-clock spent, dollars burned. The SDK hands you the turn; whether to take it is your policy. This is the line between a finite run and a runaway.

  3. 03

    Dispatch through your safety net

    Each tool call runs through your dispatch layer — sandboxed, gated on destructive actions, with every side effect logged. Custom dispatch means custom blast radius. The managed harness did this for you; yours does not until you build it.

  4. 04

    Account, then loop or stop

    You append results, tally cost and latency, and emit a replayable record of what happened. Only then does control return to the loop. The observability is not a follow-up — it is the precondition for ever letting this run unattended.

The Tradeoff

A custom harness buys total control and costs you the entire surface area this section describes — forever, across every model version, including the bugs. The managed harness costs you control at the edges and gives you a loop that gets better while you sleep. The honest default is: use the managed harness, reach for the SDK at the first concrete requirement it cannot meet, and even then keep the preset preamble. Most "we need our own agent infrastructure" decisions are the Checkpoint Loop lesson unlearned — solving for imagined generality instead of the next verified step. Build the harness when the requirement is real and named. Not before.