It improves itself. It doesn't grade itself.
What recursive self-improvement is in plain terms, how to keep a human on the loop instead of in it, and the lessons that cost me the most: separate the ruler from the thing it measures, measure first, fail loudly, and earn autonomy on evidence.

I've been building a system that improves itself, and running it in production for a while. This is what I'd tell a colleague who is about to try the same. Short on theory, long on the parts that bit me.
What RSI actually is

Recursive self-improvement sounds like science fiction. In practice it's a boring loop, and the boring part is the point.
- Harvest. The system notices its own failures: a task that went wrong, a retry, a human correction.
- Propose. It drafts one small change to itself. A prompt, a routing rule, a check.
- Review. A second pass reads the proposal and throws out the obviously bad ones.
- Admit. The change is replayed on held-out cases it never trained on. It gets in only if it measurably helps.
- Land. It becomes an ordinary pull request.
- Merge. CI and a gate decide, with a human in the loop for anything that matters.
- Retain. The change stays only while the scoreboard says it earns its keep.
- Rollback. If it doesn't, it comes back out. Automatically.
Nothing in that list is magic. Every step is something you already do by hand. The loop just does it at 3 a.m. and writes down what happened.
The hard part is the word "measurably." That one word is where most of what follows comes from.
Never let it grade itself

A system that edits itself and also decides whether the edit was good will always find that the edit was good. Give it enough rounds and it will find the shortest path to a higher score, and that path will not be the one you wanted.
So I split the loop in two. There is the thing being measured, and there is the ruler. The proposer can change the first. It can't touch the second.
What lives on the ruler's side:
- Held-out cases. Examples the proposer never saw while drafting. If it can see the test, it will fit the test.
- Invariants. A short list of things that must stay true no matter what the change does. A change that breaks one is rejected before any score is computed.
- The scoring code itself. It sits behind the same wall. Changes to the ruler go through a separate path, with a human, and never as a side effect of a self-improvement round.
If you take one thing from this post, take that. Everything else is tuning.
Measure before you automate
The tempting order is to build the loop, then work out whether it's helping. It's backwards. Before the loop proposes anything, you need a baseline: what the system does today, on a fixed set of cases, with a number you can compare against next week. A scorecard, even a crude one.
Without it, every improvement is an anecdote. With it, you find out that half of your "obvious wins" move nothing, and that a few boring changes move a lot. You also find out when the loop is quietly making things worse, which is the case you most want to catch.
Write the scorecard first. Automate second.
HITL, HOTL, and the ladder between them

Two terms people mix up.
Human in the loop (HITL): a person approves every change before it ships. Safe, slow, and it stops scaling the day the loop produces more changes than you can read.
Human on the loop (HOTL): the system acts inside bounds you set. The human watches the scoreboard, reads the alerts, and holds the kill switch. They don't approve each change. They approve the policy, and they can stop everything.
You don't pick one. You climb from the first to the second, and each step has to be earned.
- Start supervised. For the first N changes, a human reviews every one. N is small and fixed in advance.
- Promote on evidence. Moving up a step needs a certificate: a record of how many changes landed, how many held up on the scoreboard, how many had to be rolled back. A person signs it. Nobody gets promoted by editing a config file.
- Demote on evidence too. A bad stretch moves the system back down a step.
The certificate matters more than it sounds. If autonomy is a setting, then autonomy is whatever somebody last typed at 11 p.m. A certificate leaves a trail, and it's hard to produce by accident.
What always stays human
Some decisions don't move down the ladder, whatever the evidence says.
- Money. Anything that spends it or commits to spending it.
- Personal projects. Anything that ships under your own name or to your own users. You decide what goes out.
- The rules that grade the loop. The ruler from the section above.
The reason is accountability. When one of these goes wrong, someone has to answer for it, and a model can't.
The brake

A loop that can ship changes needs a way to stop shipping them.
Mine has tripwires. If the scoreboard regresses past a threshold, or too many changes get rolled back in a row, the loop freezes. It stops proposing and stops landing. It keeps harvesting, so I still know what's failing.
The freeze can be cleared by a human, and only by a human. The loop can't clear it, and neither can the process that tripped it. It's tempting to add an auto-clear with a cooldown. Don't. If the thing that tripped the brake can also release it, a single bug can do both.
A brake you can't trust is worse than no brake, because you stop watching.
Several tools, one loop

The loop runs on a few models and tools, each doing the job it's good at.
- A judgment tier for the work that needs real reasoning: reading a failure cluster, drafting a fix, reviewing a diff. It's the slowest and most expensive, so it only sees what survives the layers below.
- Cheaper tiers for the bulk: summarising logs, formatting, first-pass extraction.
- Failover between providers. One provider has a bad hour, or hits a rate limit, and the loop moves on instead of stalling. Providers fail more often than you plan for.
- A fast typed-decision layer. This is where Jev fits.
If you read my earlier post, you know the idea. Jev doesn't write. It picks one option from a list you define, and tells you how sure it is. A call takes a fraction of a second and costs almost nothing.
That's the right shape for the cheap, frequent, small decisions inside a loop like this:
- Classify a failure: is this a real bug, a flaky test, or a one-off?
- Route a request: which tier should handle this?
- Yes or no: is this cluster worth a round of the expensive proposer?
- Score a proposal: does it look worth replaying?
A lot of what a self-improving system does all day is exactly this. It doesn't need a paragraph. It needs a pick.
Where Jev doesn't go
One rule, and I won't bend it. A single Jev probability never approves money, a merge, or a deploy.
Jev's output is advisory. It can decide what gets looked at first. It can't decide what ships. That belongs to the held-out replay and the gates, and to a human where the section above says so. A calibrated 95% is still a 1-in-20 chance of being wrong, and you don't want a 1-in-20 chance on a deploy.
It's also worth saying that "can't make up an answer outside the list" is not the same as "picks the right one." That second part you still have to measure.
Silent failure is worse than loud failure
The scariest bug in a loop like this isn't a crash. It's a step that fails, swallows its own exception, and returns an empty result. The next stage reads "no failures found" and reports a healthy week.
A system that fails loudly gets fixed in an hour. A system that fails quietly gets trusted for a month.
What helped:
- Empty is suspicious. If a stage that usually finds something finds nothing, that is an alert, not good news.
- Unknown is an error. A model name it doesn't recognise, a field it can't parse, a case it can't classify: fail loudly rather than fall back to a default.
- Heartbeats. Every long-running piece writes a timestamp. A stale one pages someone.
Communication is part of the system

If the operator can't understand the alerts, you don't have an operator. You have a logging system and a person who has learned to ignore it.
Accurate alerts can still be useless. Stack traces, internal names, a wall of detail: people stop reading them, and that's the moment the loop becomes unsafe.
What works:
- Plain English. One or two sentences a non-specialist could act on.
- Important only. If it doesn't need a decision or signal a risk, it goes in the weekly summary, not in my pocket.
- Say what's needed. Every alert states whether I have to do something, and what the system will do if I don't.
- Make it visual. A small trend line tells me more in a second than three paragraphs of numbers.
This is a design problem as much as an engineering one, and it deserves the same care as the loop itself.
Agents and tests can hurt the host

A system that runs code to test its own changes will eventually run code that does something nasty. A test that signals a process group. A cleanup that deletes the wrong directory. A tool call that "helpfully" kills things.
I learned this the annoying way: a test suite that exercised a process-killing path logged me out of my own machine, more than once. The code was fine. The tests were fine. The environment they ran in was the real one.
So:
- Sandbox everything the loop runs, including its tests. Throwaway directories, throwaway processes, no access to the real thing.
- Guard destructive calls. Kill, delete, overwrite and network-write calls go through a shim that refuses unless it's explicitly inside the sandbox.
- Assume the agent will try it. It won't be malicious. It will be enthusiastic.
Autonomy is earned, not configured
If I had to put the whole post in one sentence: autonomy is a number you earn from evidence, not a flag you flip.
- The system starts supervised.
- It gets more room as the scoreboard shows it deserves it.
- A human signs each promotion.
- The ruler, the money and your personal projects stay with people.
- One tripwire can pull it all back in a second.
None of that limits what the system can do. It's what makes it safe to leave running.
How to start
If you want to try this, here's the order I'd do it in.
- Pick one narrow failure you see every week. Not "improve the system." Something like "this class of request gets routed wrong."
- Build the scorecard. Fifty held-out cases and a number. Run it by hand twice and check it's stable.
- Write the invariants. Three to five things a change must never break.
- Do the loop by hand. You harvest, you propose, you replay. Get a feel for what a good change looks like before you automate any step.
- Automate one step at a time, starting with the cheapest. Harvest first, then triage.
- Add the brake before the autonomy. A tripwire and a freeze only a human can clear.
- Stay supervised for the first N changes. Decide N before you start.
- Make the alerts readable. Then promote on evidence, and keep every certificate.
You'll go slower than you want to. The loop you end up with is one you can leave running.