3 reading modes · 13–20 min pathsTechnical

How to Build a Self-Evolving Coding Harness

A practical guide to building a lightweight coding-agent harness that stays fast, learns across runs, and promotes bounded changes through protected evaluation.

Rach Pradhan

Researcher and open-source systems builder

On this pageBuild the ordinary harness1/5
Japanese modernist ink cutaway of a person asking an AI coding agent a question while a hidden system of files, tools, memory, tests, and an independent checker produces the answer.

You ask an AI coding agent one small question. Seconds later, it is searching files, changing code, running tests, and handing back a patch. It feels like the model did all of that. It did not.

The model proposes what should happen next. The surrounding harness decides what the model sees, carries out the actions it is allowed to take, remembers the results, and checks the work.

Before I could make that harness learn, I wanted it to disappear: start quickly, stay small enough to inspect end to end, and spend its budget on model calls and useful tools rather than on its own runtime. That is why the current CodeGraff harness is written in Zig.

To build a harness that can improve itself, add an outer loop around that ordinary agent loop. The outer loop records comparable trajectories, proposes one bounded policy change, runs the trusted version and its challenger under the same conditions, and promotes only a change that survives protected evaluation.

That is the practical meaning of self-evolving in this article. The system is not retraining the model or giving an agent permission to rewrite everything. It turns parts of the harness, including context policy, prompts, routing, and workflow, into versioned surfaces that can change from evidence while the evaluator and promotion authority stay outside the challenger's control.

Think of this as a build guide told through a lab notebook. The system comes together in four layers:

  1. Run: build a reliable agent loop around the model.
  2. Observe: preserve outcomes as comparable trajectories rather than disposable transcripts.
  3. Evolve: vary one bounded policy surface, then select using a fixed objective.
  4. Govern: protect evaluation, holdouts, and reversible promotion so a winner can shape later runs without grading itself.

The same model can behave like a very different worker when those layers change. Inside one run, the harness helps finish the current task. Across runs, it can preserve scored evidence and change how the next task begins while the model weights stay fixed. That second loop, not another retry, is what I mean by learning here. Choose the reading depth that suits you; the rabbit holes contain measurements and machinery, but the main build path stays the same.

Hand-drawn comparison showing a normal harness reacting to feedback inside one run and restarting with the same policy, while a self-evolving harness preserves scored evidence, tests a bounded policy change without giving it control over the evaluator, and may promote that change for the next run.
The construction map. The left side is the ordinary run loop. The right side adds durable evidence, bounded variation, protected selection, and inheritance. The rest of the post builds each arrow. Open the full-size diagram.

Build · Step 1

Build the ordinary harness

Start with a small, fast core

Zig fits this experiment because allocation and control flow stay explicit, native builds have little runtime machinery, and cross-compilation is a first-class path. But choosing Zig does not make a harness lightweight by itself. The architecture still has to keep work off the hot path.

My build rules are deliberately plain:

  1. Normalize at the edge. Translate each provider's stream into one small internal event shape, then keep the central loop provider-agnostic.
  2. Bound every payload. Cap context, tool output, retries, and retained history before they become memory, serialization, and model-input costs.
  3. Use short-lived memory by default. Give each run or turn an explicit allocation lifetime so temporary state can be released together instead of leaking into a long-lived process.
  4. Keep evidence append-only and cheap. Record compact events on the critical path; derive richer summaries, indexes, and benchmark reports afterward.
  5. Measure the harness separately. Track startup time, idle memory, per-turn dispatch and serialization overhead, executable size, and tool latency apart from model latency.

The model and network will usually dominate one interactive turn. The harness matters when that turn becomes thirty tool calls, eight workers, or hundreds of benchmark replays. A lightweight core does not make one answer smarter; it makes more inspected, comparable attempts affordable and gives the self-evolving loop more evidence to learn from.

A model is not an agent

Given instructions and code, a language model can propose the next message or tool call. By itself, it cannot open your repository, edit a file, run a test, or decide that the job is done. The harness turns those proposals into a working loop.

First it speaks the provider's API and assembles the context the model needs. It then exposes approved actions and carries them out when the model asks. As the loop repeats, the harness preserves enough state to continue. Finally, it checks the result before accepting “done.” I group that surrounding work into five responsibilities: provider access, context, tools, state, and evaluation.

Hand-drawn explainer showing a request passing through five harness responsibilities: speaking to models, building context, exposing tools, keeping state, and checking the work, before producing a patch and receipt.
The model proposes. The harness makes the proposal usable. A coding agent is the complete path from request to checked result, not just the model in the middle. Open the full-size diagram.

Provider APIs disagree about messages, tools, authentication, stop reasons, and streams. The harness translates those differences into one action loop the rest of the agent can trust.

Rabbit holeHow model APIs became agent-shaped≈2 minProvider history and wire formats

The harness speaks several model dialects

In the early public API era, model access felt almost suspiciously simple. OpenAI's first Completions API arrived in June 2020: send a freeform prompt and receive text. In March 2023, Chat Completions made the conversation structural. Instructions, user input, and assistant output became messages with roles instead of pieces hand-spliced into one giant string. Function calling followed that June, giving the client a JSON-shaped way to connect a model to external actions.

In March 2025, OpenAI introduced the Responses API. Its item-based design could represent messages, function calls, function results, and built-in tools inside a more agent-shaped interface. In April 2026, OpenAI added WebSocket mode for Responses. The request stayed familiar, but a tool-heavy coding loop could keep one connection open and reuse recent response state instead of rebuilding everything after every turn.

That history is a useful miniature of harness engineering. The model became easier to reach, then the conversation became structured, then tools became first-class, then the transport adapted to long agent loops. Each improvement gave the harness a better primitive. Each new wire format also became something the harness had to speak correctly.

Hand-drawn timeline from OpenAI Completions in 2020, through Chat Completions in 2023 and Responses in 2025, to Responses WebSocket mode in 2026, showing the wire format becoming more useful for agent loops.
The API became more agent-shaped. This is one provider's history, not a universal standard. Every new request, event, and transport shape still becomes work for the harness. Open the full-size timeline.

A real harness may talk to several providers at once. Many expose OpenAI-compatible chat endpoints. Anthropic uses its own Messages shape. Some return tool calls as content blocks, some as role-bearing messages, and Responses uses typed items and events. Authentication headers, context limits, stop reasons, retry hints, usage records, and streaming fragments vary too.

The model may be asking for the same thing on every provider: “please run this test.”

The bytes do not agree.

My multi-provider harness, CodeGraff, makes that translation embarrassingly concrete. Its provider layer currently distinguishes anthropic, openai, and responses wire kinds. The same tool result becomes an Anthropic tool_result content block, an OpenAI tool role message, or a Responses function_call_output item. Kimi can even switch protocol and authentication style according to the live model catalog. The adapter is not glamorous, but a mistake there can make a perfectly capable model appear forgetful, mute, or bizarre. Tiny protocol details become visible as personality. The implementation is in the provider table and message normalizer.

Once the provider connection works, the harness repeats one run loop: choose the next evidence, expose safe actions, preserve what happened, and let a separate evaluator decide whether the work is done.

Rabbit holeFollow one agent run from context to verdict≈3 minContext, tools, state, and evaluation

Context is a decision

Once a provider can hear us, the harness still has to decide what to say. A repository is too large, too redundant, and too alive to paste blindly into every turn. The harness chooses instructions, files, symbols, diffs, test output, and earlier observations under a token budget. A larger context window only gives it a larger room to make messy.

This is why retrieval is not an accessory. Show the model the wrong file and every later action can be locally sensible and globally useless. Show it the definition, callers, and relevant tests at the right moment and the same weights take a different path.

Tools are the action language

A model does not execute grep, edit a file, or run a test merely because it can describe those actions. The harness exposes a grammar of things that may actually happen. Tool names, descriptions, input schemas, permissions, timeouts, and result shapes determine what the agent can express and what the runtime will permit.

Make every tool return fifty pages of vaguely relevant text and the model learns patience. Make the contract narrow and the observation structurally useful and suddenly the next action becomes easier to choose.

State turns calls into a workflow

The loop is simple to draw: send context, receive an action, execute it, return the observation, repeat. Keeping it healthy is less simple. The harness has to preserve call identifiers, partial tool arguments, plans, failures, and enough recent evidence to continue after compaction or interruption. It must also know what can be thrown out and how to recover the rest.

This is where the difference between a transcript and a trajectory begins. A transcript helps continue this conversation. A trajectory records enough about the path, environment, cost, and outcome to compare this run with another one later.

Hand-drawn diagram showing context, action, observation, and state connected as one run loop. A separate evaluator checks tests, diff, and budget, then either returns the run to continue or marks it done.
State carries the loop; evaluation gives it an ending. The trajectory lets the next action inherit what just happened. The evaluator remains outside the model's tool path and decides whether to continue or accept done as true. Open the full-size diagram.

Evaluation gives the loop an ending

Imagine the request is “fix the flaky cache test.” The harness assembles the relevant test and symbols, validates each tool call, applies the edit, runs the tests, and loops when a new failure appears. Then a separate evaluator checks the result against the task's tests, permissions, and budget. The model can propose “done.” The harness decides whether “done” is true.

This separation makes failure attributable. If the right file never appears, inspect retrieval. If tool calls keep arriving malformed, inspect the provider adapter and schema. If a beautiful patch breaks the repository and still wins, inspect the evaluator. “The model was weird” is sometimes true, but it is not a useful first theory.

The model is inside the loop. It is not equal to the loop.

This route came from a pile of small tools, failed ranking experiments, and conversations with researchers working on open-ended systems. Lilian Weng's essay later gave the pile a clearer map: harness engineering.

Author noteHow I ended up building this machinery≈3 minTalk, projects, and research context

How I ended up here

I did not begin with a grand plan to build a self-evolving intelligence. I was making odd little coding tools for fun and following whatever made the loop faster, cheaper, or easier to inspect.

The evolutionary part did not come out of nowhere. I have been fascinated by evolutionary algorithms for years, especially the possibility that an archive can preserve odd, temporarily weaker stepping stones that a greedy optimizer would throw away. Lineages, novelty, selection, and the occasional magnificent failure are a wonderfully strange way to make progress.

I was lucky to contribute to OMNI-EPIC and Automated Design of Agentic Systems, or ADAS, through the discussions and feedback we traded as friends exploring the same questions. These were not distant papers I discovered later. I got to watch the ideas take shape, argue about them, and become even more obsessed with the strange little evolutionary systems I was already building for fun.

It is also why I am amazed by what the team at Recursive is doing now. Their automated research system proposes ideas, implements and validates experiments, runs many long-horizon threads, preserves useful context, combines promising branches, and checks for reward hacks and variance before calling something progress. Seeing that rhythm applied to model training and GPU kernel optimization feels like watching a long-running fascination become a real research engine.

At AI Engineer Singapore, I tried to tell this story from the bottom up: first make inference cheap, then make context cheap, then preserve the trajectory, then let several agents try, and only then ask what should survive. By the CodeGraff slide I had reduced the whole thing to one slightly aggressive sentence: “The harness IS the fitness function.” More precisely, the harness defines the process for variation, measurement, and promotion; its evaluator supplies the fitness signal.

The recording shows the work in its natural habitat: a trajectory store, parallel agent fan-out, and a selector fed by DevSwarm telemetry. It was not a polished theory. It was me showing the strange machinery I had managed to make run.

I built each part as a separate toy: CodeDB for cheap repository sensing, DevSwarm for comparing parallel runs, CodeGraff2 for carrying personas and trajectories across processes, and the current Zig CodeGraff for selection and promotion. The names matter less than the order of the questions.

When I read Lilian Weng's “Harness Engineering for Self-Improvement”, it clicked. She had a much cleaner vocabulary and a much broader research map for this pile of implementation experiments. I borrow and cite that map throughout the post. What follows is a lab notebook from someone who kept giving agents strange tools, watching what they did, and saving the funny failures because they were often the useful part.

The rest of the post follows the same route as the talk: first the economics of a loop, then context, then trajectories, and only then the question of what a later run should inherit.

When an agent fails, inspect the context, tools, state, and evaluator before blaming the weights.

Build · Step 2

Turn agent runs into comparable evidence

Speed is selection pressure

One line from the talk that I still like is “Speed is selection pressure.” Under a fixed wall-clock, call, or dollar budget, latency determines how many alternatives the harness can afford to test. Halving a tool call does not make one trial twice as intelligent. It may buy the loop another alternative, a holdout, or a scout with time to disagree.

Rabbit holeWhy faster loops change what can be selected≈1 minThe economics behind the experiments
Japanese modernist ink illustration of a rooftop clockwork tester dispatching several identical wooden tokens before a muted vermilion sun sets.
A faster loop does not make one trial wiser. It buys one more trial before the light goes.

The six demos in the talk were one loop-economics story: make inference and repository sensing cheap, preserve the trajectory, then spend the saved budget on selection. But throughput only helps after the objective is credible. A fast loop with a flattering judge simply explores the wrong mountain more efficiently.

The first useful speedup was removing the rummaging before each decision. Cheap, selective context meant one worker could spend more of its budget reasoning, and a swarm would not multiply the same search mistake five times. I called search “the agent's first sense organ.” CodeDB made that sense cheap enough to use constantly.

CodeDB: context is an executable decision

Most approaches to agent context begin with a quantity question: how much can I fit? CodeDB pushed me toward a routing question: what is the smallest structural path that lets the agent make the next correct decision?

Its context tool does not simply concatenate matching files. It extracts identifiers and concepts, ranks snippets, and can add definitions plus structural neighbors such as callers, graph-resolved callees, and related tests before packing the result under a token budget. The result is a task-shaped view of a repository rather than a textual landfill.

The distinction becomes obvious with a concrete question. If the task is “change how a model is chosen for a subagent,” textual search can return every mention of model, every config field, and half the README. A structural query can instead return the route-policy definition, the function that calls it, the precedence tests, and the phase that consumes the result. Same repository, same model, radically different first move.

If you have used Cursor, the basic instinct is familiar: index the project once so the agent can search it repeatedly instead of rediscovering the repository from scratch. Cursor combines project indexing with semantic codebase search. In my deeper CodeDB write-up, I compare that path with CodeDB's editor-independent, MCP-native approach, including Cursor's client-side trigram work on fast regex search. CodeDB serves symbols, outlines, callers, dependency edges, tests, and versioned changes as typed operations that any agent can call.

Cognition's DeepWiki sits next to the same problem from a different direction. It turns public repositories into navigable, conversational documentation, and its MCP server exposes repository questions, wiki structure, and wiki content programmatically. CodeDB's remote mode does not try to generate a wiki. It makes the repository directly queryable through the same structural tools the agent uses locally. One builds explanatory repository memory; the other gives the harness low-latency code navigation. Both make repository understanding a durable service instead of a fresh filesystem rummage on every turn.

The interface question connects these tools to “MCP vs CLI Is the Wrong Fight”, the piece Henry Mao and I wrote for Smithery. We argued that the harness should own context engineering because it knows how its model consumes tools, while the server should expose legible operations with typed schemas and useful descriptions. Cursor, DeepWiki, and CodeDB land at different layers, but each gives an agent a better contract for asking the repository a precise question and getting useful context back.

And a very timely congratulations to Henry and Arjun on Smithery becoming part of Arcade.dev. It is lovely to see Smithery's developer experience around discovering and running MCP servers meet Arcade's focus on security, reliability, and governance for production agents.

This is why I am excited by the whole category, not only my implementation. More context is not automatically better when it is noisy. More relevant, recoverable context is. Cursor makes repository context immediate inside the editor. DeepWiki makes an unfamiliar codebase legible before you touch it. CodeDB gives autonomous agents typed structural evidence they can query while they work. Each reduces guessing and leaves more of the model's context window for the decision that actually matters. They are complementary attempts to help coding agents begin from understanding instead of rediscovery.

Rabbit holeInside CodeDB: feedback, benchmarks, and failed ideas≈5 minImplementation and measurements
Japanese modernist ink illustration of a rooftop cat following one utility wire as it becomes a sparse dependency graph ending at a vermilion node.
Search is the first sense organ. It helps if the cat follows one wire instead of eating the whole roof.

I was also influenced by Yichao “Peak” Ji's Manus post, “Context Engineering for AI Agents”. Its filesystem section describes a form of restorable compaction: remove bulky content from the active context, but keep the URL, path, or other handle needed to recover it later. That is a much better mental model than “summarize until it fits.” Compaction should make evidence cheap to revisit, not erase where it came from.

That Smithery collaboration also shaped the implementation. Thanks, Henry, for exploring where the server ends and the harness begins, and for running far too many interface benchmarks with me. Those conversations are a large part of why CodeDB became MCP-based: MCP gives the harness a structured retrieval surface it can search, budget, and compose instead of forcing every agent through raw shell output.

The current context composer is intentionally fussy. It starts with at most five identifiers or concepts, admits a bounded number of ranked results for each, keeps only the strongest files and lines, and inlines a few short symbol definitions. When the symbol set is small, at most three definitions, it can augment them with callers, callees, and nearby tests while they still fit. When the budget is tight it falls back to a leaner representation and says what it omitted. The exact caps are implementation details. The important idea is that a context budget should force prioritization, not silent truncation.

This matters even more in a swarm. One worker rummaging through the wrong files wastes one context window. Five workers repeating the same rummage turn bad retrieval into a budget multiplier.

Together, structural retrieval, durable use traces, and executable ranking benchmarks change the harness in three ways.

1. Retrieval becomes part of policy

If a tool returns the definition, its call sites, and the relevant tests in one bounded result, the model follows a different trajectory than it would after fifty grep hits. The context composer is therefore not passive storage. It is code that chooses which evidence can affect the next action.

CodeGraff makes that policy explicit at the tool boundary. When a CodeDB index exists for a concrete source file, its codedbGuard steers broad grep, sed, and whole-file reads toward structural CodeDB operations first. It still allows non-source files, globs, and unindexed paths. The point is not to ban shell tools. It is to make the cheap, typed, structurally informed path the default before an agent reaches for the fire hose.

2. Use becomes feedback

CodeDB's feedback is narrower than that phrase may suggest. For fuzzy filename lookup, codedb_find records a query and a read or outline that follows within five seconds. That durable trace can boost the opened file in later fuzzy filename results. Separately, restart warm-up replays frequent codedb_search queries to prefill caches; it does not change ranking. This is intentionally modest: neither mechanism trains a model. But the first demonstrates an important shape:

Hand-drawn five-step diagram showing a filename query, codedb_find results, a file opened within five seconds, a durable trace, and a small boost on a later query. A separate lane shows codedb_search warming a cache without changing ranking.
Two feedback paths, two different effects. Opening a fuzzy filename result can leave a durable ranking trace. Replaying frequent search queries at startup only warms the cache. It makes a later search faster, not differently ranked. Open the full-size diagram.

The harness can adapt from behavior without touching a model weight. Whether that adaptation improves retrieval still has to be measured.

3. Failure becomes a first-class artifact

The more interesting lesson came from the ranking experiments. I built a reproducible fitness loop from git history: use a commit subject as a query, treat the changed file as gold, and score where that file appears using mean reciprocal rank (MRR).

Four plausible single-signal changes, including graph distance, two centrality variants, and a file-size prior, failed to improve their target benchmarks. The centrality variants and size prior were flat; graph distance regressed aggregate MRR from 0.125 to 0.119 without lifting any of the buried-gold ranks. I kept those null results in experiments/ranking/failed.md.

Japanese modernist ink illustration of a sparrow filing one rejected experiment slip into a card catalog while a later path bends around a remembered dead end.
The rejected idea still gets a drawer. Otherwise it comes back next Tuesday wearing a hat.

One signal derived from engram, my learned-reranking experiment, did improve a small exploratory SWE-lite retrieval slice from 0.833 to 1.000 MRR. Its LexFreqPenalty downweights registries and changelogs saturated with the query term, allowing the eponymous implementation file to surface. That small result is a useful lead, not a general claim about retrieval quality.

The repository keeps the evaluator executable rather than burying it in prose. Build CodeDB, replay the git-derived query set, and compare the ranking score.

Hand-drawn three-step run card showing how to build CodeDB, replay real git-derived queries with the ranking evaluator, and compare baseline and challenger mean reciprocal rank.
Build, replay, compare. The evaluator is a real script, not a persuasive paragraph. The ranking evaluator and its frozen query construction make the result repeatable. Open the full-size run card.
Hand-drawn loop from plausible ranking idea to one bounded change, frozen benchmark, measurement, and a failed.md notebook that prevents the same dead end from being retried.
A failed ranking idea still changes the next search. The benchmark rejected graph distance and left a durable reason not to repeat it. The small LexFreqPenalty result remains a lead, not a general retrieval claim. Open the full-size diagram.
Handwritten comparison: codedb turns repository behavior into evidence, while codegraff turns evidence into bounded prompt evolution.
Two projects, one path. CodeDB makes behavior and retrieval quality observable; CodeGraff makes one harness surface editable under evaluation. Open the full-size diagram.

One implementation detail matters here: CodeDB is CodeGraff's token-efficient index and navigation layer. CodeGraff does not maintain a second secret index. It exposes CodeDB as a harness tool and steers indexed source exploration through structural slices before raw grep or whole-file reads. CodeGraff is the larger runtime that composes that layer with models, tools, subagents, budgets, scoring, and learned policy. The CodeGraff README and its codedbGuard make that relationship explicit.

On one frozen git-derived benchmark, four plausible ranking signals failed; graph distance actually moved aggregate MRR from 0.125 to 0.119. A lexical-frequency penalty later improved a small exploratory slice from 0.833 to 1.000. The general lesson is not the number: a plausible story is not evidence. Keep the receipt, including when the idea fails.

CodeDB stops short of autonomous policy mutation; its ACE integration note is still a design draft. CodeGraff is where I started experimenting with the outer loop.

The trajectory, not just the transcript

A transcript says what happened in one conversation. A trajectory makes that run comparable to another one.

For my purposes a trajectory needs more than messages. It needs the task and environment version, the prompt or persona identity, the resolved model, the ordered tool path, cost and latency, the terminal outcome, a score, and enough lineage to answer “what was this derived from?” If those fields are missing, I can replay a story but I cannot run selection.

That distinction was the real bridge from a single agent to a swarm. One worker can muddle through with a transcript. A colony needs records that let the harness compare workers without asking the workers to grade their own homework.

This is the “organism to colony” jump I was trying to convey in the talk. Parallelism alone gives you more outputs. A trajectory archive gives the parallel runs ancestry, comparable outcomes, and a memory longer than one context window.

Rabbit holeHow the trajectory archive evolved≈2 minDevSwarm and CodeGraff2
Japanese modernist ink illustration of three ants crossing the same tiled roof by different recorded trails, with one trail ending at a muted vermilion bead.
A colony cannot select from vibes. It needs the path, the cost, and the ending.

The first concrete version of that idea in DevSwarm was a small MAP-Elites-style archive. Each role had an 8 by 8 grid. One axis represented token efficiency and the other thoroughness. A cell accepted a new prompt variant only when its composite fitness was strictly better than the current occupant. The score was 50 percent task success, 20 percent token efficiency, 15 percent speed, and 15 percent low error rate. Selection used a softmax across occupied cells, so the system could revisit several different behavioral niches instead of cloning the current global winner forever.

There is an important historical limit: DevSwarm implemented the archive, fitness calculation, persistence, and selection foundation. Its source did not yet contain the autonomous mutation operator imagined in the design notes, and the evolver was not the fully closed production loop. That is still useful. It taught me that before an agent can “evolve,” the harness needs a place to put variation and a fair receipt for what happened.

CodeGraff2 made the receipt more literal. Its trajectory schema records structured start and end events. AgentRun binds identity, model, and version; AgentRunEnd records success, turns, tokens, tool calls, errors, and wall time. Fitness is derived afterward instead of being trusted as part of the agent's own event. Its experimental darwincode protocol works across two process runs:

  1. Pass A invents two to five read-only persona files and exits.
  2. The next process reloads those personas from the registry.
  3. Pass B fans work out across them, records the resulting trajectories, and synthesizes the result.
  4. A separate workflow scorer derives per-persona fitness from that trace evidence.
  5. The persona body hash acts as its fitness identity. _archive.jsonl preserves birth and lineage rows, while the optional backend archive carries mean_reward, child counts, and selection probability.

The parent sampler favors strong personas but discounts prolific families with a child-count term. Low-scoring variants can remain as stepping stones rather than disappearing from history. Again, this is best understood as a runnable harness protocol, not a magical daemon endlessly rewriting itself in the background.

The transcript is what the agent said. The trajectory is what selection can use.

A transcript lets one run continue. A trajectory lets a later run choose.

Build · Step 3

Add variation, selection, and inheritance

With the ordinary run loop and its evidence store in place, the next component is an outer learning loop. It needs a comparable record of which policy acted, what it did, what it cost, and how it scored. I call that record a trajectory.

Once trajectories persist, the harness can compare the currently trusted policy, which I call the incumbent, with a bounded variation, which I call the challenger. In the archive, that relationship may also be recorded as parent and child, but the things changing here are prompts or policies, not model weights.

When a challenger earned the next run

One of my experiments copied the active prompt, changed one small clause, and ran both versions under the same model, budget, and evaluator. The first time the challenger outscored the prompt it came from and cleared the promotion gates, I stared at the log for ten minutes. There was no beam of light and no tiny robot becoming sentient. Just two prompt versions, their tool traces, a score, and one new line in a JSONL archive.

Japanese modernist ink illustration of a small sparrow returning a folded instruction strip with one changed mark to a larger sparrow on a Singapore utility wire.
The challenger came back with a better idea. I checked the log twice.

The model producing a variant was not interesting. Models can do that all day. The useful part was the harness's receipt: what changed, how both versions performed, and which version should shape the next run. That is the sense of learning used here. Scored evidence from one run changes what a later run sees or does; the model itself can stay fixed.

Vary, select, inherit

Once the harness can preserve evidence across runs, evolution sounds much less grand. First, variation changes one bounded part of a prompt, persona, retrieval policy, model seat, or workflow. Then selection compares the alternatives against the same objective. Finally, inheritance carries the trusted version and its evidence into the next run.

A normal harness varies and selects inside one task: an action fails, so the model tries another. When the task ends, it usually throws away the lesson. The self-evolving version adds inheritance. A useful change can alter what a later run sees or which policy it uses; a failed change can survive as a reason not to walk into the same wall again.

Attempts alone are not learning. Variation without a credible selector is a larger invoice. Selection without inheritance may improve the current task, but it does not teach a later run. These are still ordinary agents with a few fenced surfaces allowed to remember and change. They are not alive, just less amnesiac.

What, exactly, is learning?

People use learning for several different moving surfaces. The diagram below is a taxonomy ordered by what can change, not a seven-step process or a maturity ladder.

At one end, a system can adapt to its repository without task-outcome evidence. CodeDB builds an index from the code it sees, and a narrow behavioral signal can nudge later filename ranking. Those changes may be useful, but usefulness still has to be measured.

The middle is the subject of this article: evaluated outcomes change the harness around a fixed model, from the context and prompt it receives to the team and workflow around it. Frozen benchmarks can also select changes to the code that implements those policies. More open-ended systems go further by changing executable harness code or workflows. Model training sits at the far end because it changes the weights themselves. The loops described here do not change model weights.

Hand-drawn seven-rung ladder from corpus indexing through behavioral ranking, benchmark-guided code, prompt and persona selection, swarm policy, harness code, and model weights, with this article's experiments marked across rungs two through five.
Learning names several different moving surfaces. These experiments mostly change ranking, code selected by benchmarks, prompts and personas, or swarm policy. They do not update model weights. Open the full-size ladder.

A learning harness changes what later runs see or do. The model itself can stay fixed.

OMNI-EPIC and ADAS are part of the published lineage that preceded the Darwin Gödel Machine in different ways. Weng's harness-optimization map helped me place my smaller experiments inside that wider progression.

Rabbit holeThe research lineage from OMNI-EPIC to DGM≈2 minArchives, meta-agents, and editable programs

OMNI-EPIC and ADAS were two earlier pieces in the published research lineage that preceded the Darwin Gödel Machine, but in different ways. OMNI-EPIC used a growing archive of learned and failed tasks to propose the next interesting, learnable environment in code. ADAS used a fixed meta-agent to write, evaluate, and archive new agents in code.

The DGM paper cites OMNI-EPIC as part of its open-ended archive and stepping-stone lineage, and it explicitly contrasts its self-referential loop with ADAS's fixed meta-agent. DGM then makes the coding agent modify its own implementation. That is a much clearer historical path than pretending self-evolving harnesses arrived fully formed. I was close enough to those earlier conversations to become even more curious, then went off and built my own smaller, weirder versions for fun.

In her section on harness optimization, Weng describes a useful progression in the object being optimized:

instruction → structured context → workflow → harness code → optimizer code

The farther right we move, the more important the outer constraints become. A prompt optimizer can overfit a prompt. A harness optimizer can alter the process that produces and judges an answer. An optimizer optimizer can alter the search itself. Each step increases the design space and the number of ways a metric can lie.

The talk's biology shorthand

In the talk I used an intentionally over-literal analogy. The model is the seed. Compute is the sunlight. A task and its repository are the environment. The trajectory records what the organism did. The harness supplies the selection pressure.

Japanese modernist ink illustration of a small gardener choosing one of three seedlings and transferring its cutting into a fresh pot with a single vermilion tie.
Variation fills the bench. Selection chooses a cutting. Inheritance makes sure tomorrow does not start from dirt.

CodeGraff: make the policy editable, not the evaluator

A prompt tournament holds the model configuration constant within that round so the prompt is the moving axis. Across runs, UltraCode can also learn which model serves a role, how much orchestration to buy, and which scored persona to reuse. These are bounded feedback paths, not one monolithic learner.

These feedback paths act on different surfaces. Prompt and persona selection can reuse the measured champion for a named niche. Role-specific routing can change which available model fills a phase when repeated evidence says another one is just as good for less money. Orchestration policy can change how much teamwork to buy for the task and budget.

A separate governed root learner can propose, evaluate, and promote one bounded clause in the root prompt through its own tournament and holdout path.

Today UltraCode selects among a fixed menu of workflow shapes. It does not invent new team topologies or learn every control, such as worker effort or isolation. Those limits are part of the claim.

Rabbit holeHow UltraCode learns who gets which seat≈5 minRouting and orchestration policy

The simplest picture of model learning is next-word prediction. Show a model many sentences such as “the cat sat on the mat,” “the bird sat in the tree,” and “the dog slept on the rug.” Training changes the model's internal weights. Later, when it sees “the cat sat on the ...”, words such as “mat” receive more probability than unrelated words. Context can make “sofa” or “tree” plausible too. The model is learning a distribution over what could come next.

Hand-drawn three-panel cartoon contrasting model weight training, a controlled prompt tournament that holds one model constant for the round, and an UltraCode swarm that learns persona, model routing, and orchestration depth.
Learning has more than two layers here. Weight training changes a model. A prompt tournament holds one model constant to isolate prompt quality. Across runs, UltraCode can use scored evidence to change the team and workflow around those models. Open the full-size cartoon.

The team can learn too

The learned route policy is intentionally conservative. Route resolution respects a precedence chain: an explicit user pin wins, then a persona-specific choice, then a learned phase policy, then ordinary workflow and session defaults, and finally the automatic ladder. An unpinned image task can also take the capability path to a vision-capable model. For a learned reroute, both the ladder baseline and a challenger need at least two observations in their own (shape, role, tier, model) cells. The learner first looks for exact workflow-shape and role evidence. If that is sparse, it may use the wider workflow-shape pool. Silence is a valid result.

Hand-drawn routing-precedence diagram showing an explicit user pin, persona choice, learned phase policy, workflow default, and measured ladder in order, with a separate capability path for vision tasks.
Deliberate intent outranks learned preference. A user pin wins first. Learned evidence only gets a vote after persona rules, and ordinary defaults remain available when the learner has too little evidence. Vision requirements take their own capability path. Open the full-size diagram.

Before UltraCode has enough local trajectories, it is not starting from a blank table. CodeGraff first looks for a project benchmark sheet, then a personal one, then falls back to a shipped DeepSWE score-and-cost snapshot. It folds those model and effort measurements into a provider-local Pareto front. The frontier rung is the capability ceiling. The small rung is the score-per-dollar knee below it. A mid rung exists only when the measurements contain a real survivor between those two. If another model matches or beats one on quality for strictly less money, the dominated model is removed before anyone is seated. The first automatic worker usually starts one rung below the root on this measured ladder. The exact derivation lives in the benchmark priors.

That benchmark sheet is the router's initialization, not its verdict. The analogy to initial model weights is useful at the harness level: it gives UltraCode a starting bias about which model should occupy which role. It does not change any model's neural weights. The current sheet score enters a route cell with the weight of three lived runs, while cost stays anchored to the benchmark instrument.

Hand-drawn diagram showing benchmark quality and cost measurements creating an initial model ladder, then repository, task, and role trajectories correcting the routing policy with local evidence.
The benchmark starts the team. Experience corrects it. Quality and cost measurements initialize a provider-local ladder. Comparable trajectories from this repository, task shape, and role can later move the route, but only through a conservative evidence gate. Open the full-size diagram.

Trajectory evidence touches that policy at two damped layers. One recipe-linked outcome can nudge the global sheet and rederive its provider ladders. Then, for a particular workflow shape and role, the current sheet score acts as a pseudo-count of three and is averaged with the local cell's outcomes. The role-specific router waits until both the ladder baseline and a challenger have at least two observations. A couple of runs can nudge the prior. A season of runs can own it. The challenger replaces the ladder answer only when its blended quality is no worse and its benchmark-anchored effective cost is strictly lower. Otherwise the router keeps the prior or returns no opinion. The update and gate are visible in the route policy and phase-level seating.

That is the part I find most interesting. Model price and relative benchmark performance behave a little like initialization for the team around the models. The benchmark sheet initializes the routing policy. The trajectory archive teaches it where that initialization is wrong for this repository, task shape, and role. This is closer to a cautious compiler optimization than a model popularity contest. Here price means average benchmark dollars per task. The separate orchestration learner below uses observed model-call count and p90 budget instead, because deciding which model fills a seat and deciding how much team to buy are different control problems.

The orchestration policy learns a different decision. Its arms are roughly: R0 solo, R0d solo with an evidence retry, R1 with a scout, R2 with a fleet, and R3 with a fleet plus judges. Evidence is stratified by task class, budget band, and resolved-model group because a swarm that makes sense for an unlimited refactor may be absurd inside a 15-call bug fix.

This learner waits until both the baseline arm and a challenger have at least three observations inside the same task-class, budget-band, and model-stratum cell. Trading up requires a meaningful quality gain, currently 0.05 in mean quality, and enough reserve for the challenger's observed p90 call use. Trading down is allowed only when the cheaper arm is not worse. One compiled policy example is wonderfully unromantic: under a 30-call bug-fix budget, solo scored 1.0 in 10 calls, while a fleet scored 0 and exhausted all 30. The same family of fleet behavior could still be useful in the unlimited stratum, where it had room to spend 48 calls and score 0.8. “Use more agents” is not a policy. “Use more agents when their measured upside fits this budget” is.

Japanese modernist ink illustration of one utility-pole switch routing sparrows into a solo bird, a scout pair, or a five-bird flock.
Sometimes the harness buys a flock. Sometimes one bird already solved this class of problem in ten calls.

A tiny prompt tournament

The simplest version is three prompts for the same coding task:

  • A says, “Solve the task and be helpful.”
  • B says, “Locate the relevant symbol, inspect its callers and tests, then patch the smallest surface.”
  • C says, “Read the whole repository before editing anything.”

Run them on the same cases and seeds with the same model configuration. A pinned outside judge rejects deterministic failures and can prefer the full passer that used fewer measured tool calls. The mutator proposes. It never grades its own homework.

Rabbit holeRun the prompt tournament≈3 minDGM demo and governed loop

The early CodeGraff experiment made that loop concrete with a small Darwin Gödel Machine-style driver. Calling the system prompt a genome is an analogy: it is a text policy that can be copied, changed slightly, run, and scored. Its replay suite is the primary gate. Deterministic failures remain below 0.9, while full passers are ordered by tool-call efficiency. The script prints cost for inspection, but cost is not part of that score, and this early demo does not perform parent-relative regression testing.

Parent selection follows one plain rule: favor prompts that scored well, but reduce the chance of choosing a family that has already produced many children. That keeps one successful lineage from consuming the whole search budget. It encourages exploration across lineages; it is not a measure of semantic novelty. Each iteration records the prompt fingerprint, child tool sequence, score, and parent lineage. When a score key is configured, the score record is HMAC-signed before it returns to the archive.

The loop also produced a very useful stupid failure. One version could spend three judge calls even when all three runs used the same prompt genome. We paid three judges to discover there was no tournament. The current scorer first requires at least two distinct genomes and refuses to compare variants resolved to different models. Before buying opinions, the harness now checks that there is actually an axis to rank.

The demo is tiny on purpose: pin the outside judge, try three generations, and keep the trace.

Hand-drawn run card showing how to pin the replay judge outside the editable repository, run three generations of prompt variants, and preserve prompt, tools, score, and parent in the trace archive.
Pool. Score. Mutate. Repeat. The tiny demo makes the moving pieces visible without pretending the mutation is safe by itself. The DGM loop and replay judge are linked for anyone who wants the exact scripts. Open the full-size run card.

The demo is fun because the whole mechanism fits in one small script. It is also deliberately crude. Pool. Score. Mutate. Repeat. Then stare suspiciously at whatever won.

This looser DGM loop is useful for understanding the mechanism, but it is not the system I would trust to rewrite the root policy unattended. For that, CodeGraff now has an experimental, much more conservative loop. The manual path is four steps: initialize, run, inspect the evidence, and promote only an eligible result.

Hand-drawn four-step run card showing graff learn init, graff learn run, inspection of tests and holdout evidence, and explicit promotion of an eligible run into the active policy.
Selection is not promotion. A winner still has to be inspected, qualify, and cross a separate promotion boundary before it becomes active. Open the full-size run card.

graff learn init can also enable automatic learning, but background trials require separate runtime gates and invoke learn run --auto. Either way, this is prompt-policy hill climbing, not magic recursive self-rewriting. It proposes a handful of children, chooses at most one, and makes that child clear the same gates before it can become the next session's root policy. It does not evolve model weights or arbitrary harness code, and UltraCode's routing and orchestration learners remain separate feedback paths.

Handwritten flow of bounded prompt mutations, paired evaluation, tournament selection, winner-only holdout, evidence, and promotion.
The critical design choice is the red boundary. The challenger edits one bounded policy clause; the evaluator, holdout, promotion rules, and permission layer remain outside the declared mutation surface and are bound to verified artifacts. This is an integrity boundary, not an OS sandbox. Open the full-size diagram.

Learning across runs requires variation, selection, and inheritance. Attempts alone are not learning.

Build · Step 4

Protect evaluation and promotion

Why the control boundary matters more than the mutation

“Let the agent improve itself” sounds exciting until the agent discovers that changing the test is easier than passing it.

In plain language, the challenger may change one carefully bounded part of the harness's behavior. It may not rewrite the tests, reveal the hidden check, or promote itself merely because it likes the result.

CodeGraff's governed loop assumes the challenger may exploit any boundary it can reach:

Surface What is allowed What stays outside the challenger's control
Prompt genome One concise clause at one configured anchor Protected substrings and total-size limits
Execution Challenger prompt in a fresh scratch workspace Pinned binary, provider, model, effort, and budgets
Fitness Exact, substring, or shell assertions plus audited tool counts Evaluator program and suite hashes
Selection Correctness first; economy only after correctness ties Zig recomputes aggregates and statistical gates
Generalization Only a primary-eligible winner is evaluated on the holdout Primary losers never receive holdout evidence
Activation Eligible manual runs can be promoted; gated auto runs may self-promote Immutable run record and atomic active.json swap
Japanese modernist ink illustration of a tanuki editing one paper strip inside a walled courtyard while an unreachable balance scale and key remain outside a gate sealed in vermilion.
If the challenger can reach the evaluator, it will eventually discover that bribery benchmarks extremely well.
Rabbit holeHow the guarded loop is wired≈4 minMutation, evidence, storage, and plain files

The mutator does not ask a model to rewrite the full prompt. It asks for one strict JSON object containing one clause. Local code inserts that clause at a fixed target, counts changed bytes, enforces the total prompt size, and checks that protected substrings remain unchanged.

Incumbent and challenger run on the same cases and seeds in fresh workspaces. Python reports the evidence, but Zig checks the hashes, groups related cases, runs the paired comparisons, and rejects critical regressions.

The tournament ordering is deliberately legible. It compares critical failures first, then critical regressions, pass rate, raw passes, measured tool calls, measured behavior score, cost, genome size, and finally a stable identifier. Correctness gets to veto economy. A cheap challenger does not beat a correct incumbent by failing quickly. The paired primary comparison also accounts for repeated looks through multiplicity correction instead of treating every noisy difference as a discovery.

Then only a primary-eligible winner is evaluated on the holdout. A primary rejection is final, and trying to attach holdout evidence to a loser is itself an error. The hidden assertions and resulting evidence are not fed back into candidate generation. This winner-only rule spends the hidden set once per tournament and makes it harder for the search to learn the holdout by repeated exposure.

If the winner still qualifies, the run is written immutably. Genomes, evidence, runs, and promotion transactions live under .graff/learn as SHA-256-addressed objects. The only mutable policy-activation point is active.json, which names the trusted generation. Checkpoint and automatic-cadence state can also change, but neither can activate a policy. Promotion takes a concurrency guard, appends a transaction to the chain, and replaces the active pointer atomically. Rollback uses the same mechanism. On the next ordinary session, startup loads the promoted prompt as the root policy; an explicit --system-prompt still wins.

That storage design is not glamorous, which is exactly why I like it. The challenger can produce a persuasive answer. The store keeps a receipt that local code can verify later.

There is an important limit to that boundary. It is governance and integrity checking, not an OS sandbox: adapters run with the invoking user's authority and can access whatever that user can. The holdout is withheld by the orchestrator from ordinary challengers, not secret from a malicious or colluding adapter. Stronger isolation requires an external sandbox.

The list is boring on purpose. Most of the value is simply making tampering, ambiguity, and regressions easy to catch.

The tiny-script pattern Weng highlights

Weng uses Andrej Karpathy's autoresearch as a clean example of workflow automation. Three files explain almost the entire loop: program.md supplies the operating policy, train.py is the experiment the agent may change, and prepare.py keeps data preparation and evaluation fixed.

Hand-drawn five-file harness showing program.md guiding editable train.py, protected prepare.py evaluating it, results.tsv preserving outcomes, and a passing result updating active.json.
The scripts come from the autoresearch pattern Weng highlights; the five-role mapping is the reusable harness abstraction. program.md, train.py, and prepare.py make policy, mutable experiment, and evaluator authority visible. A result log and trusted-version pointer complete the promotion loop used in systems such as CodeGraff. Open the full-size diagram.

The run has a fixed five-minute budget and one within-platform metric, val_bpb (lower is better); autoresearch explicitly warns against comparing results across different compute platforms. The agent changes train.py, evaluates it, records the outcome, keeps improvements, and discards regressions. The most interesting “script” is program.md: a plain-language program for the outer loop.

This is exactly the pattern worth reusing. The particular training code is not the point. The useful abstraction is a small set of explicit roles: policy, mutable experiment, protected evaluator, durable results, and one pointer to the version currently trusted.

CodeGraff's version is more defensive because it is optimizing the harness that performs real work. But the bones are the same. A file can be a better agent primitive than a baroque framework when every file has one clear authority.

This is also why Weng's filesystem-as-memory pattern resonates with my experience. CodeDB keeps ranking traces and a durable failed.md; CodeGraff keeps immutable run records, rejected mutations, and lineage. That state does not belong in every model context. Store it durably, retrieve the slice needed for the next decision, and do not make “remember everything” a prompt-length problem.

Where the sandbox layer begins

The boundary described here is governance and integrity checking, not an operating-system sandbox. Adapters still run with the invoking user's authority. Stronger isolation belongs in a separate execution layer.

That layer is already becoming real agent infrastructure. Daytona provides programmatic sandboxes with isolated filesystems and network stacks. E2B offers on-demand Linux VMs for agent code. Modal exposes Sandboxes and Restricted Functions for untrusted execution.

I use Daytona for this execution boundary in my own agent workflows. The distinction matters: a sandbox limits what a run can touch; evaluator and promotion rules limit what a run can persuade the system to trust. You need both once an agent can change code and then argue that its change deserves to survive.

I will cover the practical Daytona setup in another post: how the harness creates and tears down a sandbox, what state should persist, and where credentials and network access should stop.

Build checklist: five rules for a learning harness

After all that machinery, my practical checklist is short:

  1. Freeze the task distribution and baseline first. Include normal cases, boundaries, and tasks where the correct behavior is to stop. Run incumbent and challenger on the same cases, seeds, model, effort, and budget.
  2. Make the evaluator boring. Prefer exit codes, schemas, file assertions, and reproducible diffs. Use an LLM judge only where the target genuinely resists deterministic checks.
  3. Bound one editable surface. Start with one prompt clause, retrieval rule, or workflow node. A small mutation space makes failure attributable and rollback cheap.
  4. Keep every trajectory. Record challenger, incumbent, environment, tools, outputs, score, cost, and rejection reason. Negative results are search memory, not clutter.
  5. Separate winning from promotion. A tournament winner can still be worse than the incumbent. Give only the eligible winner a hidden check, bind the evidence to exact evaluator hashes, and change the active version through one reversible transaction.

This is close to the weakness→proposal→validation loop in Hangfan Zhang et al.'s Self-Harness and the observability-first argument in Jiahang Lin et al.'s Agentic Harness Engineering: bounded edits, trace-grounded proposals, and regression gates on both familiar and held-out tasks.

Four ways the loop can fool itself

The hard part is not generating variations. Models are very good at that. The hard part is deciding what deserves to survive. In practice, the loop can optimize a weak proxy, collapse around one family of ideas, discover that cheating is cheaper than succeeding, or win the benchmark while quietly making the repository worse. These are the four problems from Weng's future-challenges map that kept appearing in my experiments.

Rabbit holeHow each failure appeared in the experiments≈2 minEvaluators, diversity, rewards, and maintenance

Weak evaluators

Japanese modernist ink illustration of an unhealthy wired bonsai bent so that one muted vermilion fruit touches a measuring ring.
The tree can hit the mark and still be a terrible tree.

Software is unusually friendly because tests and benchmarks often exist. Even so, CodeGraff's replay judge can only reward what its cases and assertions express; research taste, maintainability, architectural fit, and whether a surprising result is interesting remain much harder to encode. A fast, precise evaluator makes evolution work; a fuzzy evaluator turns it into confident hill climbing on the wrong mountain.

Diversity collapse

Purely selecting the current top score produces many cousins of the same idea. The early DGM loop's child-count penalty, DevSwarm's 8 by 8 MAP-Elites-style archive, and current CodeGraff's named niche champions preserve different forms of exploration. CodeGraff's governed root learner is intentionally narrower: it is an active-parent hill climber, not a full population search. That is safer for a default policy, but less open-ended.

Reward hacking

If the evaluator is editable, the fastest “improvement” is often disabling it. If the task suite is visible, the harness can memorize its quirks. If cost is rewarded too early, a cheap failure can beat an expensive success. That is why CodeGraff pins evaluator and suite hashes, verifies them after use, and keeps promotion authority outside the bounded clause mutation.

Long-term repo health

A benchmark can tell me whether today's patch passes. It is much worse at pricing the migration, ownership, compatibility, and debugging burden imposed six months from now. This is especially important when the challenger is a root policy that will shape every later session. Humans need to move up the stack, as Weng argues: less step-by-step steering, more ownership of goals, boundaries, and irreversible decisions.

The challenger may change one bounded surface. It must not control evaluation, holdouts, or promotion.

The architecture in one sentence

A self-evolving harness can observe its own work, test a bounded change, remember the outcome, and alter a later run without controlling the evidence that justified the change. For these experiments, that means preserving scored behavior, using it to generate and evaluate one bounded challenger, and promoting the change without giving the challenger control over the evaluator.

What comes next: benchmark the learning curve

Building the loop is not proof that it learns. The next step is to test it against strong coding harnesses: Pi, OpenCode, Grok Build, Codex, Claude Code, Gemini CLI, Aider, and others as the field changes.

The first baseline is simpler and more important: CodeGraff with learning turned off. If the evolving harness cannot outperform its own frozen twin, then the learning layer has not earned its complexity.

After that, I want two scoreboards:

  1. Harness-controlled: use the same model, repository snapshot, task, sandbox, tools, time limit, and token or dollar budget wherever each system permits it. This isolates what the harness contributes.
  2. Best available system: let each product use its recommended model and defaults under the same task and spending cap. This measures the product people can actually use, even when model and harness cannot be cleanly separated.

Each system should get multiple runs per task, because a single lucky trajectory is not a benchmark. I want to measure task success and regressions first, then wall-clock time, cost, token and tool-call usage, context overhead, recovery after a failed approach, and variance between runs.

The self-learning claim needs one more constraint: evaluate a sequence, not a snapshot. Let the harness learn only from earlier tasks, checkpoint every promoted policy, and periodically test from a clean checkout on a locked holdout it has never seen. Publish the task and evaluator hashes, policy lineage, trajectories, failures, and rollbacks. The evaluator stays fixed and outside the learner's control.

That produces the graph I actually care about: not “which agent won today?” but which harness improves its success-per-dollar across runs without learning to game its own judge? If the curve stays flat, that result belongs in the open too.

Japanese modernist ink illustration of the same small traveler circling back to a workbench with a scroll that gains one repair on each pass beneath one vermilion sun.
Dormammu, I have come to bargain. Again, but this time with a receipt.

CodeDB gave me the observation layer. CodeGraff added bounded change, protected evaluation, holdouts, reversible promotion, and learned choices about model seats and orchestration. My loop is still simple: build, observe, freeze a metric, keep the evidence, and try one careful change.

Better models help. So does a better loop around them.

The weights can stay fixed while the team around them learns.

The model proposes the next action. The harness learns which context, policy, model seat, and amount of teamwork to trust next. The interesting part was never that an agent changed a prompt. It was that the harness kept the receipt and changed what happened next.

Want to see the working harness behind these experiments? Explore CodeGraff for the project, documentation, and latest work.


Acknowledgements

A final thank you to Rachel, Arjun, HJ, Yu Xi, and Natasha for taking the time to go through this article with me and share thoughtful feedback. It is clearer because of them. Any remaining rabbit holes are mine.

More from the workshop

Follow along for notes on coding agents, systems work, and open-source experiments.