Self-Regeneration — the recursive self-improvement loop
This doc is the loop. The two self-modification surfaces it drives already exist: self-improvement.md (weights — LoRA hot-swap) and self-modification.md (code — staging-clone + verify + PR). What's been missing is the closed,…
f7a8cb56
View source ↗
The threshold that matters isn’t a chat demo — it’s AI becoming part of the loop that improves AI. For an agent harness, that means: Prax autonomously produces a better version of its own scaffolding (tools, prompts, routing, skills) — and proves it’s better before adopting it.
This doc is the loop. The two self-modification surfaces it drives already exist: self-improvement.md (weights — LoRA hot-swap) and self-modification.md (code — staging-clone + verify + PR). What’s been missing is the closed, autonomous, safe loop that ties them to a fitness function.
Scope it right: harness self-improvement, not model self-improvement
“Make a better version of yourself” reads as “rewrite my weights” — but that needs frontier training infra Prax will never own (it’s a model consumer + narrow LoRA fine-tuner). Prax’s achievable — and correct — target is its harness: the tools, prompts, routing, skills, and evals where most agent leverage actually lives (see harness-engineering). The goal is “Prax produces a better version of its own scaffolding, verified,” not “Prax retrains a frontier model.”
The load-bearing truth: the fitness function is the whole game
Recursive self-improvement optimizes brutally against whatever measures “better.” Goodhart isn’t a footnote — it’s the danger. An agent told “improve yourself,” pointed at a gameable eval, produces a version that games the eval (the METR “environment cheating” finding — prax-benchmarks §6 — at the self level). So:
RSI is only as safe as its fitness function is un-gameable. The un-gameable-eval work is the precondition for letting Prax touch itself at all — not quality hygiene.
This reframes Prax’s readiness. The easy half of RSI — surfaces to change itself —
Prax has (plugin_write, prompt-as-file, finetune_service, sandbox + make ci).
Everyone has that now. The hard half — a fitness function that survives an
optimizer attacking it, plus safe graded adoption — is exactly what’s been built:
deterministic verify, the supervising
auditor, accept-rate not
self-report (#22), the “never spike / fix the problem class”
rule, and flag-gated-default-off rollout + durable checkpoints. That stack is the
RSI substrate.
The loop (mapped to what Prax has)
Notice → Propose → Isolate → Verify → Canary-adopt → Rollback / Record, run by Prax on itself:
- Notice — a concrete weakness from the eval/signal stack, not vibes: a
failing golden, a recurring failure (
metacognitive.py≥3), a low accept-rate behavior (#22), a pass/fail trace-diff (#19). ✅ inputs exist. - Propose — an abstracted fix (never-spike): a prompt edit, a new/edited
plugin (
plugin_write), a routing tweak, a LoRA. ⚠️ have code-authoring; no systematic prompt/routing proposer yet. - Isolate — apply it in a sandbox / git worktree. ✅.
- Verify —
make ci(correctness/lint) +make eval(goldens, gaming-resistant). Adopt only if it improves without regressing or spiking. ✅✅ the over-invested part — correctly. - Canary-adopt — flag-gated default-off → measure accept-rate on real traffic (#22) → promote or roll back (checkpoints). ✅ substrate.
- Record / compound — log what kind of change helped as a signal/skill (#17, #23) so the loop learns its own improvement priors. ⚠️ tracked, not closed.
The missing piece is the orchestrator — which is #23 (the ambient initiative loop) pointed at Prax itself, governed by #22. The engine is designed; it isn’t aimed inward yet.
The prompt-overlay loop as built (prax/eval/self_regen.py)
The first loop that exists is narrower than the plugin rung below: it edits a
system-prompt overlay and is graded by the deterministic capability suite.
It is propose-only unless --apply and SELF_REGEN_ENABLED are both set, and
nothing calls it but the CLI:
uv run python scripts/eval_suite.py self-regen --rounds 5 --revise-kept --split --keep-replicates 2
What it enforces, whatever the mode:
- The scorer is fingerprinted before and after: the capability cases, the generators, the goldens and the loop itself. If any moved mid-run, nothing is kept.
- The keep decision needs a margin of at least one case, or an Occam tie (shorter at equal score).
- The winner must pass the private golden split (
accept_change), measured against a replicate noise floor. Without private goldens it fails closed. - Two vetoes run before any evaluation:
- deterministic: over-length patches, and patches containing an answer number
from any check,
regexchecks included; - an LLM auditor, on the full patch.
- deterministic: over-length patches, and patches containing an answer number
from any check,
Two protocol options (both off by default; harness learning is the evidence for both):
| Flag | What changes |
|---|---|
--split |
Three disjoint case sets. The pool is the authored suite plus generated cases (prax/eval/case_generators.py; --generated per family, computation only today), split within each family (split_cases). The proposer sees the feedback set’s failures: the task, the answer given, the checks missed. A change is kept only on the disjoint scoring set. The private goldens stay the held-out set. A one-case family is scored, never shown. |
--revise-kept |
Each round revises the kept overlay, with a fresh report from running it, instead of drawing an independent addition from one fixed signal. |
--keep-replicates N |
The baseline and every candidate are scored N times. A change is kept only if its mean gain beats the margin and the measured run-to-run spread (the larger of the incumbent’s and the candidate’s). Without it, one execution decides: MASS recorded an identical prompt and seed winning 6–0 and then losing 0–6. |
Without --split, the proposer still sees only dimension averages: hiding the
cases is the only defence against memorizing them when the same cases decide
the keep. With --split, that defence is the measurement. A fix that works
only on the cases shown earns nothing on the scoring set.
Every proposal is recorded in revisions.jsonl beside the run’s
summary.json, in every mode:
- the exact proposer input;
- the patch, and its parent;
- the measured score and delta;
- the vetoes and the audit;
- whether it was kept;
- the case ids on each side.
That is the (context, edit, reward) record a trained proposer learns from: SFT
on kept revisions, RL on all of them. It accumulates now, for when a training
GPU is available. Held-out content never enters a proposer input, so it never
enters the record. The files live in $PRAX_EVAL_DIR (data only, never
committed); prax-eval-battery is the private place to back them up.
Model weights. “Never own training infra” above is about frontier models. A small proposer that edits the harness, with the agent’s model frozen, is a different size of job: the harness-learning paper trained a 4B one. It is parked until a GPU is free, not declined.
The two things that make it safe (the real bottleneck — not code-writing)
- A graded self-modification boundary (the capability-gateway / tool-risk model
applied to self-changes, deny-by-default):
- Low risk (a new/edited plugin/tool) → auto-adopt behind the eval gate.
- Medium (prompt tweak) → canary + accept-rate gate.
- High (orchestrator policy, weights) → human gate (the existing self-modification.md PR path).
- Blast-radius containment — every self-change reversible (durable checkpoints), canaried, with accept-rate (#22) as the early-warning tripwire.
The first rung (small, bounded, uses only what exists)
Close the loop on the lowest-risk, most-measurable self-change: Prax proposes + tests a new/edited plugin against a golden, auto-adopting behind a flag only if it improves the eval without regression. That’s “make a better version of one of my tools, proven” — a genuine RSI micro-loop. Prove the fitness function holds there, then widen scope to prompts, then routing. Tracked as IDEAS_BACKLOG #29.
The line not to cross (yet)
Autonomous edits to the orchestrator policy / system prompt, before the fitness function is proven un-gameable. That’s where a gamed eval turns self-improvement into confident self-degradation — undetectable precisely because the grader is the thing being corrupted. Widen autonomy only as fast as the fitness function earns trust; until then, high-risk self-changes stay on the human-gated PR path.
Bottom line
Prax’s gating resource for “AI in the loop that improves AI” is not capability to change itself — it has that. It’s a measure of “better” that survives an optimizer attacking it, plus a safe graded-adoption boundary. Both are unusually far along. What remains is the one spoke that closes the loop inward (#29) and the discipline to widen its autonomy only as the eval proves un-gameable.