Skip to content

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

mini-ork self-improve --dry-run --max-iters 1
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

  1. Worktree per iteration. Each iteration runs in its own worktree on a fresh branch (self-improve/iter-<N>-<ts>).
  2. 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.
  3. Branches stay quarantined unless --auto-merge is passed. A failed iteration leaves the branch intact for inspection.
  4. 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.

mini-ork apply --task-class code_fix --target recipes/code-fix/prompts/implementer.md
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-only edits prompt files without a database write.
  • --db-only records removals from database state alone (for use after a merge, when on-disk markers are gone).
  • --include-home also 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 main directly 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