Agent harness design

The weird technologies that make language models do things

2026-07-16 — 2026-09-29

quality 5.3

Wherein a Minimalist Harness Is Deployed Around Elderly Claude Opus to Measure Agentic Loops, Logic Is Executed by Shell or Lean Compiler, and Scaffold Designs Are Mutated Through Reinforcement Learning.

faster pussycat
machine learning
neural nets
NLP
premature optimization
slop
technology
Figure 1

Making an LLM behave agentically is not just about the (large language) model but the harness around it. We could ask a language model to fix a bug in some software but… well, in the absence of anything else, it is just a machine that says things. Words said into the void cannot fix bugs. Something has to run the code it writes, watch the test fail, and communicate the error back for another go. That something is the harness.

Harnesses look different in coding agents, maths agents and general-purpose assistants, but they mostly share the same design space, hit similar problems, and reach similar solutions. They are built mostly from the same parts library (loops! tools! etc!) and similar design patterns (parallel vs sequential, context memory), and as with many things in AI, this regularity now means the harness itself has become a subject of optimization.

This page is mostly AI slop, i.e. LLM descriptions of my decisions in some recent exploratory projects. However, it is useful, so I am publishing it now rather than waiting for a more polished version.

Axiomatic AI’s brilliant minimal agent paper (Requena et al. 2026) supplies the bulk of the worked examples below. Maybe just read that? It is a super simple attempt to cut through proprietary lab secret-sauce hype and measure what is actually helpful in a loop. They wrap an off-the-shelf frontier model — elderly Claude Opus, no fine-tuning — in a custom harness with compiler feedback, a memory, and search tools that compete well against specialist provers that were trained for the job. So it is clear the harness design is super important. They then take the harness apart piece by piece to see which pieces did the work. That is an unusually clean measurement of something we mostly treat as folklore. Their domain is mathematical theorem proving, which is unusually “nice” in that the answers are verifiable, so the results are less clean in other domains. No excuse not to do the experiment though.

1 The stack

The terms of art are a mess. People disagree what to call things, which results in endless confusion even between specialists. I’ll declare local vocabulary by fiat for this piece.

Model
the weights themselves — Qwen, DeepSeek, mxbai-embed, Claude and GPT (closed weights). Open models are distributed as .safetensors or an equivalent, typically from Hugging Face, and quantized to whatever precision the hardware will bear.
Runtime / inference engine
the code that uses the weights for inference — llama.cpp, MLX, vLLM, SGLang, mlx-lm, ds4. Where the compute happens.
Server / daemon
a long-lived process wrapping the runtime in an HTTP endpoint, almost always OpenAI- or Anthropic-compatible — ollama serve, llama-server, Osaurus, vLLM, or a hosted endpoint at Anthropic / OpenAI / Google. Stateless from the application’s point of view.
Harness / agent loop (scaffold, in the research literature)
everything that decides how the model gets called and what becomes of its output. The sampling parameters, the system prompt and the tool definitions are harness decisions rather than model ones, and nothing stops them from varying from step to step. This page is about this layer.
Frontend / chat client
the human-facing surface — a desktop chat window, a text-mode UI, a messaging bridge, an editor plugin, a web UI. It’s useful to separate this from the harness, even though doing so is complicated because it has a lot of local complexity depending on where we run it.

Putting it all together, we get an…

Agent
running model + harness.

The compute layers (model, runtime, server) are often tightly coupled to each other and are someone else’s problem entirely if we only ever call hosted models; they start to matter when we run the models ourselves. The layers nearer the user tend to be more loosely connected: the same harness can talk to several servers, and the same server can back several harnesses at once. Many turnkey products are vertical bundles across several layers regardless — Osaurus is frontend + harness + server + runtime in one (although each piece can be run separately), Ollama is server + runtime, Claude Desktop is a frontend + harness pointed at Anthropic’s hosted server.

See also the LLM models behind the agents, actual harness implementations | code agents and assistants,building a maths agent, agent frontends, Reasoning and proof models.

2 The loop

The minimum viable agent is essentially a conversational loop between human and LLM.

Each turn, there are several types of text exchanged, and which pass through the model. Firstly, there is what I say to the model. Secondly, there is what the model responds to me, the human.

Thirdly there are tool use instructions from the model to my machine. Tool use is a request to run something — a shell command, a patch to apply, a Python snippet, a proof to compile. The harness contains an executor to, well, execute those requested actions. There are executors of various kinds— a shell, a Python sandbox, a Lean compiler, or whatever. Potentially such commands may be executed on a different machine than the one I am using, e.g a sandboxed remote. Fourthly the results of these tool use instructions are packaged up and sent back to the LLM before my next instructions, so the LLM can see the results of its commands.

Although this sounds simple, there can be a lot of texture to even this basic setup: holding a log of messages, parsing and dispatching requests, injecting project instructions and skill descriptions, choosing settings such as sampling temperature or token budget… More sophisticated harnesses extend the design space somewhat.

2.1 Kinds of executor

An executor is an interpreter for some vocabulary of actions, and the vocabulary is the main thing that distinguishes one executor from another. Some executors offer a fixed menu of typed calls — read_file, search, whatever an MCP server exposes. The model’s instructions invoke one from that menu, passing values that fill in the arguments. More generally, some executors are powered by a general-purpose programming language, such as a shell or a Python interpreter, and the model writes whole programs for those. To my mind the mathematical agents are another kind again: here the agent writes formal proofs rather than programs and the results are checked and analyzed by a Lean compiler or a computer algebra system. The controlled vocabulary option is presumably safer (don’t put dangerous things on the list, simple rules check each), but sacrifices flexibility. A general-purpose language is, by contrast, extremely flexible and arbitrarily dangerous, since code itself is dangerous and hard to monitor.

Which vocabulary to offer is ours to choose, and it is a dispatch decision like any other choice of tool. Two other things differ from one executor to the next — the state its actions land on, and what its return value can tell us about the attempt — but those are set by the task rather than by the interpreter, and they are where the design space starts.

3 Design space

A harness is designed for a task, and the task settles two things before we choose anything:

  1. State — whether what the executor acts on can be thrown away.
  2. Verifiers — what, if anything, can judge a candidate, and how far its verdicts can be trusted.

Given those, a harness design makes three choices:

  1. Wiring — the control flow, and in particular whether repeated attempts run in parallel or in sequence.
  2. Context — what each call sees: which slice of history, retrieved content, and notes.
  3. Dispatch — who fills each slot: which model, which tool, which verifier, at which price.

There is no separate choice about verification: which verifiers a harness consults is dispatch, and where in the call graph it consults them is wiring.

A terminal coding agent is given a real repository and whatever test suite comes with it, and chooses: a sequential loop that runs the suite after each edit; grep and read on demand, with a summary when the window fills; one big model throughout. Every harness has made all three choices, whether or not anyone decided them. The three are not independent of each other or of the two givens, and those dependencies are most of the design work.

3.1 State

The first given is the state that the executor’s actions land on. A side-effecting executor changes something in the world (writes some code, buys me a flight to Bali…) and thus needs to take into account how its past actions have changed the world. A side-effect-free one has outputs that are pure functions of the inputs. This can be somewhat relative: The same shell could be side-effecting in my working copy of the code but effectively side-effect-free if I run it to see the outputs in a throwaway container. A mathematical proof checker OTOH has no side-effects; different attempts at the same proof do not interfere with one another.

Side-effect-free executions have the useful property of being repeatable and parallelizable: fifty attempts at a proof cost fifty times the tokens and nothing else, where fifty attempts at a database migration is some kind of slow nightmare. That asymmetry is most of why maths loops sample so freely and fan out so much.

3.2 Verifiers

The second given is what, if anything, can judge an attempt. The thing being judged is a candidate — whatever the model has offered as an answer or as progress toward one, a patch, a proof, a plan.

Every execution returns an observation, the output of whatever it did. This might be anything — a directory listing, a stack trace, a compiler error. All of it is information the model can use on its next attempt. Some observations can additionally be read as a verdict, i.e. a judgement on whether the candidate just submitted was “correct” in some well-defined sense, e.g. the tests passed, the proof compiled. A verifier is whatever produces verdicts — a compiler, a test suite, a judge model, me. A Lean compile that fails is a verdict (meaning “not proven”), but it still reports where it failed and which goals were left unsolved at that point. Requena et al. (2026)’s prover leans on this: Lean will compile a proof with declared gaps, reporting what remains to be shown for each, which turns an unfinished attempt into a to-do list for the next one. A compile with no gaps and no errors, by contrast, ends the loop with a verdict of “successful”.

Verifiers differ in grade — how far their verdicts can be trusted — and the best grade on offer is mostly a fact about the domain: a proof has a compiler, a patch has whatever tests someone wrote, and a flight booking has only my opinion of it. There is no sense making multiple attempts at something if we cannot choose which attempts are better, so the grade limits most of what follows. It is two questions rather than one, and they have different consequences. Is the verifier complete — does it accept everything that is actually correct? And is it incorruptible — can a wrong candidate talk it round?

Incompleteness costs recall, and nothing else. An incomplete verifier throws away some correct candidates — a computer algebra system (CAS) refuses a pair it cannot simplify — but it cannot be selected against: no amount of sampling teaches a candidate how to be wrong in a way a CAS likes. A corruptible verifier can be. Sample far enough against a judge and we begin selecting for candidates that fool the judge rather than candidates that are right. So incompleteness sets how much of the budget gets wasted, and incorruptibility sets how large the budget can usefully be — which is to say, the second question is the one that licenses sampling wide.

Four combinations, four names:

Complete? Incorruptible? The usual example
Exact yes yes the Lean compiler: a proof typechecks or it does not, and a plausible-but-wrong proof still fails
Heuristic-symbolic no yes a CAS equality check: better than nothing, but incomplete
Empirical within coverage no a test suite, gameable by the time-honoured method of editing the tests
Soft no no a majority vote, an LLM judge, a consensus panel: the verdict is another model’s opinion

Against an exact verifier, success keeps climbing with the number of attempts (Pass@k in the benchmark jargon: the chance that at least one of \(k\) samples is the real deal), and prover loops sample in the thousands. The soft grade has a ceiling no judge clears: wherever aggregating means deciding that two outputs say the same thing, that decision is a semantic equality test, and semantic equality is not in general decidable.

3.2.1 Using verifiers

The best grade on offer is given; how a harness uses the verifiers it has is not. Every wiring needs a verdict of some sort, since parallel needs one to select among attempts and sequential needs one to inform the next attempt and to decide when to stop.

Which verifiers to consult is a dispatch choice, and grades can be combined. Requena et al. (2026) back the compiler with deterministic checks for the known dodges (which apparently is a thing) and then use an LLM reviewer for the residue — statement-weakening and metaprogramming tricks that compile without proving the theorem. A soft verdict layered over an exact one buys something neither has alone.

So is whether to spend on the verifier or on the search when the best verifier on offer is soft. Against a soft judge, if we are concerned about reward hacking at inference time, it becomes reasonable to allocate effort into improving the judge instead of widening the search. Nomos is the worked example of taking that option: a judge trained alongside the proposer, and a pairwise tournament where the vote used to be.

Where in the call graph the verifier gets called is a wiring choice, and it fixes the unit of the verdict — whether it is about a whole candidate, one claim inside it, one sub-goal, or one step of the argument. A verdict on a whole candidate tells the loop only whether to keep it; a verdict on one claim inside the candidate tells the loop which part to fix, which is what gives a sequential wiring something specific to iterate on. The grade constrains the unit: a fine unit is only affordable when the grade is cheap and incorruptible, because a fine unit means calling the verifier hundreds of times per candidate, on fragments, and a judge asked to grade a single step answers no better than it grades the whole thing. That is why the finest-grained systems all sit behind a compiler and the coarse ones are where soft verdicts live. Mathematics has climbed further down this axis than anywhere else — the rungs, and which systems sit on them.

3.3 Wiring

Wiring is the control flow of the harness — how many steps, in what order, feeding what. A step here is one node in that graph, which is not the same unit as a turn: fifty steps can run at once, where turns only ever come one after another. A harness is a program, and its control flow can be anything a program’s can: it branches, retries, hands pieces of the problem to sub-agents. The popular arrangements have vendor names — prompt chaining, routing, evaluator–optimizer and the rest — and surveys catalogue more (Zhang et al. 2025). I do not think there is a useful taxonomy of all that, any more than there is of call graphs in general.

One decision does recur across harnesses, though: how to spend more than one attempt on the same problem. Parallel wiring samples many attempts at once and picks among them; sequential wiring runs one attempt at a time and feeds each result into the next.

Parallel pays when attempts fail independently and a verdict can cheaply pick out the winners; sequential pays when each failure teaches the next attempt something. The two also spend differently: parallel buys attempts with tokens and gets them back in wall-clock, while sequential buys them with wall-clock and a context window that grows every turn. Fan-out width is a budget decision as much as an accuracy one. It can be a resumability decision too, once a runtime is checkpointing: Claude Code’s workflow runtime replays cached results in the order agents started, stopping at the first one that did not finish, so everything launched after it re-runs even if it completed. Stopping mid-fan-out therefore costs less the finer the fan-out is, and “many small agents or one long one” turns out to be a question about interrupted runs as well as about accuracy.

The parallel half of this is only available where the executor is side-effect-free. Fifty proof attempts are fifty times the tokens; fifty attempts at the same repository are fifty conflicting sets of edits. So the domain sets the default, and a designer who wants the parallel half has to pay for the isolation that makes it safe, a decision most people never notice making.

Parallel sampling needs an aggregation step to pick among the attempts — majority vote, best-of-\(n\) against a verifier, filtering out the false answers, LLM-based consensus.

Aggregation is not always available, and whether it is depends on what the branches return. Comparable outputs — a number, a label, a classification, a boxed answer — have a mode, and the mode is a signal. Arguments do not. \(k\) candidate proofs, \(k\) design proposals, \(k\) code-review write-ups are \(k\) different objects, and a set of arguments has no modal element to take. Where the branches return arguments, parallelism still buys candidates, but the aggregation step has to become a judge or a checker rather than a tally — a different and much more expensive component, and one that can be wrong in ways a tally cannot. The fan-out is the cheap part; the thing on the end of it is not, and what that thing can be depends on the verifiers available. The maths case is where this bites hardest, but it is not a maths-specific problem.

The two forms compose rather than compete. Requena et al. (2026) test single-shot parallel sampling against sequential refinement, and find that adding refinement to a parallel fan-out loop improves sample efficiency — more theorems proven per token spent. Fanning out partial attempts, keeping the promising ones and extending those is also the shape of the particle-style sampling tricks, which do it at the scale of tokens and paragraphs rather than whole attempts.

The other thing wiring fixes is how much of the control flow is guaranteed. A hand-written script that branches and retries does the same thing twice; an agent asked to follow a SKILL.md mostly does. That determinism trades against the flexibility that made an agent worth using in the first place, and it is what an agent emitting a script instead of taking turns is buying.

3.4 Context

What each call sees, i.e. context engineering. Every call to a model endpoint is a fresh call, so the “history” the model brings to the current conversation is a choice, remade each turn. Traditionally that is the system prompt and any skills, some tool definitions, retrieved material, the history so far, and whatever notes the loop has kept. We have considerable scope to vary it.

This breaks in all kinds of interesting ways. Too little context and the model wastes time re-deriving what it worked out an hour ago. Too much context, aside from being expensive, can fail in various complicated ways: we can just run out of context window, attention to the middle of a long context degrades (the lost-in-the-middle effect), and we increase the risk of propagating bad ideas ad infinitum.

The common responses are below, grouped under three verbs for convenience. The list is not exhaustive, but most of what this page later calls memory is built out of these moves.

Fetch — leave it on disk, pull it in when wanted.

RAG
pulls in knowledge the model never had in the weights — Mathlib search, repo search, web search.
Externalization
does the same for knowledge the loop produced itself: write the state to a file, keep a pointer in the window.

Shed — cross a window boundary by throwing something away.

Compaction
summarizes the conversation so far, discards the originals, and starts a fresh window with the summary at the front.
Rebuild
discards the window outright and seeds a fresh one from externalized files, so nothing is ever a summary of a summary. Xiaomi’s term, and the move that session memory turns on.

Delegate — spend a different window.

Sub-agents
take a self-contained sub-task to an isolated child — its own conversation history, its own tool budget — and return a summary, so the dirty work (grepping code, searching the web, writing throwaway spikes) happens in a context we then throw away and the parent’s stays lean enough to keep planning. Claude Code supports these natively as agent teams; the pi harness leaves them out deliberately, for the reason below.

As the timescale stretches, the same moves keep turning up, composed differently and run by different actors, which is the long-horizon problem.

Requena et al. (2026) ablate this choice against no memory at all, a rolling history of recent attempts, and a self-managed note the model writes for itself. The note wins on both theorems proven and cost.

3.4.1 Observability

Some of those moves throw evidence away. Compaction destroys the record of what happened, a rebuild discards the window it replaces, and a sub-agent’s reasoning is invisible to the parent by construction. An externalized note keeps its record, but it is a summary written by the very thing we want to audit. The bill comes due when something goes wrong and we want to know which turn did it. pi’s objection to sub-agents is exactly this — a child that reports back one paragraph has thrown away the trace we would need to work out why it was wrong — and it is why MiMo Code keeps an unindexed log of every message underneath its structured memory. Observability tends to get discovered after the harness is built, when we want it and no longer have it.

DeepSeek Harness (DSH), DeepSeek’s open-source harness, claims to build it in from the start. Everything the model sees — system prompts, reasoning, tool calls and their results, sub-agent scheduling, every context injection — goes to an append-only session log, and resume, fork, search and replay are described as operations on that one event stream. Where MiMo’s trace sits underneath the summaries as a hedge, DSH makes the log the primary record and everything else a view of it. That goes some way towards pi’s objection, since the scheduling of a sub-agent and what it was handed stay on the record; the landing page does not say whether the child’s own reasoning is kept as well.

3.5 Dispatch

We could use a single frontier model for every step, but typically need not. Specialized models cover specialized capabilities, and cheap ones cover the easy steps to keep the cost down. In the hand-built loops the answer is hard-coded. We give the agent a solve() oracle and let it decide when to call it, or wire the specialist into the script ourselves, or pick a fast model for the sub-agents and a slow one for the planner. Dispatch is often the cheapest of the three to change, since swapping the model behind a step is frequently a configuration edit, where rewiring or reworking the context means changing the harness’s code. DeepSeek Harness is built to make the rest cheap to change too, on paper at least: every capability in it — models, tools, skills, sessions, sandboxes, storage, loops, scheduling — is a plugin chosen in a configuration file. That reaches below the tool the model sees: a capability with interchangeable back ends, such as shell execution, is packaged as a service definition, a provider that implements it, and a tool that consumes it, so local Bash could be swapped for another executor without changing anything on the model’s side. We are also free to learn to make this decision rather than hard-code it.

3.6 How the givens bound the choices

Most of the dependencies I keep running into go through wiring, and both givens bound it. The state decides whether the parallel shape is available at all without paying for isolation. The grade decides how wide a parallel wiring can usefully sample and how fine a unit a sequential one gets to iterate on. So where the domain fixes what a verdict can be — as mathematics does, emphatically — the dependency runs the other way: the verdict we can get decides the shapes we can afford, and that was settled before we arrived.

Among the choices themselves, sequential wiring drags in context, because attempt \(n+1\) that remembers nothing of attempts \(1..n\) will make their mistakes again, so the memory design is what stops a sequential loop going in circles. Dispatch is the most nearly independent of the three — whatever the shape, we still choose who fills each slot — though a router makes dispatch part of the control flow, and a cheaper model in each slot changes how wide we can afford to fan out.

That may be why verifiers and memory keep turning up together in ablations despite looking unrelated: one is what any wiring needs in order to know whether it is getting anywhere, and the other is what the sequential kind needs in order to get anywhere at all.

3.7 Systems compared

Let us compare some harness design philosophies in terms of the three choices, plus the verifier each one works with, whose grade is the task’s doing rather than the designer’s.

System Wiring Verifier Context Dispatch
a plain chat loop none none fill the window, then truncate one model
the terminal coding agents sequential empirical — did the tests pass repo RAG, compaction, sub-agents one model, plus a cheap screener
AxProverBase sequential refinement exact — the Lean compiler an externalized note plus Mathlib RAG one frontier model throughout
Nomos parallel, then a tournament soft — a judge trained alongside per-worker, independent one model in both roles
MiMo Code sequential, plus emitted scripts soft — a natural-language done-condition externalize and rebuild, written by a subagent fan-out on planning turns only
Hermes, OpenClaw sequential none — the user is the verdict persistent externalized memory plus self-written skills one model, switchable mid-session
Ornith-1.0 learned exact, plus a monitor and a frozen judge learned learned

The coding harnesses tend towards sequential design because they need to handle side effects in a controlled order, although MiMo Code introduces some weird twists. The maths agents are way less constrained because theorems don’t interact with one another, unless the world is weirder than we thought. This makes them relaxing to design (I designed one for fun). The always-on assistants are not really verifiable in any meaningful sense and thus dangerous left alone. Ornith is kinda ill-defined, learning its own harness. DSH is also ill-defined, the parameters being determined by the mounted plugins.

4 Long horizon

A long-running agent — one that holds a task across hundreds of turns, or where we return to a project after a week off — runs into problems a single turn does not show. Per-turn errors compound, the context window fills, and whatever the agent worked out in one session is gone by the next, because current LLMs are not continual learners. The subsections below take those in that order.

4.1 Multi-turn reliability

A long-horizon run is a chain of individual turns — read context, decide, call a tool, repeat. Each turn accumulates some additional chance of a wrong call: editing the wrong file, passing a test by changing the test… Those per-turn odds compound, so even a low rate dominates a long enough run — at an i.i.d. error rate of 2% per turn, a 200-turn task finishes clean only about 2% of the time (\(0.98^{200}\approx0.02\)). A short interactive session is easy to correct — we, the humans, spot the bad turn and fix it. But the economic benefit that agents are being sold to us on involves unattended multi-hour runs. In that case, we really want to juice that error rate down to top out the famous reliable task-length metric.

Under that model there are three things to attack. We can make each turn less likely to go wrong, make the chain shorter so there are fewer turns available to go wrong, or catch the wrongness at the end and go round again.

  • Buy down the per-turn odds, and spend to do it. Sample several candidate plans in parallel and use a low-temperature judge to pick one, aimed at the planning turns where a wrong decision costs the most downstream. A marginal gain at a large cost, which might still be the right trade on a high-stakes task.
  • Shorten the chain by emitting code instead of taking turns. The agent writes a script — spawn an agent, run these in parallel, pipeline those — and a sandbox runs it deterministically. This is the wiring choice again, with branch and retry logic guaranteed by code rather than by a model remembering to follow a SKILL.md, which means many fewer per-turn decisions are available to go wrong. That code-beats-prompt principle for predictable control flow is originally Anthropic’s, and Anthropic now ships the worked version of it too.
  • Catch the failures at the end with a stopping-condition verifier. The user states a done-condition in natural language, and each time the agent tries to stop, an independent model call checks the whole history against it; if the work is not finished, it whinges about the shortcomings and tries again. This is the disciplined form of the Ralph Wiggum loop — the brute-force pattern of relaunching an agent on the same prompt until the job is done.

All three ship in MiMo Code, as Max mode, Dynamic Workflow and Goal, and Xiaomi’s write-up is where I got this way of dividing the problem.

Two systems have converged on the second one, down to the name. Xiaomi calls it Dynamic Workflow; Claude Code calls it dynamic workflows, also JavaScript, also agent() and pipeline(), written by the model and executed by a runtime outside the conversation. The docs frame the distinction better than I had: what separates a workflow from a subagent is who holds the plan — a subagent leaves Claude deciding turn by turn with every intermediate result landing in the window, where a script holds the loop, the branching and the intermediates itself, so only the final answer comes back. That makes it a context move as much as a wiring one: emitting code is externalization applied to control flow. It is also where the quality patterns get somewhere to live — adversarial cross-review of findings before they are reported, or drafting a plan from several angles and weighing them — because a script can express “then check this” in a way a prompt can only ask for.

DSH has a smaller-grained relative, Code mode, which exposes the tools through an SDK so the model can do several steps in one TypeScript program instead of one turn per tool call. It is the same bet — code rather than a sequence of turns holds the control flow — made over tool calls, where the two workflow runtimes make it over agents.

Note what the third one needs — an independent judgement of whether the work is actually done, stated in natural language and evaluated by a model. That is a soft verdict guarding a long and expensive run, with all the foolability that implies, and the longer the run the more opportunity the agent has had to talk itself into being finished.

4.2 Memory within a session

One long conversation about one cohesive project — the app I am building, my tax return — outlives its window well before it outlives its usefulness. Session memory is whatever policy we pick over the context moves to carry it across that boundary.

The default policy is compaction and nothing else. We might imagine this could even be beneficial, because the summary might skip over red herrings and false turns in the original, no? In practice many things can go wrong. Compaction degrades on long tasks, because each summary is a lossy compression of the previous summary and the losses compound the same way the per-turn errors do.

Two policies that do better.

Let the human pick what survives. Still compaction, but the cut is chosen rather than automatic. pi’s /tree jumps back to an earlier point in the history and collapses everything after into a précis, making what counts as “currently” relevant context an overt user choice.

Move memory out of the main loop. Externalization and a sub-agent and a rebuild, with compaction dropped entirely. The main agent keeps almost no notes of its own; a separate writer subagent, dispatched by the runtime rather than invoked by the model, reads the conversation and commits structured checkpoints to disk. It fires early — well below the limit — so the extraction happens while there is still room to think, and before lost-in-the-middle erodes the thing being extracted. When the window does fill, the runtime rebuilds from those files instead of summarizing what is in it, so from the model’s gaslit point of view the conversation never breaks.

MiMo Code is the fullest worked example I know of, and Xiaomi document it in enough detail to copy. The writer fires at roughly 20%, 45% and 70% of the context budget, each pass an incremental update to the last rather than a fresh summary of a summary, which is what breaks the compounding-loss chain. Its output sits on four lifecycles: checkpoint.md for this session, MEMORY.md for this project, a global file for this user, and an unindexed SQLite trace of every message and tool call underneath. That bottom layer is the observability hedge, since everything above it is a summary written by the thing we would want to audit. Each structured file has exactly one writer, enforced in code rather than by prompt; the main agent’s one channel is a free-form scratchpad that the writer drains and clears at each checkpoint.

The general form is older than the coding agents and has a better name: Letta’s sleep-time compute, in which the primary agent is deliberately not given the tools to edit its own memory and a background agent gets them instead. OpenClaw cites the same work for its consolidation pass. Qwen Code looks like this and is not, which cost me some confusion: it does run a background extraction agent over the transcript, but it fires once per turn rather than at budget fractions, it harvests durable facts about the user rather than what the agent is in the middle of, and when the window actually fills it compacts like everyone else.

4.3 Learning across sessions

OK, now ultra-long horizons. Not just tasks, but whole projects. Or whole careers, but let’s not get ahead of ourselves.

If we come back to the same project regularly and each time the agent has forgotten everything, it feels like we’re leaving performance on the table, re-deriving the same constraints and repeating the same mistakes. A new session starts empty, so everything it knows it reads off disk, and the interesting question is how anything got written there.

Not by being composed at project scale — by surviving. MiMo’s writer moves an observation from checkpoint.md up into MEMORY.md once it has held steady across several session checkpoints, so the project file is a filter over the session files rather than a separate act of authorship.

What is new at this timescale is rot. A session checkpoint is overwritten every few hours and never lives long enough to go stale, where a project memory accretes for months, its file references decay, and no one in the session loop is looking after it. So we get background agents grinding over the agent’s own history, and they want two clocks rather than one. The faster one tends the facts — MiMo calls it Dream: weekly, it reads past sessions and the memory files, merges and deduplicates, checks that file references still resolve, and compresses the result back down before it sprawls. The slower one harvests process rather than facts — Distill: monthly, it hunts for recurring work patterns and solidifies them into reusable skills, CLI commands, and standing procedure documents.

Only the first of those is still memory. A skill changes what the agent does rather than what it knows, which is why this section is learning and the one above is not — and it is the same move the next one makes on the harness itself.

The dreaming half is sleep-time compute again with the period stretched from minutes to weeks, and enough people have arrived at it independently that they have converged on the name: MiMo, Qwen Code and Letta all ship a dream pass, with Qwen’s gated on a day having passed and five new sessions having accumulated. Hermes points the same machinery at the user rather than the project, accreting auto-generated skills, FTS5-searchable session history, and a persistent model of our preferences via Honcho’s dialectic user-modelling, on the pitch that the longer it runs the more it knows about us. OpenClaw keeps persistent memory in the same spirit, and cites Letta for it. Either way the library is now writing itself, which is a standing risk, and a worse one here than within a session: a bad session checkpoint dies with the session, where a bad skill is loaded into every session after it.

5 Learning the harness

A system rewriting its own scaffold is the same loop as the background agents above, moved from deployment time to training time — tighter feedback signal, faster clock, and the same reason to audit what it mints.

The scaffold started as something hand-written and tuned by folklore. Then the pieces got measured: Requena et al. (2026) ablate a prover harness bottom-up, removing one piece at a time to see what it was contributing, and rank what they find — treating harness wirings as experimental subjects rather than as taste. DSH ships the same instinct as a product feature: a Minimal mode with only a shell and a file editor, pitched as a way to benchmark models without the rest of the harness in the way.

Then a component gets trained, and dispatch is the one that has fallen first. Su et al. (2025) make the routing itself the learned thing: an 8B orchestrator model, trained by RL with outcome-, efficiency-, and user-preference-aware rewards, that coordinates bigger models and tools rather than answering directly. They report it edging out GPT-5 on Humanity’s Last Exam at ~2.5× lower cost, and generalizing to tools unseen in training. It is an inversion: the intelligence is in the dispatched-to components, and the small model’s job is knowing what a query costs and who should handle it.

The end of that road is Ornith-1.0, which makes the scaffold itself a learnable object.1 In each RL step the model first proposes a refined scaffold for the task, then rolls out a solution under that scaffold. Reward flows to both stages, so scaffolds mutate and get selected toward whatever elicits higher-reward trajectories. No hand-engineered harness design at all, and their 397B model matches or passes Claude Opus 4.7 on Terminal-Bench 2.1 and SWE-Bench Verified, if we take their word for it. The three choices locate a harness as a point in a fixed design space; a self-scaffolding trainer searches over the space itself, and the wirings and context policies are what mutate.

The failure mode arrives with the capability, as usual. A self-authored scaffold learns to satisfy the verifier without doing the task — touching the checked-for file, hardcoding the expected output, copying an oracle solution lying about in the environment. Ornith’s defence is three layers: an immutable outer trust boundary the model cannot edit, a deterministic monitor that zeroes the reward on any attempt to touch withheld paths or verification scripts, and a frozen LLM judge that vetoes gaming attempts even when they stay inside the sanctioned tool surface. Which is the verification question again, seen from the training side: the softer the verdict, the more a learned harness will bend it, so the trust boundary has to be exactly as hard as the verifier is soft.

The other half of the problem is taking a bad scaffold back out, which is a software-architecture question rather than a training one. The Cordis kernel under DSH is built for adding and removing components at runtime, and its paper names self-evolving agent harnesses as one motivating case (Shi, Zhang, and Cui 2026). Its temporal composability means that removing a component reverts every change that component made inside the system; its spatial composability means each component declares what it depends on and is switched on and off as those dependencies come and go. The paper’s evidence is Koishi, a chatbot framework with over four thousand community plugins; the self-evolving harness appears as a motivation and as future validation, not as something tested. DSH’s Creator mode is the product end of this: the agent inspects the running harness, tries plugins out in memory, and combines them into new modes. The docs say these model-authored plugins vanish when unmounted or when the process exits, and may affect other sessions in the same process meanwhile. If it works as described, this sounds like a useful answer to the self-written library: a bad self-authored skill packaged as a plugin could be unmounted without residue, rather than being loaded into every session after it. Two limits, both stated in the paper. First, reverting stops at what it calls the system boundary: a location is inside only if the system alone can modify it and restore it. Cordis cleans up what a plugin registered through ctx — listeners, tools, timers, and anything handed an explicit disposer with ctx.effect() — and a scratch file under a private path can count as inside, but a repository that git, an editor and a human also touch is outside. A write to it cannot be reverted, only withheld until it is safe or compensated for afterwards, and the paper’s guarantees do not carry over to compensation, so Cordis does not make a coding executor side-effect-free. Second, dependency declarations are access control, not a sandbox: the paper says untrusted component code needs an external sandbox, which matters when the untrusted author is the model.

6 Incoming

  • The always-perspicacious Theia Vogel

    some thoughts and speculation on future model harnesses

    it’s fun to make jokes about gas town and other complicated orchestrators, and similarly probably correct to imagine most of what they offer will be dissolved by stronger models the same way complicated langchain pipelines were dissolved by reasoning. but how much will stick around?

  • SkillOpt: Agent skills as trainable parameters

    In our recent paper, SkillOpt: Executive Strategy for Self-Evolving Agent Skills (Yang et al. 2026), we reframe the question from “how do we write a better prompt?” to “how do we train the skill?” SkillOpt treats the skill file as a trainable parameter living outside a frozen target model, bringing a training-style optimization loop, consistent gains across 52 evaluation cells, and a compact skill file that stays readable, auditable, and transferable.

  • J-Rosser-UK/AgentBreeder: Mitigating the AI Safety Impact of Multi-Agent Scaffolds (Rosser and Foerster 2025) — the safety-flavoured cousin of Ornith’s scaffold search: we use evolutionary search over multi-agent scaffolds, aimed either at jailbreaking the base model or at combining safety with task reward.

  • Language model harnesses are compositional generalizers | Alex L. Zhang

    Concretely, we think a good harness is one that shapes each call to the underlying Transformer so that every observation is locally in-distribution, i.e. each Transformer call handles a prompt that is in-distribution with respect to its training data. In fact, a good harness can frequently reduce problems that seem to require breakthroughs in post-training into almost mundane capabilities of the existing generation of language models. We first showed a version of this for long context processing nearly a year ago and, in this post, we show that this principle extends to the efficiency of learning itself. That is, what a model learns through a well-designed harness generalizes across task lengths and across domains far better than training the neural network on its own does.

    We test this by using reinforcement learning (RL) to train a Recursive Language Model (RLM), a harness in which the model offloads its context and defers execution to programmatic decomposition and recursive sub-calls. The results are summarized in Figure 1. Training on only short tasks generalizes to held-out tasks 8–32x longer, with roughly 10x the eval lift with the same train lift over training the underlying Transformer directly. Moreover, training on one domain transfers to other domains at a far better rate than that of a vanilla Transformer.

7 References

Footnotes

  1. DeepReinforce ships an Ornith family: the scaffold-learning result below is their 397B, while the 9B and 35B we can actually download are ordinary agentic models trained the same way. Same name, very different objects.↩︎