The self-improvement loop¶
mini-ork can modify its own prompts, workflows and code — but only through a loop that measures every change against a held-out probe set before it lands. There is no human approval branch in the promotion path: a change is promoted on a real improvement, or quarantined with its reason. That makes the measurement, not the reviewer, the safety property.
Read this before enabling anything
The loop can rewrite prompts and workflows and promote the change without
asking. It ships off by default, and the apply path is gated by
MO_APPLY_ENABLED. If you enable it, the backstop is rollback and version
control — not review. See Security model.
Two loops, one principle¶
| Loop | Command | What it changes | Cadence |
|---|---|---|---|
| Outer self-improve | mini-ork self-improve |
The mini-ork checkout itself: code, prompts, recipes | Hours, capped by wall clock |
| Apply loop | improve → eval → promote → apply |
A prompt directive or workflow node selected from measured evidence | Per candidate |
Both obey the same rule: no measurement, no promotion.
The outer loop¶
mini-ork self-improve drives the recursive-self-improve recipe against the
mini-ork checkout. One iteration:
flowchart TD
S[bottleneck scanner] --> L1[perf lens]
S --> L2[correctness lens]
S --> L3[architecture lens]
S --> L4[research lens]
L1 --> SYN[synthesizer: ranked patch plan]
L2 --> SYN
L3 --> SYN
L4 --> SYN
SYN --> IMP[implementer: top patch]
IMP --> V1{bottlenecks found?}
V1 --> V2{self tests pass?}
V2 --> V3{no regression?}
V3 -->|all pass| C[commit on self-improve/iter-* branch]
V3 -->|fail| RB[rollback, branch left for inspection]
Usage¶
| Flag | Default | Meaning |
|---|---|---|
--soft-cap-hours <H> |
3 |
Finish the current iteration, then stop |
--hard-cap-hours <H> |
5 |
Kill mid-iteration and exit |
--max-iters <N> |
unbounded | Also bound the number of iterations |
--auto-merge |
off | Merge successful iterations into the parent branch |
--parent-branch <ref> |
resolved base ref | Branch to merge into when --auto-merge is set |
--dry-run |
off | Plan + scan, then exit before any model dispatch |
--resume |
off | Continue an interrupted session from the last recorded iteration |
--resume reads MINI_ORK_DB to find the last iteration. The first thing to run
on any new machine is the dry run: it proves the wiring without spending money.
Isolation and the verify-before-commit rule¶
- Worktree per iteration. Each iteration runs in its own worktree on a
fresh branch (
self-improve/iter-<N>-<ts>). - The implementer never commits. The agent writes the patch and a
regression test; the runner is the only process that calls
git commit, and only after all verifiers pass. - Branches stay quarantined unless
--auto-mergeis passed. A failed iteration leaves the branch intact for inspection. - One patch per iteration. The rollback model assumes a single point of failure.
The triple gate before a commit:
| Gate | Checks |
|---|---|
| Bottlenecks found | The synthesis contains at least one ranked patch and no leaked agent envelopes |
| Self-tests pass | Every existing test suite still passes; zero suites is a failure, not a pass |
| No regression | Changed shell files parse, benchmark utility is non-negative, and the implementer did not report refused-* or failed-* |
Budgets¶
The outer loop honours the same cost governance as any run. Defaults in the recipe's agent profile are a per-iteration cap, a per-session cap, and a global daily cap. A session with a 3-hour budget typically runs 3–4 iterations; a 5-hour budget runs 5–7. The synthesizer dominates the per-iteration cost.
Raise caps deliberately. The hard cap is enforced with timeout, so an
unresponsive provider cannot extend a session past its wall clock.
State and cross-iteration learning¶
State lives in $MINI_ORK_DB:
| Table | Row per | Use |
|---|---|---|
self_improve_runs |
iteration | Outcome, deadlines, branch, notes |
learning_record |
ranked bottleneck | open → queued → attempted → resolved \| rejected \| deferred |
self_improve_arxiv_refs |
cited paper | used_in_patch flips when a technique actually lands |
sqlite3 .mini-ork/state.db \
"SELECT iter, outcome, notes FROM self_improve_runs ORDER BY iter;"
sqlite3 .mini-ork/state.db \
"SELECT iter, category, title, outcome, severity, confidence
FROM learning_record ORDER BY iter, rank;"
The apply loop¶
The apply loop turns a proposed change into a scored candidate and decides whether it may rewrite its target.
mini-ork improve # propose candidates
mini-ork eval --candidate <id> # score a candidate
mini-ork promote --candidate <id># promotion gate decision
mini-ork apply --task-class <name> --target <file>
What apply does¶
apply takes the highest-confidence proposed change for a target, scores it on a
frozen probe set, and either rewrites the prompt file (on promote) or quarantines
it with the regression reason.
| Flag | Default | Meaning |
|---|---|---|
--task-class <name> |
required | Which task class the directive belongs to |
--target <file> |
required | File the change would rewrite |
--target-kind |
prompt_file |
prompt_file, agent_prompt, workflow_node, workflow_edge |
--scorer |
probe |
probe (promotable), mock / gepa (test-only) |
--dry-run |
off | Score and report without writing |
--enable |
off | Set MO_APPLY_ENABLED=1 for this call |
Only probe is promotable. The mock and gepa scorers fabricate or neutralise
utility and can never approve a change — a promote on fabricated numbers is
indistinguishable in the audit trail from a measured one, so it is refused
outright.
Reverting unearned directives¶
The only-verified-learnings rule has a second half: directives that were not earned by a measured promote can be removed.
mini-ork apply --revert-unverified --dry-run
mini-ork apply --revert-unverified --files-only
mini-ork apply --revert-unverified --db-only --include-home
--files-onlyedits prompt files without a database write.--db-onlyrecords removals from database state alone (for use after a merge, when on-disk markers are gone).--include-homealso scans the project overlay under<home>/recipes, which a run reads before<root>/recipes.
What the loop will not do¶
- Promote without a held-out measurement.
- Promote a candidate scored by a fabricating scorer.
- Re-propose a directive that was quarantined or rejected (spend containment).
- Modify
maindirectly in the outer loop; auto-merge is explicit. - Merge a failed iteration; the branch is left for inspection.
- Apply new infrastructure without supporting evidence where the recipe requires it (a graph database, a new helper tool, a new table).
Failure modes¶
| Symptom | Likely cause | Fix |
|---|---|---|
| Exits immediately | Soft cap greater than hard cap | Fix the flags |
Iteration timed_out |
One model call hung | Inspect the run log; lower the per-iteration budget |
Iteration failed |
Scanner found nothing actionable | Inspect the bottleneck scan; seed a target manually |
All iterations rejected |
The patch cannot satisfy verifiers | Read the implementer report and the patch |
| Loop converges after one iteration | The code is stable enough that nothing ranks | This is success |
| Apply always quarantines | No probe measurement exists | Add probe tasks, or check the scorer invocation |
| Database migration fails at start | sqlite3 missing |
Install it |
Related¶
- Learning loop — how routing learns from verified runs.
- Failure triage — turning a failed run into a fix.
- Feature flags — every
MO_*gate. - Security model — the trust boundaries behind the warning.