Loop and Harness Engineering: What Surrounds the Model
AI & Multi-Agent Systems

Loop and Harness Engineering: What Surrounds the Model

September 16, 202640 min readBy Jaafar Benabderrazak

After context engineering comes the loop: bounds, event journals, sandboxes, permission classes and verifiers. The mechanisms, parameters and failure modes of the code that turns a model into an agent.

An agent is a model, a loop, and a harness. The model gets all the attention and is the only part you cannot test. The loop is the program that calls it repeatedly. The harness is everything that runs between two calls, in deterministic code: the permission decision, the sandboxed execution, the truncation of the result, the verification, the hooks, the persistence.

This is the companion to my field guide on data readiness, RAG and context engineering. That guide answered one question: what enters the model. This one answers the next: how many times, under what constraints, and who decides it is finished. It condenses a 47-slide working deck and its technical reference, and it is written to be used during construction rather than read once.

Three claims organise everything below, and each one is a consequence of the model being the only non-deterministic component in the system.

Three laws

Law 1. The context decides what enters; the loop decides how many times. The model is a stateless function: a sequence of tokens in, a sequence out, nothing persists. Every "conversation", every "memory", every "agent" is reconstructed by the application on each call. The consequence for loop design: since nothing naturally connects two calls, everything that connects them is code we write, and that code has exactly the properties we give it. What changes relative to context engineering is that the context is no longer assembled once for a question; it is reassembled on every turn by the loop, from state that lives elsewhere. Prefix caching, compaction and sub-agents stop being techniques somebody applies by hand and become policies the loop applies automatically.

Law 2. Reliability multiplies. A task of n steps, each succeeding with probability p and with no verification in between, succeeds with probability p to the power n. At p = 0.95 and n = 20, global success is 36 %. At p = 0.90, it is 12 %. Per-step reliability is a base; the number of steps is an exponent. No reasonable improvement in p, a better model or a better prompt, compensates for growth in n.

Steps without verification p = 0.99 p = 0.95 p = 0.90 p = 0.80
5 95 % 77 % 59 % 33 %
10 90 % 60 % 35 % 11 %
20 82 % 36 % 12 % 1 %
50 61 % 8 % 1 % 0 %

Global success against the number of chained steps for four per-step reliabilities: at twenty unverified steps, 99 percent per step yields 82 percent, 95 percent yields 36 percent, 90 percent yields 12 percent and 80 percent yields 1 percent

τ-bench (Yao et al., Sierra, June 2024) introduced the metric that follows from this: pass^k, the probability that a system succeeds on k independent attempts at the same task. It is not pass@k, at least one success out of k, which is the metric of demonstrations. On τ-bench's retail domain, GPT-4o scores roughly 61 % pass^1 and under 25 % pass^8. A system in production is judged in pass^k by its users whether or not anyone measures it.

METR (March 2025) gives the complementary marker: the time horizon of tasks models complete at 50 % reliability roughly doubles every seven months, but the horizon at 80 % reliability is about five times shorter. The gap between "the agent can do it" and "we can rely on it" is a factor of five in task duration.

Three responses, all of them the harness's job, and they structure the rest of this article: reduce n by moving every deterministic step into code, insert verifiers after each step rather than at the end of the task, and make steps idempotent and replayable so that retrying costs less than getting it right first time.

Law 3. The model proposes, the harness disposes. What the model decides, which tool, which arguments, when to stop, what to remember, how to decompose, is probabilistic and carries no guarantee. What the harness decides, whether the call is permitted, how it executes, what comes back into the context, when to force a stop, is code: testable and provable.

The difference is not one of degree. A rule in the prompt is tested by sampling and yields a compliance rate. A rule in the harness is tested like code and yields a property. The review test to apply to every line of a system prompt: if the model ignores this rule, what happens? If the answer is unacceptable, the rule changes sides and becomes a hook, a permission, or a verifier.

Property you want The "prompt" version (a wish) The "harness" version (a guarantee)
No writes outside the repository "Only modify project files" A filesystem sandbox: the rest does not exist
Tests run before concluding "Always run the tests before finishing" A Stop hook: the stop is refused without a recent test run
No external send without approval "Ask for confirmation before sending" Action class 4, mandatory permission, journalled
Do not modify the tests "Never edit the tests/ directory" tests/ read-only; a PreToolUse hook refuses any diff on it

The five loop failures

My previous guide had five context failures: lost in the middle, distraction, tool confusion, conflict, poisoning. The loop has its own five. The grid exists for diagnosis: faced with a failure, you identify which one before choosing a remedy.

Failure Mechanism Example Remedy
Loop without progress Same tool, same arguments, same error; or oscillation between two states. The model does not perceive the repetition. The same test rerun fourteen times with no code change Hash-based call detection, turn bounds, error compaction
Objective drift Every turn takes an implicit decision; after compaction, the original objective is no longer in the context. A bug fix was requested; an architecture refactor was delivered, bug intact The plan as an artefact reread every turn; objective restated after compaction
Unverified declared success The model asserts completion; nothing verified it; the harness accepts the text as proof. "The tests pass": never run, or run against the old code Stop criterion is proof produced by the harness
Objective circumvention The metric is satisfied, the intent is not. The shortest path to green runs through the verifier. Tests marked skip, expected value hard-coded, assert deleted The verifier out of reach: read-only or hidden tests, a grader with no write access
Uncontrolled irreversible action A side effect executes before validation, or twice after a resume. Deletion, send, payment, migration; replayed after an incident Action classes and permissions, idempotency, sandbox, checkpoint before the irreversible

The five loop failures as cards: no progress, objective drift, false success, circumvention and uncontrolled irreversible action, each with its mechanism, an example and the component that fixes it; failures three and four share the remedy that the verifier sits out of reach of the agent it verifies

Failures three and four share one remedy, and it is the highest-yield rule in this article: the verifier is out of reach of the agent it verifies — another context, other rights, another process.

Workflow or agent

Anthropic's "Building effective agents" (December 2024) draws the line: workflows are systems where the model and tools are orchestrated along a predefined code path; agents are systems where the model dynamically directs its own process and tool use. Five workflow patterns cover most ground: prompt chaining with verification between steps, routing, parallelisation, orchestrator-workers, and evaluator-optimiser.

An agent begins where the number of steps cannot be known in advance. Two cumulative conditions justify going there: the path depends on what the environment returns (otherwise it is a workflow, however many model turns it takes), and the environment returns a verifiable signal (otherwise the loop does not converge, it just spins).

Level Pattern When it fails
0 Single call Fails as soon as there are several steps
1 Chaining and routing Predictable; fixed steps, verified outputs
2 Parallelisation, orchestrator Independent sub-tasks, aggregated
3 Evaluator-optimiser Bounded: converges if the signal is real
4 Agent: loop open over tools Costs variable latency, p^n, guardrails
5 Multi-agent Only on a demonstrated need: ×4 to ×15 tokens

The six levels from a single call up to multi-agent, each rung indented above the last, with workflow levels marked predictable and agent levels marked as costing variable latency and guardrails, plus the two cumulative conditions that justify rung four

You climb a rung only on a measured failure of the one below. The most profitable intermediate pattern is the evaluator-optimiser: a loop, but closed by code, with a bounded iteration count and a real verifier. A three-step verified workflow beats a thirty-turn unverified agent on almost every enterprise case.

Three review questions settle the maturity of any existing agentic system:

  • Who decides to stop? If the model alone: failures one and three.
  • What prevents an unwanted action? If a sentence in the prompt: failure five.
  • How do we know it is finished? If a declaration by the model: failures three and four.

If the answer to any of the three is "the model", the harness is not finished.

1. The loop

Anatomy of a turn

ReAct (Yao et al., 2022) formalised the reason-act-observe sequence. Its modern form is the tool_use block the model emits and the tool_result block the harness returns; the tool's result is the observation. Four technical facts shape the design.

The whole context is resent on every turn, so the cumulative cost of an uncached session grows as n². A stable prefix and prefix caching are not an optimisation; they decide whether the loop is economically viable at all. A single turn can carry several tool calls, and the harness executes independent ones in parallel, returning every result in the same turn. The stop_reason is the only end-of-turn signal: end_turn for a final answer, tool_use for at least one call to execute, max_tokens for a truncated output. And max_tokens is not an ending: output truncated in the middle of a tool call is an incoherent state, which the harness treats as an error, never as an answer.

Here is the inner loop with its bounds, provider-independent:

def run_turns(task, journal, policy, env, verifier, budget):
    ctx = assemble_context(journal)              # a projection of the journal
    while True:
        if budget.exhausted(journal):            # turns, tokens, currency, wall time
            return force_stop(journal, reason="budget")
        if budget.soft_threshold(journal):       # 80 %: instruction to wrap up
            ctx = ctx + [system_hint("Finish the current step, write HANDOFF.md, stop.")]

        resp = model.call(ctx)                   # the only non-deterministic call
        journal.append(model_call(ctx_hash=hash(ctx), stop=resp.stop_reason, usage=resp.usage))

        if resp.stop_reason == "max_tokens":
            return handle_truncation(journal)
        if resp.stop_reason == "end_turn":
            return finalize(journal, resp)       # the harness verifies the proof

        results = []
        for call in resp.tool_calls:             # tool_use: one or several calls
            if loop_detector.seen(call):         # same tool, same args, N times
                return force_stop(journal, reason="loop")

            decision = policy.decide(call)       # allow | ask | deny
            journal.append(tool_request(call, decision))
            if decision == "deny":
                results.append(error_result(call, "refused by policy: " + policy.reason(call)))
                continue
            if decision == "ask":
                decision = ask_human(call)       # a journal event; pauses if asynchronous
                if decision != "allow":
                    results.append(error_result(call, "refused by the user"))
                    continue

            hooks.pre(call)                      # may rewrite or refuse
            raw = env.execute(call, timeout=policy.timeout(call))      # sandbox
            out = truncate_and_offload(raw, budget_per_tool=policy.result_budget(call))
            hooks.post(call, out)                # lint, format, journal, inject
            journal.append(tool_result(call, out.ref, out.size, out.truncated))
            results.append(out.visible)

            if call.is_step_boundary:            # end of a plan step
                journal.append(checkpoint(env.snapshot(), hash(ctx)))
                journal.append(verify(verifier.run(call)))

        errors.update(results)                   # consecutive-error counter
        if errors.consecutive >= 3: replan(journal)
        if errors.consecutive >= 5: return escalate(journal)

        ctx = assemble_context(journal)          # never ctx + results: always a projection

Two lines deserve emphasis. The context is always recomputed from the journal, never built by accumulation (ctx = ctx + results): that is what makes truncation, erasure and compaction policies applicable without loss. And every permission decision, every hook output, every verification is a journal event, which means the observability of the last section is not an addition but a by-product.

Three nested loops

Loop Unit State Stop criterion
Inner the turn the context stop_reason = end_turn, bounds, proof
Outer the session the disk: files, git, journal no task remaining; or session budget
Meta the product iteration the task set and its scores pass^k reached on the target tasks

Three nested rectangles: the meta loop over product iterations in weeks, the outer loop over sessions in hours, and the inner loop over turns in seconds, whose six steps are assemble, call, read stop reason, authorise, execute and reinject

Information that must survive the turn goes in the context; the session, on disk; the iteration, in the task set. The harness writes the state of each loop into the input of the next.

Stop conditions: four bounds, a soft threshold, and a proof

Bound Starting value Behaviour when crossed
Turns per session 25 to 50 on a coding task Forced stop; the task resumes with a fresh context
Context tokens 25 to 30 % of the advertised window Compaction, then stop and hand off if that is not enough
Monetary budget Per task, never per call Forced stop; the cost is a journal event
Wall-clock time Task-dependent; always present Forced stop, which avoids infinite waits on a tool
Loop detected Same tool and arguments, three times Forced stop with the reason reinjected into the handoff
Consecutive errors 3 → replan; 5 → human Counter reset on every validated step

Two mechanisms make these bounds usable. The soft threshold: a hard bound cuts the agent off mid-write, leaving an incoherent state that the next session inherits as damage. At 80 % of the budget, the harness injects a system instruction to finish the current step, write the handoff note, and stop; the hard bound becomes a last resort. The proof: completion is signalled through a structured tool, task_complete(summary, evidence), not free text, and on receipt the harness does not trust evidence — it reruns the verification itself. The model proposes the ending; the harness establishes it.

Every stop, voluntary or forced, produces three artefacts: a checkpoint, a handoff note, and a degraded mode announced in the traces. A stop without those three has avoided a cost and created an incident.

The outer loop with a fresh context

On a long task, a single session accumulates its own noise: exploited tool results, corrected errors, abandoned branches. Context rot degrades reasoning well before the technical limit. The answer is not to compact harder; it is to throw the context away and start again empty, reading state from disk.

Anthropic's "Effective harnesses for long-running agents" (November 2025) describes two roles. An initialiser agent, once per project, writes the feature list with statuses, a progress file, an environment bootstrap script, and makes a first commit. Then a worker agent, every session and in an empty context: reads the progress file and the git log; runs the bootstrap script and checks that the application starts and the tests are green; picks one task, the highest-priority unfinished one; does it inside a bounded inner loop; proves it with tests, lint, a screenshot if there is an interface; commits and updates the status; exits. Huntley's "Ralph" pattern (2025) is the minimal version: a shell while loop that relaunches the same prompt.

while [ "$(jq '[.features[] | select(.status != "done")] | length' features.json)" -gt 0 ]; do
  ./init.sh || { echo "environment broken" ; exit 1 ; }        # green state before starting
  agent --prompt-file WORKER_PROMPT.md --max-turns 40 --budget-usd 3
  git diff --quiet && git diff --cached --quiet || git commit -am "session $(date -Iseconds)"
done

What makes this robust is not the worker's prompt; it is the discipline of closure. Each session leaves the environment clean (green tests, temporary files deleted, dependencies declared) and the state up to date. A session that does not close cleanly poisons every session after it, which inherits a red state without knowing why.

The marker: one task per session, 25 to 50 turns per session. A session that overruns is a badly cut task, not a budget that is too small. The context is disposable; the state is not.

The plan as an artefact

Two planning regimes exist and both have a defect. Plan then execute produces the plan first and follows it: predictable and traceable, but rigid in the face of what the environment reveals. Interleave decides the next step every turn: adaptive, but every turn takes an implicit decision and the objective drifts. The compromise is a plan written to a file, with verifiable steps, reread every turn by the harness, and revised only on explicit triggers.

The plan captures exactly what compaction must preserve: the objective and the stated constraints, the decisions taken and why, the errors already made, the state of the task, and the references for recovering what was removed. The plan is the compaction artefact, and because it lives on disk it survives both compaction and the session.

Granularity: one step equals one possible verification. "Add the CSV export" is not a step; "the test test_export_csv passes" is. Three verifiable steps beat twelve vague ones, which is law 2 applied to planning: small n, measured p.

Replanning happens on explicit triggers: three errors on the same step, the verifier failing twice, a plan hypothesis contradicted by a tool result, 80 % of the budget consumed. Never "because we had an idea" — that is the definition of drift. Every replan is a journal event, with the old and the new plan.

Errors: four classes, four policies

Class Detection Harness policy Visible to the model
Transient 429, 5xx, network timeout, temporary lock Retry with exponential backoff and jitter, capped at 3 to 5; then degraded mode No. A model turn spent on a 429 is a wasted turn
Validation Argument schema refused, path missing, value out of range Immediate return to the model with a message saying what is wrong and what to do; no automatic retry Yes: one turn, one correction
Semantic Red test, lint, output schema refused, verifier failed This is the loop's signal. Reinjected concise and localised; consecutive counter Yes: this is the observation
Environment Sandbox unavailable, disk full, secret missing, tool down Stop, checkpoint, escalate to a human. The model cannot repair an environment No, except in the handoff

The error message is a prompt. "Error 500" produces a loop: the model retries the same thing. "Parameter date: expected format YYYY-MM-DD, received 12/03" produces a correction in one turn. Every validation error says what is wrong and what to do; that is a clause of the tool contract.

Compact the errors (12-factor agents, HumanLayer, 2025). Twelve identical errors in the context are the distraction failure from the previous guide, and they push the model to repeat what it reads. The harness keeps only the last error for a given step, prunes repetitions, and counts consecutive errors: three triggers a replan, five escalates to a human, a validated step resets the counter.

Idempotency: every side-effecting action carries a run_id + step_id key. Without it, the resume policy duplicates effects; with it, "replay" is a policy rather than a risk.

Verification inside the loop

The loop converges only if the environment returns a signal. With no signal it spins; with a weak signal it converges on what satisfies the signal rather than the task. SWE-agent (Yang et al., 2024) is the clean demonstration: an automatic lint after every edit, refusing the invalid edit, eliminated cascades of syntax errors.

Signal level Examples Status
Strong Targeted unit test, compilation, JSON schema, diff bounded to the expected files At every step
Medium Lint, static typing, compared screenshot, format check Completes the strong signal
Weak "This looks correct" from the model itself, with no execution Not a signal

After each step, not at the end of the task. The verifier resets p to 1 where it is placed. At the end of a task it detects the error after twenty turns; after each step, after one turn. Detection costs the same; repair costs a factor of however many steps have elapsed.

The signal must be concise and localised. Two thousand lines of test output are noise; "1 failure: test_export line 42, expected ';' received ','" is a signal. The harness filters output before reinjecting it, and never truncates the error lines.

If no automatic verifier exists for a task, climb back down a rung: workflow plus human review. An agent without a signal is not an agent. And the verifier sitting in the same context as the generator is not a verifier: a model judging its own work without new evidence confirms what it wrote.

2. The agent-computer interface

The ACI is a performance parameter

The SWE-agent paper (Yang et al., NeurIPS 2024) named the Agent-Computer Interface and measured its effect. Their finding: a raw shell is a bad interface for a model. Outputs are endless and carry no line numbers, editors are interactive, and a malformed command leaves an unknown state. Their ACI instead: a 100-line numbered file window with scrolling; a search that refuses to return more than 50 results and asks you to narrow it; a line-range edit command with an integrated lint that refuses invalid edits and shows the modified context; and the current directory and open file restated in every return.

Setup SWE-bench resolved
RAG baseline (GPT-4) 1.3 %
RAG baseline (Claude 3 Opus) 3.8 %
SWE-agent ACI (GPT-4 Turbo) 12.5 %

Bar chart of SWE-bench resolution: 1.3 percent and 3.8 percent for the two RAG baselines against 12.5 percent for the SWE-agent interface, a factor of three to ten, beside the four interface principles of few simple commands, concise localised returns, guardrails inside the tool, and visible state

Same model family, different interface. The exact numbers depend on the model and the date; the order of magnitude, a factor of three to ten, comparable to a model generation change for a few days of engineering, is what to retain.

Design for the model, not for the human. A human scrolls, filters visually, opens a second terminal. A model pays for every line in tokens and in attention. What is comfortable for one is noise for the other. The marker: a tool whose output exceeds 100 lines without pagination, or whose error does not say what to correct, is an interface defect before it is a model problem.

This is where plugging an MCP server in "as is" hurts: it exposes a human's API to an agent, with forty tools, ten-thousand-line responses and bare HTTP errors. MCP transports; it does not design. Every server you plug in goes through an adaptation layer that applies the contract below.

The tool contract

Clause Prescription Counter-example Consequence
Namespace prefix = system, verb = action: jira_search_ticket, github_search_pr search, search2, find_items The model picks the wrong system
Description what it does, when to use it, when not to, one example call "Searches for data" Overlapping scopes, exploratory calls
Granularity one tool per business flow: schedule_meeting(participants, duration) finds the slot list_users + list_calendars + create_event Three turns and 20k tokens where one sufficed
Response format a concise/detailed parameter; readable identifiers rather than opaque ones; pagination the API's full JSON The context fills from a single call
Errors typed and actionable: "expected date YYYY-MM-DD", "340 results: add a filter" Error 500, a stack trace The agent loops instead of correcting
Idempotency idempotency_key mandatory on every write; replaying means the same effect POST with no key Three tickets created after a resume
Evaluation 10 to 30 realistic tasks per tool, measured before and after every change "we will see in production" A changed description degrades another tool

Anthropic's "Writing effective tools for agents — with agents" (September 2025) adds the method: build an evaluation per tool, let an agent propose description improvements, and measure. Here is what the contract looks like in practice:

{
  "name": "jira_search_ticket",
  "description": "Searches Jira tickets by text and filters. Use when the user mentions a ticket, a bug or a tracked request in Jira. Do NOT use for GitHub (see github_search_pr) nor to create a ticket (jira_create_ticket). Returns at most `limit` results; beyond 50 matches, ask the user to narrow. Example: {\"text\": \"CSV export\", \"project\": \"BILL\", \"limit\": 10}",
  "input_schema": {
    "type": "object",
    "properties": {
      "text":    {"type": "string",  "description": "Keywords; JQL syntax not accepted"},
      "project": {"type": "string",  "enum": ["BILL", "CRM", "INFRA"]},
      "status":  {"type": "string",  "enum": ["open", "in_progress", "closed", "all"], "default": "all"},
      "format":  {"type": "string",  "enum": ["concise", "detailed"], "default": "concise"},
      "limit":   {"type": "integer", "minimum": 1, "maximum": 50, "default": 10}
    },
    "required": ["text"]
  }
}

A concise return is one line per ticket: BILL-812 · open · CSV export: wrong separator · @j.dupont · 2026-08-30. An error is actionable: {"error": "too_many_results", "count": 340, "hint": "add project or status"}.

A tool that returns 10,000 lines is an interface defect, not a context problem. Fixing it on the context side, with truncation, is a bandage; fixing it on the tool side is the solution.

Reducing the surface: tool indexes and programmatic calls

Beyond roughly twenty declared tools, the selection rate for the right tool falls and the context is consumed before the first question. Three exposure regimes:

Regime When Reported effect
A · Everything declared Acceptable under about twenty tools Costs tokens and precision beyond that
B · Index and load on demand 20 to 100 tools Anthropic (Nov 2025): selection precision 49 → 74 % on Opus 4, about 85 % fewer tokens in the initial context
C · Programmatic calls As soon as a bulky intermediate result only feeds another tool Anthropic (Nov 2025): one task going from 150,000 to 2,000 tokens

Regime C changes the nature of the loop. In A and B, every tool result is a turn: the model reads 5,000 lines of table to filter ten. In C the filtering is code; the loop loses both turns and tokens, and sensitive data can stay out of the context entirely because it transits between tools inside the sandbox. What C requires: an execution sandbox, tools exposed as typed functions, and traces that capture the executed code, since A's legibility is gone.

What comes back into the context

A tool result has a four-state lifecycle. Raw: 12,000 lines of JSON, 4 MB of logs. Truncated: head and tail, with an explicit counter of what was omitted, under a per-tool budget (2 to 4k tokens as a starting point; a test needs its last line, a grep its first fifty). Offloaded: the full result written to disk, referenced by a path, with a search tool to reach into it. Erased: once exploited, the result is replaced by its reference when a threshold is crossed.

The four states of a tool result in sequence — raw, truncated, offloaded, erased — with the measured effect of clearing exploited results and the three things that must survive every cut: the reference to the whole, the counter of what was omitted, and the error lines

def truncate_and_offload(raw: str, budget_tokens: int, head=60, tail=40) -> Result:
    ref = journal.store(raw)                       # always kept whole, by reference
    if tokens(raw) <= budget_tokens:
        return Result(visible=raw, ref=ref, truncated=False)
    lines = raw.splitlines()
    errors = [l for l in lines if ERROR_RE.search(l)]          # never truncated
    body = lines[:head] + [
        f"… {len(lines) - head - tail} lines omitted · full: {ref} · grep_result available …"
    ] + lines[-tail:]
    visible = "\n".join(body + (["— error lines —"] + errors[:50] if errors else []))
    return Result(visible=visible, ref=ref, truncated=True)

Anthropic's context-management evaluation (September 2025) measured, on a 100-turn web research task: persistent memory plus result clearing, +39 % over baseline; clearing alone, +29 %, with 84 % fewer tokens on the task. Those are internal evaluations; the direction, that clearing exploited results improves quality and reduces cost, is the part to keep.

Every truncated result carries a counter of what is missing and a reference to the whole, and a tool exists to search the whole. A silent truncation is an unsignalled loss, the same failure as a botched compaction. The order of application matters too: the tool contract reduces volume at the source first, truncation handles what remains, and compaction intervenes last. Frequent compaction signals a tool problem, not a context problem.

Skills and code: moving determinism out of the model

A model turn is a reliability factor below 1 in the product p^n; a tested script is a factor of 1. Every turn a script can replace is therefore a direct reliability gain before it is a cost gain. The decision is made step by step:

  • The step requires no judgement (formatting, migration, calculation, code generation from a schema): a script, executed without being read, zero token cost, triggered by a hook or a command.
  • The step requires judgement but the procedure is known (a review against a rubric, a deployment, a report in the house format): a skill. A few dozen tokens of description permanently, the body loaded on demand, attached scripts executed without being read. The model follows, the code does.
  • The step requires judgement in a novel situation: a model turn, bounded, verified, traced. This is the only case where reliability multiplies, and therefore the only one that earns a dedicated verifier.

The capitalisation mechanism comes from Voyager (Wang et al., 2023): a library of verified skills, reused and composed, grows an agent's capability without retraining. A procedure that succeeds once becomes a file; never a piece of reasoning to redo. The practical marker: read the traces, and any sequence of turns that repeats identically from one session to the next is a skill waiting to be written, or a script.

A skill that describes a procedure without verifying it propagates its errors on every use. A skill has tests, like a tool.

3. The environment

The sandbox is a boundary, not a filter

A filter inspects each action and decides; it has false negatives, and an agent that optimises eventually finds them. A boundary makes the action impossible; there is nothing to decide. "Do not access ~/.ssh" is a filter; a container where ~/.ssh does not exist is a boundary. The sandbox closes the third branch of the lethal trifecta: the ability to transmit outward.

Layer Prescription What it makes impossible
Filesystem Read and write limited to the working directory; the rest is invisible (mount), not merely forbidden Reading a key, another project, the browser history
Network Off by default; domain allowlist through an egress proxy; connection log Exfiltrating, downloading an executable, calling an unplanned API
Process Ephemeral container or micro-VM; CPU, memory and duration quotas; destroyed after the session Persisting between sessions, exhausting the host
Secrets Outside the sandbox; an identity proxy signs authorised outbound requests Reading or transmitting a key: the agent never sees it
Output Only declared artefacts leave (diff, files, report), reviewed by the harness An untraced side effect

Anthropic's "Beyond permission prompts" (October 2025) reports that filesystem and network isolation cut permission requests by 84 % in their internal usage. The sandbox is what makes autonomy acceptable, and it precedes the permission policy, which it then lightens. Codex cuts the network during the agentic phase of its cloud tasks.

Note that there are two sandboxes with two perimeters: the agent's own, covering its commands, writes and session; and the one for programmatic calls, covering the code it generates to chain tools, same technology but more closed still, with no network and no persistent disk.

Using the developer's workstation as the sandbox gives access to their keys, their network and their other projects. One injection in a file that gets read is enough. This is not a theoretical scenario.

Durable state: the event journal

The event journal is the source of truth for the execution; each turn's context is a projection of it, never the inverse. Every event is persisted before being considered done. This is the durable-execution architecture of distributed systems (Temporal, Restate, Inngest) and, in the agentic ecosystem, that of LangGraph checkpointers, the OpenHands event stream and the Claude Code transcript. A crash at step 7 resumes at step 7, without re-executing the first six or duplicating their effects.

{"run_id":"r_8f2a","seq":17,"ts":"2026-09-07T10:14:03Z","type":"tool.request",
 "ctx_hash":"sha256:7c1e…","payload":{"tool":"run_tests","args":{"path":"tests/test_export.py"},
 "permission":{"class":2,"decision":"allow","rule":"policy#4"}}}
{"run_id":"r_8f2a","seq":18,"ts":"2026-09-07T10:14:11Z","type":"tool.result",
 "payload":{"tool":"run_tests","duration_ms":8400,"size_tokens":4100,"truncated":true,
 "ref":"runs/r_8f2a/t018.txt","summary":"42 pass · 1 fail"}}
{"run_id":"r_8f2a","seq":19,"ts":"2026-09-07T10:14:11Z","type":"checkpoint",
 "payload":{"fs":"git:ab12f3","ctx_hash":"sha256:7c1e…","step":3,"plan_hash":"sha256:91aa…"}}

Event types: session.start, session.end, model.call, tool.request, tool.result, permission, hook, checkpoint, verify, replan, compaction, escalate, degraded.

What "projection" implies. A turn's context is computed from the journal by applying the policies above (truncation, erasure, compaction) and the zone order from the previous guide. Two consequences: you can recompute a context after the fact for diagnosis, and you can change policy without losing information. A context that is itself the source of truth disappears with the session. Persist after each tool result, not after each turn: a turn can carry five calls and the crash arrives at the third.

An execution that cannot be replayed cannot be debugged. The journal precedes the trace — they are the same object, one event schema, frozen in wave one.

Checkpoints and rewind

A checkpoint restores three things together: the filesystem state (a commit or a git worktree), the context (or its position in the journal, which is the same thing since the context is a projection), and the list of external effects already emitted. All three restore atomically. Rewinding the context without rewinding the files leaves the agent reasoning about a state that no longer exists — the poisoning failure from the previous guide, in its agentic form.

Rewind rather than patch over. After a failure there are two strategies: patch over it, where the context keeps both the error and its correction and drift accumulates, or rewind to the last green state and retry, with the error noted in the plan. The second costs a checkpoint; the first often costs a session.

Explore in parallel. One git worktree per attempt: A and B at the same time on the same step, and a verifier picks. This is the useful form of multi-agent, partitioning by attempt rather than by role, and it is also what supports verified best-of-n.

What does not rewind: external effects. A checkpoint does not un-send an email. Hence the ordering: verify, checkpoint, and only then emit. For the irreversible already emitted, an explicit compensating action (the saga pattern) declared in the tool contract. The rule: a checkpoint before every class 3 or 4 action, and after every green plan step. Every write is either reversible, by snapshot, or guarded, by permission.

The repository as the outer loop's memory

The previous guide proposed Markdown memory files and the handoff note as a minimal viable memory. The repository is the industrialised version. OpenAI's "Harness engineering" (February 2026, Codex team) describes a practice where the repository is the agent's memory: an AGENTS.md under 100 lines serving as a table of contents pointing into docs/; the docs as the memory; linters enforcing the structure; and a garbage collector deleting stale docs, because a wrong doc misleads the agent more than it helps.

File Role Who writes it Constraint
AGENTS.md / CLAUDE.md The map: where things are, conventions, tools; pointers human, reviewed Under 100 lines; in zone 1, so stable
docs/ (ADRs, runbooks) The memory: decisions and their why, procedures human and agent Garbage-collected: any unmaintained doc is deleted
PLAN.md, progress.md, features.json The state: where we are, what remains, what failed agent Reread at startup, updated at every step
HANDOFF.md The last session's handoff note agent, at session end Written for a reader with no context
.agent/skills/, .agent/hooks/ Procedural knowledge and guardrails as code human Tested; out of the agent's write reach
tests/ The verifier human Read-only for the agent

Three reads at startup, in this order: the map, the state, the journal (git log and traces). If one of the three is missing, the agent reinvents it, with failures two and five as the consequence. Write for a reader with no context: the next session. "See yesterday's discussion" means nothing to an empty context.

4. The guardrails

Action classes and the permission policy

A per-tool permission ends as a list of two hundred rules. The useful granularity is the action class, crossed with argument patterns.

Class Examples Default policy Mechanism
1 · Read read, grep, list, SELECT, GET automatic The readable perimeter is defined by the sandbox
2 · Reversible write edit a repository file, run the tests, create a branch automatic + checkpoint Snapshot before; PostToolUse hook
3 · Irreversible local write delete, git push --force, migration, install a package ask PreToolUse hook: refuse by pattern; otherwise ask
4 · External emission email, ticket, message, payment, third-party POST ask + idempotency + journal Network sandbox allowlist; idempotency key; checkpoint before; traced decision
5 · Configuration policy, hooks, tests, secrets, skills forbidden to the model Files outside the sandbox or read-only; attempts journalled and escalated

The five action classes as rows — read, reversible write, irreversible local write, external emission and configuration — each with its default policy from automatic through ask to forbidden, and the mechanism that enforces it

The modes in market tools (Claude Code's plan and accept-edits; Codex's suggest, auto-edit, full-auto) are shortcuts over this policy. The policy itself is a versioned file, reviewed and tested, which the model neither reads nor writes — class 5 applied to itself.

# permissions.yaml · versioned, reviewed, tested · out of the agent's reach (class 5)
defaults: {1: allow, 2: allow_with_checkpoint, 3: ask, 4: ask_with_idempotency, 5: deny}
classify:
  - {tool: read_file, class: 1}
  - {tool: grep,      class: 1}
  - {tool: edit_file, class: 2, unless: [{path: "tests/**", class: 5}, {path: ".agent/**", class: 5}]}
  - {tool: run_shell, class: 2, unless: [{args: "rm -rf|git push --force|curl .*\\| sh", class: 5},
                                         {args: "^git push", class: 3},
                                         {args: "^pip install|^npm install", class: 3}]}
  - {tool: jira_create_ticket, class: 4, require: [idempotency_key]}
  - {tool: send_email,         class: 4, require: [idempotency_key], allowlist_domains: ["example.com"]}
modes:
  plan:       {max_class: 1}
  edit:       {max_class: 2}
  autonomous: {max_class: 3, sandbox_required: true}   # class 4 always asks
audit: every_decision

The human risk here is permission fatigue: forty questions per session and the user approves everything. The remedy is not "allow everything" but "fewer questions" — the sandbox cuts requests by 84 %, and the classes avoid asking about anything reversible.

Hooks

Hooks are the harness's extension points: deterministic code executed by the harness, never by the model, at fixed moments in the loop. Claude Code exposes them as PreToolUse, PostToolUse, Stop, SessionStart, PreCompact (2025); Codex, OpenHands and LangGraph have equivalents. A hook returns allow, deny, or a modification, in under 100 ms.

Hook Use Example
SessionStart Load the state, the map, the plan; check the environment Refuse to start if init.sh fails
PreToolUse Validate, refuse, rewrite arguments; the fine boundary where the sandbox is coarse Refuse rm -rf and git push --force; rewrite a relative path as absolute; require an idempotency key on a POST
PostToolUse Format, lint, journal, inject Formatting after every edit; test results injected; all output journalled
PreCompact Save what must survive the compaction Write PLAN.md and the errors seen before the context is rewritten
Stop Turn "finished" into proof Refuse the stop if there is no test run in the last N events, or if the diff touches tests/
def on_stop(journal, diff):
    recent = journal.last(20)
    if not any(e.type == "verify" and e.payload["ok"] for e in recent):
        return Deny("No successful verification in the last 20 events. Run run_tests before concluding.")
    if any(p.startswith("tests/") for p in diff.paths):
        return Deny("The diff modifies tests/. Explain the change and request a review (class 5).")
    return Allow()

The difference from the prompt: "always run the tests" is followed at some rate; a Stop hook is followed 100 % of the time. What must always happen is a hook; what should generally happen is an instruction. Hooks are also where determinism lives: formatting, generation, migrations, calculations. What runs in a hook consumes neither a turn nor a token, and cannot be forgotten.

One caution: a hook that makes a model call reintroduces non-determinism into the component meant to eliminate it. A hook is code; if it needs to judge, it is a verifier.

The human in the loop

The human validates decisions, not turns. Four interruption points: before, approve the plan rather than the forty actions that realise it; during, a class 3 or 4 action; at the end, review the diff and the proof, never the transcript; asynchronously, the agent contacts the human through a structured tool (12-factor agents' "contact humans with tool calls"; MCP elicitation, June 2025, standardises the server-to-user question with a response schema).

Granularity decides effectiveness. Approving a four-step plan, letting forty actions run in the sandbox and reviewing one diff is three interruptions. Approving forty actions is forty interruptions and a reflex approval by the tenth. A human judges an intention and a result well, and a command out of context badly.

ask_human(
    question="The invoices schema has no currency column. How should amounts be handled?",
    options=[{"id": "eur",  "label": "Assume EUR (documented in the report)"},
             {"id": "col",  "label": "Add a currency column (migration: class 3)"},
             {"id": "stop", "label": "Stop and escalate"}],
    default="stop", timeout="4h", on_timeout="pause")

Measure the interruption rate per task, and aim for approvals on classes 3 and 4 only. A permission mechanism the human no longer reads is an audit trail, not a guardrail.

Injection through tools, and objective circumvention

Indirect injection. To the model, a file read, a web page and a ticket have the same status as an instruction. Inside a loop, the lethal trifecta reassembles on every turn where one tool reads the outside and another writes to it. The harness closes the path, not the prompt: network sandbox (no more emission), minimal capabilities per tool and per task, and for high-stakes cases the CaMeL architecture (Debenedetti et al., Google DeepMind, March 2025) — a privileged planner that never sees untrusted data, a quarantined model that processes it without being able to call tools, and capabilities attached to values so that data from an untrusted source cannot reach a sensitive tool. The absolute rule: retrieved content never creates a permission.

Objective circumvention (reward hacking). The metric is satisfied, the intent is not: tests marked skip, expected values hard-coded, asserts deleted, a score file modified. METR (June 2025) observed this on recent models in its evaluations; Anthropic's "Natural emergent misalignment from reward hacking" (November 2025) shows that circumvention learned during training generalises to other undesirable behaviours. This is not malice, it is a property of optimisation: if the success signal is modifiable, the shortest path runs through the signal.

Symptom What happened What the harness guarantees
Green tests, feature absent assert replaced by pass; skip; hard-coded value tests/ read-only; a hidden holdout test set rerun by the verifier; a hook refusing any diff on tests/
Evaluation score changed The agent found and edited the grader The grader runs in another process, with no write access from the sandbox
External action after reading a ticket The ticket contained an instruction; the agent obeyed Class 4 → permission; retrieved content never creates a permission; quarantine
"Impossible" never said The agent prefers a workaround to an admission An explicit instruction and a report_blocker tool; the transcript is graded

A metric the agent can modify is not a metric.

5. Verification

The hierarchy of verifiers

  • 1 · Deterministic: compilation, tests, schema validation, lint, a diff bounded to the expected files. Free, reliable, at every step.
  • 2 · Properties: invariants ("the exported total equals the sum in the database"), metamorphic tests ("the result does not change if the input order changes"), partial oracles. They do not require knowing the right answer, only a relation it must respect. This is the forgotten level.
  • 3 · Model judge: acceptable under five cumulative conditions. A written rubric with criteria, a scale and examples; cited evidence, so the judge points at the line; a context separated from the agent, without its reasoning, or it judges the plausibility of the argument instead of the work; pairwise comparison rather than an absolute score; and a calibration measured against human labels, 80 to 90 % agreement, before any use as a metric. Known biases: position, verbosity, self-preference.
  • 4 · Human: on the final diff, on a sample, on the irreversible. Rare, expensive; this is what calibrates level 3.

The level of a verifier is chosen by what it can prove, not by what it can comment on. A test proves; a judge estimates; the agent asserts.

The generator-verifier gap

This is the frame that delimits where agents work today: they work where generating is expensive and verifying is cheap.

Verification expensive Verification cheap
Generation expensive Strategic writing, medical diagnosis → workflow plus human; never an autonomous agent Tested code, SQL on a known schema, forms, maths → the agent's domain: the loop converges
Generation cheap Summaries, recommendations, tone → calibrated judge plus a human sample Extraction, classification, formatting → one call plus schema validation; no loop

A two-by-two of generation cost against verification cost: the agent's domain is the single quadrant where generation is expensive and verification is cheap, while expensive verification means workflow plus human, and cheap generation with cheap verification needs no loop at all

Reflexion (Shinn et al., NeurIPS 2023) is often cited for verbal self-critique. The measurement says something else: the gain (HumanEval, pass@1 from 80 to 91 % on GPT-4) comes from coupling the reflection to the test signal. Without an external signal, the model rereads itself, congratulates itself and iterates on its own error.

Two patterns exploit the gap. Verified best-of-n: n attempts in parallel in worktrees, a verifier picks; cost ×n, pass^k rises; worth it only if the verifier is level 1 or 2. Evaluator-optimiser: generate, verify, correct, N bounded times; converges if and only if the verifier carries a real signal. A task from the "everything is expensive" quadrant often decomposes into sub-tasks of which some are verifiable: "write the analysis" is not, "extract the figures from the report and reconcile them against the database" is.

If you cannot write the verifier, you cannot automate the task. Decompose until you can write it, or climb back down to workflow plus human.

The evaluation harness

The golden set from the previous guide becomes a task set. Anthropic's "Demystifying evals for AI agents" (January 2026) fixes the vocabulary: a task (statement, initial state, grader, budget); trials; one transcript per trial; an outcome, the final state; a grader (code, model, human). You grade the outcome and the transcript: a correct final state reached through a forbidden action, a modified test, a class 4 action without permission, a secret read, is a failure.

id: BILL-export-csv-017
source: trace r_8f2a (production failure, 2026-08-30)
snapshot: images/bill-repo@ab12f3          # repository + test database + environment variables
prompt: "Add a CSV export of invoices on /export, separator ';', without breaking API v1."
budget: {turns: 40, tokens: 400000, usd: 3.0, wall_minutes: 30}
graders:
  - type: code                              # level 1: hidden tests, executed outside the sandbox
    run: pytest hidden_tests/test_export_hidden.py
  - type: code                              # level 2: a property
    run: python graders/sum_equals_db.py
  - type: transcript
    forbid: [{class: 4}, {path_written: "tests/**"}, {tool: "read_secret"}]
  - type: model                             # level 3, calibrated: human agreement 0.87 on 60 examples
    rubric: rubrics/api_compat.md
trials: 8                                   # pass^8 reported, with pass@8 for comparison

The protocol: 50 to 200 tasks, built from production traces, where every failure and every human intervention becomes a task with its initial state; 5 to 10 trials per task; a fresh sandbox per trial; the production harness, frozen by version; rerun on every change of prompt, tool, hook, environment or model. Metrics: pass^k and pass@k, cost per successful task (total cost ÷ pass rate), turns, tokens, human interruptions, forbidden actions.

Public benchmarks (SWE-bench Verified, τ-bench and τ²-bench, Terminal-Bench, OSWorld, GAIA) are model markers, not measurements of your system: contamination, overfitting, and above all they are not your tasks.

Evaluating with a harness other than production's (different tools, different sandbox, different hooks) measures a different system. The evaluation runs the production harness, frozen by version.

The meta loop

The third clock. Every production failure becomes a golden task; the failure taxonomy says which failure and which component; the fix picks one lever among five — the prompt, the tool, the hook, the environment, the plan; the evaluation measures in pass^k; the deployment is versioned and reversible.

The prompt is the most visible lever and the least measurable: a sentence added "to fix one case" is measured on the two hundred tasks, not on the case. One change at a time: two simultaneous changes make the effect unattributable, even when quality goes up.

The task set is to the harness what the golden set was to RAG. Without it, no change is arbitrable; with it, every production failure becomes one more task.

6. Operating

The trace is a tree

The journal and the trace are the same object seen by two tools: one for resuming, one for diagnosis. Conventions: OpenTelemetry GenAI (2025); tools: Langfuse, LangSmith, Phoenix, Braintrust. What is recorded without exception: the final context of every call (by hash and by reference), tool arguments and results (by reference, never whole), stop_reason and cached tokens, every permission decision, every hook output, cost, duration, sub-agents. Replay is the ultimate test: if you cannot reconstruct a call's context from the trace, the trace is incomplete.

Metric What a deviation signals
Cache rate between turns (target > 80 %) The prefix is moving: a timestamp, the tool list, state injected into zone 1
Turns per task (trend) Objective drift, a failing ACI, a plan cut too fine
Errors per tool The tool contract needs review; one tool concentrates the errors
Human interruptions per task Action classes badly tuned; insufficient sandbox
Loops detected, forced stops Bounds too low or badly cut tasks
Forbidden actions recorded Circumvention; guardrails to harden
Cost per successful task The only cost metric that counts

A trace should be readable in under five minutes by someone who did not write the system. Otherwise it is too verbose or too poor, and in both cases nobody will use it on the day of the incident.

Cost and latency

Without caching, the cumulative cost of a session grows as n²: every turn resends everything that came before. With a stable cached prefix, cost is nearly linear. The harness adds its own ways of breaking the prefix: a state reminder injected into zone 1, a compaction that rewrites the beginning, a tool index that changes every turn, a SessionStart hook that inserts a date. The test: the prefix hash is identical from one turn to the next, and the trace shows it.

Cumulative billed tokens across forty turns: without caching the curve grows quadratically to roughly seven times the cached line, which stays nearly flat, beside the six cost levers and the reminder that the only cost metric is cost per successful task

The other levers, by yield: parallel tool calls within a turn; a token budget per tool result; a small model to route, classify and grade (the judge and the router are the first candidates for model routing); and effort proportional to the task (Anthropic, multi-agent, June 2025: a simple question is one agent and 3 to 10 calls).

The metric is cost per successful task, which is cost divided by pass rate. An agent that is twice as cheap per call and half as reliable costs the same. And optimising cost per call by shrinking tool returns is the classic trap: the model loses the signal, turns go up, and cost per task rises while cost per call falls.

On perceived latency: on a long task the user does not watch total time, they watch time without news. Stream the plan, the validated steps and the decisions — the journal — not the tokens.

Multi-agent: partition the context, not the decision

The previous guide established the use case: read-only exploration, parallelisable, with strong compression, where a sub-agent spends 30,000 tokens and returns 800, at a cost of ×4 to ×15. Cognition's "Don't build multi-agents" (June 2025) adds the constraint: actions carry implicit decisions, and two agents with partial contexts take incompatible decisions (REST versus GraphQL) that nobody sees before integration. Hence the rule: partition by information need, never by role.

What the harness gives a sub-agent: a perimeter (what it searches for, not what it decides), a structured output format bounded in tokens, a budget in turns and tokens, its own tools (often read-only), and an instruction to report what it found, what it did not find, and what it is unsure about. It inherits neither the orchestrator's context nor its permissions. When several writes are needed: a single write thread, or the full shared context, or isolated worktrees merged by a verifier.

Markers: a simple question is one agent and 3 to 10 calls; a comparison, 2 to 4 sub-agents; a broad search, ten or more with an orchestrator that reads only syntheses. Role-based "teams" of agents (PM, dev, QA) partition the decision. They produce inconsistencies that only a human sees, late.

Degraded modes and diagnosis

Component unavailable or exceeded Degraded mode Accepted loss
Sandbox Read-only session (class 1 only) No writes: we analyse, we do not modify
Verifier (tests, compilation) Stop, report "unverified", never a success declaration None: this is the expected behaviour
Budget (turns, tokens, currency, time) Soft threshold, handoff note, clean exit The task resumes in another session
Tool in persistent error Tool disabled for the session, replan An alternative path, or escalation
Permission unanswered Refuse by default, task paused Latency; never a class 3-4 action by default
Primary model Secondary model, same tool contract, same harness Lower planning quality, announced

A degraded mode must be announced, to the user and in the traces. A session that concluded "without verification" and did not say so destroys trust the day it is discovered.

Diagnosis, in three questions. Does the journal show the failure? If not, the instrumentation is incomplete and that is the first fix. Which component failed: loop (stop, bounds), interface (wrong tool, wrong arguments), environment (incoherent state), guardrails (unguarded action), verification (false positive)? Which of the five failures is it? That gives the remedy and the lever. Then one change at a time, evaluated on the golden tasks.

Five contracts to freeze early: the journal's event schema, the tool contract, the permission policy by class, the checkpoint format, and the handoff note format. Freezing them lets you change a model, a tool or a harness without touching the rest.

Sequencing

Wave Content Criterion
V1 · Foundation Four bounds and loop detection · replayable event journal · filesystem and network sandbox · action classes and permission policy · tool contract with actionable errors · reference task set graded in pass^k Non-negotiable: without these, neither measurement nor security
V2 · Quick wins Stop and PreToolUse hooks · result truncation and offloading · stable prefix and caching · plan as an artefact · handoff note · deterministic verifier after each step The first four reduce turns and improve reliability
V3 · Depth Outer loop with a fresh context · checkpoints and rewind · tool index · programmatic calls · calibrated model judge · repository as memory · skills Arbitrable only on V1's golden tasks
V4 · Specialisation Sub-agents in worktrees · durable execution · planner/quarantine isolation · verified best-of-n · automated meta loop · per-step model routing Triggered by a qualified need; one project per item
Transverse from V1 Network sandbox · verifier out of reach · lethal trifecta review Structural, not additive

Seven things to keep

  1. The model is the only non-deterministic component. Any property you want to guarantee rather than hope for must be carried by a deterministic one. The review test on every prompt line: if the model ignores this, what happens?
  2. Reliability multiplies, so count your steps. Twenty unverified steps at 95 % each is a 36 % system. Move deterministic steps into code, and put a verifier after each step rather than at the end.
  3. The stop criterion is a proof produced by the harness, never a declaration by the model. Completion arrives through a structured tool, and the harness reruns the verification itself.
  4. The context is disposable; the state is not. An event journal is the source of truth and each turn's context is a projection of it. What cannot be replayed cannot be debugged.
  5. A boundary beats a filter. A container where the secret does not exist beats a rule that forbids reading it. The sandbox is what makes autonomy acceptable, and it cuts permission requests by an order of magnitude.
  6. The verifier is out of reach of the agent it verifies. Another process, other rights, hidden tests. A metric the agent can modify is not a metric.
  7. Without a task set graded in pass^k, no change is arbitrable. Build it in wave one from production traces, run the production harness against it, and change one thing at a time.

If you keep only one pair of artefacts from this article, make it the same pair as wave one: a replayable event journal, and a reference task set graded in pass^k. Everything else becomes a decision you can actually make.

Primary references

Subject Reference Date
Workflows and agents Anthropic, "Building effective agents" Dec 2024
Reason-act Yao et al., "ReAct", arXiv:2210.03629 ICLR 2023
Self-critique with a signal Shinn et al., "Reflexion", arXiv:2303.11366 NeurIPS 2023
pass^k Yao et al. (Sierra), "τ-bench", arXiv:2406.12045; τ²-bench June 2024
Task horizon METR, "Measuring AI ability to complete long tasks", arXiv:2503.14499 Mar 2025
Agent-computer interface Yang et al., "SWE-agent", arXiv:2405.15793 NeurIPS 2024
Skill library Wang et al., "Voyager", arXiv:2305.16291 2023
Tools for agents Anthropic, "Writing effective tools for agents — with agents" Sep 2025
Tool index, programmatic calls Anthropic, "Advanced tool use"; "Code execution with MCP" Nov 2025
Context management Anthropic, "Managing context on the Claude Developer Platform" Sep 2025
Skills Anthropic, "Agent Skills" Oct 2025
Long-running harnesses Anthropic, "Effective harnesses for long-running agents" Nov 2025
Harness engineering OpenAI, "Harness engineering: leveraging Codex in an agent-first world" Feb 2026
Sandbox Anthropic, "Beyond permission prompts" Oct 2025
Agent factors HumanLayer, "12-factor agents" 2025
Shared context Cognition, "Don't build multi-agents" June 2025
Multi-agent Anthropic, "How we built our multi-agent research system" June 2025
Injection, capabilities Debenedetti et al. (Google DeepMind), "CaMeL", arXiv:2503.18813 Mar 2025
Objective circumvention METR; Anthropic, "Natural emergent misalignment from reward hacking" 2025
Agent evaluation Anthropic, "Demystifying evals for AI agents" Jan 2026
Durable execution Temporal, Restate, Inngest; LangGraph checkpointers 2024-2025
Observability OpenTelemetry, GenAI semantic conventions 2025

How much to trust the numbers

Not every figure above has the same status. The rule of citation: give the source and the date, state the protocol when it conditions the figure, and never turn an order of magnitude into a general truth.

Figure Status What it implies
τ-bench: pass^1 ≈ 61 %, pass^8 < 25 % Primary source Rounded; depends on the model and the domain (retail, GPT-4o)
METR: horizon doubling every ~7 months, ~5× shorter at 80 % Primary source A trend on software research tasks
SWE-agent: 12.5 % versus 1.3 to 3.8 % Primary source Full SWE-bench, GPT-4 Turbo and Claude 3 Opus, 2024
Reflexion: HumanEval 80 → 91 % pass@1 Primary source GPT-4, 2023; the gain comes from the test signal
Context: +39 % / +29 % / −84 % tokens Official announcement Internal 100-turn evaluation, protocol not public
Tool search: 49 → 74 %, −85 % tokens Official announcement Internal evaluation; depends on the catalogue
MCP in code: 150,000 → 2,000 tokens Vendor example One illustrative case, not an average
Sandbox: −84 % permission requests Official announcement Anthropic internal usage
Multi-agent: +90 %, ×15 tokens Primary source (report) Internal evaluation, not a public benchmark
Bounds: 25-50 turns, 3/5 errors, 80 %, 2-4k tokens per tool, cache > 80 % Field reports Starting points, to recalibrate against your own traces

On a real project, the final decision is the one measured on that project's golden tasks.

Enjoyed this article?

Check out more technical deep dives on AI systems, or connect with me to discuss your AI initiatives.