Llm self heal
Autonomous self-healing loop for leerie worker prompts that produced captured failures. For each call_type with failures, runs a measured n=N baseline (unpatched), then iterates: invoke patch-generator worker (claude -p) → apply proposed patch → replay patched arm → score → check convergence (SUCCESS/PLATEAUED/BUDGET_EXHAUSTED/TIMEOUT/REGRESSED). Writes a healing-<call_type>.md report per call_type with the best patch and the iteration history. Production prompts in prompts/ stay manual — the skill proposes patches with measured evidence.From its SKILL.md
npx -y skills add enricai/leerie --skill llm-self-healAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 10 stars10 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
11.9 KB, as published. Nobody here has run it
- Baseline — run n=N unpatched replays per failing sample via
claude -p, score each, establish noise floor. - Loop — invoke the patch-generator worker (a direct
claude -pcall) to propose a minimal patch to the system prompt, apply the patch, replay the patched arm, score, check convergence. - Report — write
<heal-dir>/<call_type>/healing-<call_type>.mdwith the verdict (SUCCESS / PLATEAUED / BUDGET_EXHAUSTED / TIMEOUT / REGRESSED), the best patch found, and the full iteration history.
Output: per call_type with failures, a heal report under the run's
<heal_subdir>/ directory (default heal-out/; configurable via
--heal-dir / LEERIE_HEAL_DIR / leerie.toml heal_dir).
Production prompts in prompts/ are NOT modified by this skill.
Patches are proposed evidence — applying them is a separate manual step.
</objective>
<execution_context>
Arguments parsed from $ARGUMENTS:
- First positional:
<run-id>or path to acalls.ndjsonfile or its parent directory. If a run-id is given, the skill resolves<state-root>/runs/<run-id>/calls.ndjsonand the corresponding heal output dir<state-root>/runs/<run-id>/heal-out/, where<state-root>is the resolved leerie state directory (default$HOME/.leerie/<basename>/, overridable viaLEERIE_STATE_DIR/--state-dir/leerie.toml state_dir;/leerie-stateinside the container) — never a path relative to CWD. --call-type <name>(optional): heal only this call_type; default heals all call_types that have failing verdicts in the verdict files found underjudge-out/.--verdict-dir <dir>(optional): where judge-llm-batch wrote its verdict JSON files. Defaults to<run-dir>/judge-out/.--heal-dir <dir>(optional): where to write heal-loop state and reports. Defaults to<run-dir>/heal-out/or the value resolved fromLEERIE_HEAL_DIR/leerie.toml heal_dir.--max-iterations <N>(default 10,HEAL_MAX_ROUNDS_DEFAULT): hard cap on loop iterations per call_type.--n-replays <N>(default 5,HEAL_N_REPLAYS_DEFAULT): replays per arm (baseline or each patched iteration) per failing sample.--success-threshold <0..1>(default 0.9,HEAL_SUCCESS_THRESHOLD_DEFAULT): pass-rate target for SUCCESS exit.--plateau-window <N>(default 3,HEAL_PLATEAU_WINDOW_DEFAULT): consecutive iterations of small delta → PLATEAUED exit.--plateau-delta <0..1>(default 0.03,HEAL_PLATEAU_DELTA_DEFAULT): "small delta" threshold in pass-rate units.--model <alias>(defaultsonnet,MODEL_DEFAULT_PER_WORKER["heal"]): model alias passed toclaude -pfor replay arms. Override viaLEERIE_MODEL_HEALor--heal-modelon the main orchestrator, or pass--modeldirectly to this skill invocation.
All default values match IMPLEMENTATION.md §2 "Heal-loop convergence parameters". </execution_context>
<context> Leerie records every `claude -p` worker invocation to `<state-root>/runs/<run-id>/calls.ndjson` (one line per call, appended immediately after each call returns). The judge-llm-batch skill produces verdict JSON files in `judge-out/`. This skill consumes those verdicts to close the loop: it replays failing samples against patched prompts to find a patch that raises the pass rate above the success threshold.call_type → prompt-file mapping
Each call_type has exactly one system-prompt source (IMPLEMENTATION.md §10):
| call_type | Prompt source |
|---|---|
| classifier | prompts/classifier.md |
| planner | prompts/planner.md |
| reconciler | prompts/reconciler.md |
| implementer | prompts/implementer.md |
| integrator | prompts/integrator.md |
| conformer | prompts/conformer.md |
The heal loop reads the current file from prompts/ as the base
prompt text for any call_type it heals.
Heal-loop on-disk state layout
Under <heal-dir>/<call_type>/:
state.json — loop state (history, best-so-far, baseline)
iter-<N>/
patch-request.json — inputs for the patch-generator worker (claude -p)
patch-response.json — worker's structured output
applied-patch.txt — the patched system prompt text
arm-results.json — n-replay results per failing sample
scores.json — per-sample per-replay pass/fail verdicts
This matches IMPLEMENTATION.md §8 "Coordination directory layout".
Replay mechanics
Each replay runs claude -p with:
--append-system-prompt <patched-prompt-text>(the prompt under test)--json-schema <schema>(the same schema used for this call_type in the live orchestrator, perSCHEMASinorchestrator/leerie.py)--model <model>(the heal model alias)- User content from the captured
user_contentfield
A replay passes when structured_output is present and schema-valid
(parsed_ok=true equivalent). Schema validity is the primary pass
criterion — the same bar the live orchestrator uses.
</context>
Step 1: Pre-flight
- Confirm CWD contains
orchestrator/leerie.pyandprompts/. If not, abort:llm-self-heal must run from the leerie repo root. - Resolve the input path. If a run-id string, check
<state-root>/runs/<run-id>/calls.ndjsonexists. If a directory or file path, resolve accordingly. - Confirm
judge-out/(or--verdict-dir) contains at least one*-verdicts.jsonfile withpass=falseentries. If none, emit:No failures found — nothing to heal.and stop. - Resolve
--call-type. If absent, collect all call_types that have failing verdict entries. - Estimate total cost:
failures × n_replays × 2 × max_iterationsLLM calls. Warn the user if this is large (>50 calls) before proceeding.
Step 2: Per-call_type loop
For each call_type in scope:
2a. Baseline
For each failing sample (those with pass=false in the verdict file):
- Extract
system_prompt,user_content, andcall_typefrom the matchingcalls.ndjsonline (join oncall_id). - Run
n_replaysunpatchedclaude -pcalls using the capturedsystem_promptverbatim. Record pass/fail for each. - Persist per-sample baseline pass rates to
<heal-dir>/<call_type>/state.json. - Samples that pass at majority vote in baseline are "noise-floor" cases — the captured failure didn't reproduce, so patch measurement is unreliable for them. Note them in the report.
2b. Iteration loop (until convergence or cap)
-
Read base prompt: load from
prompts/<call_type>.md. -
Build patch request: create
<heal-dir>/<call_type>/iter-N/patch-request.jsonwith:call_typecurrent_prompt(the current best prompt text — base on iter 0, the last applied patch on subsequent iterations)failing_samples(array of{call_id, user_content, captured_response, judge_rationale}for samples that still fail)prior_attempts(array of{iter, anchor, replacement, strategy, pass_rate}fromstate.jsonhistory)
-
Invoke patch-generator worker (
claude -p): run a direct headlessclaude -pcall — the same subprocess mechanism as the replay calls above (see "Replay mechanics"), not the Agent tool:claude -p \ --append-system-prompt "$(cat prompts/patch_generator.md)" \ --json-schema '<SCHEMAS["patch_generator"] from orchestrator/leerie.py>' \ --model <heal-model> \ "<contents of patch-request.json formatted as delimited sections>"The schema requires
{anchor, replacement}(both non-empty strings) with optional{strategy, pivot_reason}— matchingSCHEMAS["patch_generator"]inorchestrator/leerie.py. Write the worker's structured output to<heal-dir>/<call_type>/iter-N/patch-response.json. If the output is not valid JSON, retry once with a reminder to emit only the JSON envelope. -
Apply patch: validate that
anchoris a literal substring of the current prompt text — the same code-enforced checkrequest_patch()performs inorchestrator/leerie.py(per the prompts-are-advisory-code-enforces principle: this check must happen mechanically, not be trusted from the worker's output). Ifanchoris not found verbatim in the current prompt, skip this iteration and log a warning — do not apply a patch that cannot be cleanly located. Otherwise substituteanchor→replacementin the current prompt text and write the resulting prompt to<heal-dir>/<call_type>/iter-N/applied-patch.txt. -
Replay patched arm: for each failing sample, run
n_replaysclaude -pcalls against the patched prompt. Record pass/fail. Write to<heal-dir>/<call_type>/iter-N/arm-results.jsonandscores.json. -
Score and check convergence: compute pass rate across all non-noise-floor samples for this iteration.
pass_rate ≥ success_threshold→ SUCCESS, stop.- Iterations within
plateau_windowall have|Δpass_rate| < plateau_delta→ PLATEAUED, stop. iter == max_iterations→ BUDGET_EXHAUSTED, stop.- Pass rate dropped vs. prior best by >
plateau_deltaforplateau_windowconsecutive iters → REGRESSED, stop. - Otherwise → CONTINUE.
Update
state.jsonwith this iteration's result and best-so-far.
2c. Write report
Write <heal-dir>/<call_type>/healing-<call_type>.md with:
# Heal report: <call_type>
**Verdict:** SUCCESS | PLATEAUED | BUDGET_EXHAUSTED | TIMEOUT | REGRESSED
**Best pass rate:** <P>% (iter <N>)
**Baseline pass rate:** <B>%
**Iterations run:** <N>
## Best patch
**Anchor:**
<anchor text>
```
Replacement:
<replacement text>
Strategy: <one-line description>
Iteration history
| iter | pass_rate | delta | verdict |
|---|---|---|---|
| 0 (baseline) | <B>% | — | — |
| 1 | <P1>% | <Δ> | CONTINUE |
| ... |
Notes
<noise-floor note if any samples didn't reproduce> <structural-scoring warning if applicable>
## Step 3: Emit summary
For each call_type processed:
[<call_type>] iterations=<N> verdict=<X> best_pass_rate=<P>% → <heal-dir>/<call_type>/healing-<call_type>.md
Then stop. Do not apply any patch to `prompts/`.
</workflow>
<safety_constraints>
- This skill reads NDJSON captures, verdict JSON, and prompt files
- This skill writes only into `<heal-dir>/<call_type>/`
- This skill does NOT modify `prompts/*.md` or `orchestrator/leerie.py`
- Patches are proposed with measured evidence — applying them is a
separate manual step the user performs after reviewing the report
- Replays make real `claude -p` calls using the user's subscription
- The skill warns the user before starting if the estimated call count
is large (>50 calls)
</safety_constraints>
<example_invocations>
Heal all call_types with failures in a run:
/leerie:llm-self-heal fix-login-timeout-bug-b81e90
Heal only the implementer call_type:
/leerie:llm-self-heal fix-login-timeout-bug-b81e90 --call-type implementer
Heal with tighter budget:
/leerie:llm-self-heal fix-login-timeout-bug-b81e90
--call-type planner
--max-iterations 5
--success-threshold 0.85
</example_invocations>