Help us improve
Share bugs, ideas, or general feedback.
From lich-skills
Runs a command repeatedly, fixing errors one at a time until it exits with code 0. Use when build, typecheck, lint, or test is failing.
npx claudepluginhub lichamnesia/lich-skills --plugin lich-skillsHow this skill is triggered — by the user, by Claude, or both
Slash command
/lich-skills:build-until-passThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
A bounded self-correcting loop: run the project's check command, capture its
Autonomous iteration loops for .NET: build-fix, test-fix, refactor, scaffold. Bounded iterations and progress detection prevent infinite retries.
Share bugs, ideas, or general feedback.
A bounded self-correcting loop: run the project's check command, capture its errors, apply the smallest diff that addresses the first failure, re-run, and repeat until it exits 0 — or until a hard attempt cap is hit.
The core principle: the check command is the judge, not you. You do not
declare the build "basically fixed." Green is exit code 0. Anything else is
red, and red means another round.
This is the engineering-discipline counterpart to "run it and hope." The cap exists so the agent backs off instead of burning tokens thrashing on an error it cannot fix without human input.
tsc, cargo build, go build, npm run build, vite build exits non-zerodebug-hypothesis instead, then come back here to confirm green// @ts-ignore-ing real errors, or
loosening types to silence the compiler → that's cheating the judge, not
passing it (see Anti-rationalizations) ┌─────────────────────────────────────────────┐
│ attempt > MAX_ATTEMPTS (default 10)? │
│ → STOP, report what's left, ask the human │
└──────────────────────┬──────────────────────┘
│ no
RUN CHECK ──▶ green? ──yes──▶ DONE (exit 0, report rounds used)
▲ │
│ │ no (red)
│ ▼
│ READ ERRORS ──▶ FIX SMALLEST ──▶ re-RUN
│ first failure minimal diff, │
│ only, verbatim no refactor │
└──────────────────────────────────────────────┘
one round = one fix + one re-run
Hard rules:
exit code 0 from the check command. Not "looks fixed," not
"the error I saw is gone." Run it and read the exit status.round N/MAX — <errors remaining> — <what I changed>.@ts-ignore, any,
deleting a test, || true) is not a pass. See Anti-rationalizations.Goal. Know exactly what command defines "green" before you touch any code.
Steps.
.github/workflows/*), package.json scripts,
Makefile, justfile, the build tool's convention.build vs typecheck vs test), pick the one
the user named; if unstated, pick the narrowest one that reproduces the
reported failure, and state your choice.MAX_ATTEMPTS (default 10 unless the user gave a number).Exit criteria.
MAX_ATTEMPTS setCommon Rationalizations
| Excuse | Reality |
|---|---|
"I'll just run npm run build, it's always that" | It's tsc -b in half of repos and a custom script in the other half. Read package.json — 5 seconds saves a loop spent fixing the wrong thing. |
| "I don't need the baseline, I know it fails" | Then capturing it costs one run and proves the failure mode you're about to fix is the one that's actually there. |
| "I'll set the cap later" | No cap means no stop condition. Set it now or the loop has no floor. |
Goal. Get the current ground truth: exit code + full error output.
Steps.
0 → jump to Done. Non-zero → continue.Exit criteria.
Goal. Apply the minimum change that resolves the first failure.
Steps.
file:line. Read the surrounding code.Exit criteria.
Common Rationalizations
| Excuse | Reality |
|---|---|
"@ts-ignore / # type: ignore / any makes the error go away" | The error going away isn't the goal — the code being correct is. Suppressing it ships the bug with a green check on top. That's worse than red. |
| "I'll delete the failing test, then it passes" | The test is the judge for behavior. Deleting it doesn't fix the build, it blinds it. If the test is genuinely wrong, say so to the human — don't silently remove it. |
| "Let me refactor this whole file while I'm in here" | Now your diff has the fix tangled with 80 lines of churn. When the next round goes red, you can't tell which change caused it. Fix the one line. |
| "I'll fix all five errors at once to save rounds" | If the build then breaks differently, you've lost the mapping from change to effect. One fix, one run — the loop is cheap, untangling regressions is not. |
| "Loosening the type silences it" | Loosening the type to pass a typecheck defeats the entire reason the typecheck exists. The judge is now rubber-stamping. |
Goal. Decide: done, another round, or stop and escalate.
Steps.
debug-hypothesis is needed. Don't spend the remaining rounds thrashing.Report format (one line per round):
round 3/10 — 4 errors left (was 7) — fixed missing `await` in db.ts:42
Exit criteria.
Common Rationalizations
| Excuse | Reality |
|---|---|
| "9 rounds in, just let me do a couple more" | The cap is the stop condition. Hitting it means this isn't a mechanical fix — it needs a human decision or real investigation. More blind rounds burn tokens, not bugs. |
| "The error count went up but I'm close" | Going up is the opposite of converging. Stop and look at why your fixes create new errors — your model of the failure is wrong. |
| "It's the same error as round 2 but I'll try a different fix" | You're oscillating. Two different fixes for one persistent error means you don't understand the error. Switch to debug-hypothesis. |
| "I'll just ` |
Hitting the cap (or stopping early) is a legitimate, expected outcome — not a failure of the skill. Report:
Then hand back. A human unblocking one root cause is faster than the agent blindly trying fix #11.
The skill was applied correctly when:
The two failure modes this skill guards against:
Run the judge. Read the first error. Fix the one thing. Run again. Stop at the cap.