Recursive self-improvement: the output, the instructions, the workflow

Day 2: Loops and your environment · Lesson 3 of 4 · 12 min

A critique produces a fix, and the fix is the least valuable thing it produces. Improvement runs in three nested rings: fix this output, change the instructions so the mistake cannot recur, and change the workflow. Only the outer ring carries an obligation: you do not claim an improvement you did not measure.

Watch first · 5 min

Why The Harness Matters More Than The Model | YC Paper Club

Y Combinator, 2026-09-07. Segment 13:56 to 18:35. Watch what is being improved in each example: the correction keeps moving off the individual run and into the scaffolding around it. At every example, ask what would have told them the change worked.

Three rings

The innermost ring is the code in front of you: a finding says the totals are wrong, you fix them, the tests go green. It buys exactly one diff.

The middle ring is the instructions. The same finding, read as a class rather than an incident, changes the spec or CLAUDE.md so the next run does not need telling again. The outer ring is the workflow: which gates the runner stops at, what the auditor reads, which model does which job. It pays the most, and it owes you evidence.

Three rings of improvement Three nested bands, each one wholly inside the next: the output ring, this diff, sits inside the instructions ring, the spec and CLAUDE.md, which sits inside the workflow ring, the runner, the gates, the auditor and the model. The two inner bands are plain: neither carries an arrow, and each is annotated with what it pays, once for the output and until the file changes for the instructions. The outer band carries a single arc that travels most of the way round the ring and comes back to its own start, with the arrowhead at the join and a short tick at the foot of the ring marking where the measurement is taken; the arc is labelled re-run from a fresh copy, compare iteration counts. The workflow ring is therefore the only one of the three that closes back on itself. workflow — runner, gates, auditor, model instructions — spec and CLAUDE.md pays off until the file changes output — this diff pays off once re-run from a fresh copy compare iteration counts
Ring one buys one diff and ring two keeps paying until the file changes; only ring three closes back on itself, and only if you re-run from a fresh copy.

A critic that did not write the code

The session that just argued itself into a design is the worst reviewer of it: it holds the justification and none of the surprise. Claude Code gives you a critic outside that conversation as a file, .claude/agents/spec-auditor.md: Markdown with YAML frontmatter, reviewed like any other file.

A subagent starts with a fresh, isolated context window. It does not see your conversation, the skills you invoked, or the files Claude already read; it works from a delegation message Claude composes (a fork is the exception, inheriting the parent conversation). tools: Read, Glob, Grep limits the auditor to reading, so a bad audit costs a bad list, not a bad edit; omit the field and it inherits every tool. You invoke it by name, as @"spec-auditor (agent)", rather than hoping it gets picked. Built-in types such as Explore and Plan have never read your spec.

This lesson has one command, a read-only sed you run from day2-work, the lane copy Exercise 1's setup block made at the course root. It prints the auditor's frontmatter, one file for both lanes:

Swift lane
sed -n '1,6p' ../day-2-loops-and-your-environment/starter/agents/spec-auditor.md
Kotlin lane
sed -n '1,6p' ../day-2-loops-and-your-environment/starter/agents/spec-auditor.md

Give the critic the spec, not the story

An auditor pointed at a diff returns opinions; pointed at numbered criteria, it returns violations. The difference is one instruction: tag every finding with the criterion it violates, or NO-CRITERION when the spec is silent and the code chose. Name the spec in the prompt, because the auditor starts from the task it is handed; Exercise 2 gives you the full prompt.

That tag makes a finding routable. The NO-CRITERION findings are the valuable half: nothing is failing, and nobody else would have looked.

Ring two: where a finding goes

A finding tagged to an existing criterion is ring one: fix the code, and route it further only if the rule beneath it outlives this spec. The rest have three destinations: a new or sharpened acceptance criterion, where most NO-CRITERION findings belong because a criterion is testable; a line in the standing instructions, for a fact that outlives this change, such as a declined transaction counting toward no total; or the bin, with one sentence saying why.

Standing instructions grow under a net-zero line cap: to add a line to CLAUDE.md you remove at least one, the least valuable first, or you put the guidance in a path-scoped rule file, .claude/rules/<name>.md, whose paths: globs let it enter the window only when the agent reads a matching file. wc -l CLAUDE.md before and after is the enforcement; same or lower passes.

Ablation, not accumulation

To find out whether a line earns its place, take it out and see whether the mistake comes back. Boris Cherny described the same method for Claude Code's own system prompt, reported in August 2026 as cut by about 80 percent: a dated anecdote, not a target for your file.

Your version is one line out, one re-run, one answer. If the mistake returns, the line was working; if not, you were paying for it on every turn.

Ring three: measuring the workflow

Count the iterations before the change, apply your revised spec and CLAUDE.md to a fresh copy, re-run the same spec, and count again; Exercise 2 gives the step order.

Then state the result at its size: four iterations became two, on one spec, in one lane, n equals one. A useful team norm: a workflow change arrives with its two iteration counts and the spec they came from, or it arrives as a proposal.

Choosing a model per role

The critic and the worker need not share a model. The durable lever is a model: line in the agent file, taking sonnet, opus, haiku, fable, a full model id, or inherit; the shipped auditor says model: opus. The session lever is /model, with an alias or a picker where Enter saves the choice as your default and s applies it to this session only.

When you write your own agent file, include the model: line. Without it, the auditor may run on the calling session's model, and the expensive-reviewer, cheap-worker split collapses into one model reviewing itself.

When self-critique is theater

A critic with no spec returns taste, and taste is unroutable. If almost every finding comes back NO-CRITERION, sharpen the spec before you touch the agent file.

The other failure is an auditor that always finds something. Run it on a change you already accepted, where the right answer is nothing; findings there teach your team to skim. Tune it until that run is silent, or stop running it. And keep the rings in proportion: a one-line typo fix owes nobody a spec revision and a re-run. Skip the auditor entirely before a numbered spec exists, or on a diff you can read in a minute: a read-only opus pass there costs more than it returns.

Quick check

Your auditor returns nine findings and eight are tagged NO-CRITERION. What does that tell you to fix first?

The spec. Eight of the nine complaints are about behavior nobody wrote down, so they are preferences until a numbered criterion exists that a command can fail on.

You added four lines to CLAUDE.md after an audit and the next run was slower and no better. What does the net-zero rule ask of you?

Remove four lines, the least valuable first, before the new ones stay, or move the guidance into a path-scoped rule file, then re-run from a fresh copy and compare iteration counts before claiming the change helped.

Sources

Claude Code documentation, accessed 2026-09-22 against version 2.1.280, and 2026-09-23 for cc-core-38 and cc-core-40.