| name | ralph-loop |
| description | Scaffolds and runs a Ralph Wiggum loop — Geoff Huntley's "stupid simple while-loop" pattern for autonomous overnight coding sessions. Authors PROMPT.md + fix_plan.md + ralph.sh, gates them through a plan review, then runs `while: cat PROMPT.md | claude -p` in a fresh context window per iteration (defeats compaction + context-rot). Useful for long worklists with clear acceptance criteria (test suite passes, fix_plan items checked off), reverse-engineering, spec-driven refactors, "fix all the failing crons overnight" sweeps. Composes with `/cortex-goal` — Ralph is the third option alongside native `/loop` (interval-based) + `/goal` (haiku-verifier). Inherits cortex-x R1+R2 discipline, cost ceilings, and the operator killswitch file. Triggers (EN+CZ) "/ralph-loop", "/ralph", "ralph wiggum", "run ralph", "spusť ralph", "loop until done", "loop dokud nebude hotovo", "overnight loop", "autonomous overnight", "fix all X until tests pass", "oprav všechny X dokud projdou testy", "vibe-clone". |
/ralph-loop — Ralph Wiggum autonomous loop scaffolder + runner
Status: v0-experimental (2026-05-25). The R2 security review flagged this skill as carrying the canonical lethal-trifecta blueprint when run with --dangerously-skip-permissions. Do not run on production code or any repo where you cannot git reset --hard to recover. See § Known risks v0 at the bottom of this document. Hardened path forward in references/cost-discipline.md § Roadmap.
Voice charter: see standards/voice.md. No greetings, no emoji, counts-not-praise. When invoked you are scaffolding a real shell loop that will spend real money — observe + tune, not perform.
Grounded in Geoff Huntley's June 2025 pattern (ghuntley.com/ralph/) and the HumanLayer post-mortems. Key insight: a one-line shell loop with a fresh context window per iteration outperforms multi-agent orchestration on convergent worklists because it defeats compaction and context-rot. The skill is mostly discipline, not code — the loop itself is 3 lines of bash.
When to invoke
/ralph-loop or /ralph explicit invocation
- "loop until done" / "loop dokud nebude hotovo"
- "overnight" / "autonomous overnight" / "weekend run" / "běhej v noci"
- "fix all X until tests pass" / "oprav všechny X" / "ship them all"
- "vibe-clone" / "reverse-engineer X into specs"
- After an audit produces a long fix_plan and the operator wants it done overnight
Don't invoke for:
- Single-shot tasks (use direct chat — overhead not worth it)
- Tasks without an automated verifier (no
npm test / no acceptance criterion → loop drifts forever)
- High-stakes prod code with no rollback (DB migrations, payment flows, anything irreversible)
- Ambiguous specs ("make it better" — garbage in → infinite iteration)
- Codebases the loop user can't
git reset --hard (no recovery path)
How Ralph differs from /loop and /goal
| When to use | Context window | Termination |
|---|
/loop (Claude Code native) | Recurring poll on interval ("check deploy every 5 min") | Reuses session context across iterations | Operator stops |
/goal (Claude Code native) | Long focused session 14h–5d on one acceptance frontier | Single context with haiku verifier | Verifier emits COMPLETE |
/ralph-loop (this skill) | Convergent worklist, fresh context per iteration | Brand new context every loop | fix_plan.md empty OR completion-promise OR max-iterations OR circuit breakers |
Ralph's unique value = the fresh context window per iteration. /loop and /goal reuse session context, so they rot on long worklists. Ralph re-injects the same artifacts (PROMPT.md + fix_plan.md + specs/) into a blank window each loop — every iteration starts fresh.
Phase 0 — Pre-flight refuse-conditions
Before scaffolding any artifacts, check all 6 conditions. If any fails, refuse with a specific reason — don't bargain.
| Condition | Check | Fix if fails |
|---|
| Git tree clean | git status --porcelain empty | Commit/stash work first |
| Branch is not main | git branch --show-current ≠ main (Ralph commits per iteration) | git switch -c ralph/<usecase> |
| Test harness exists | npm test / pytest / equivalent succeeds today | No test = no termination signal; refuse |
STEWARD_HALT killswitch absent | ~/.cortex/STEWARD_HALT doesn't exist | Operator chose to halt all spend — respect it |
| Daily cost cap headroom | Estimated cost (iterations × avg-tokens × model-price) ≤ remaining STEWARD_DAILY_USD_CAP | Lower iteration cap or wait until reset |
| Recovery point | The last commit must be a known-good baseline so git reset --hard HEAD~N is meaningful | Commit a baseline before scaffolding |
Surface a 6-row table back to the operator with each check pass/fail and the fix.
Phase 1 — Author the three artifacts
Ralph runs on three files. The skill writes all three into cortex/ralph/<usecase-slug>/ (gitignored — these are scratch).
1.1 — PROMPT.md (the loop body)
What the prompt does each iteration:
- Loads
fix_plan.md
- Loads
specs/ (if any)
- Picks the highest-priority unchecked item
- Searches the codebase (verbatim guardrail from Huntley: "Before making changes search codebase, don't assume not implemented")
- Implements it (verbatim guardrail: "DO NOT IMPLEMENT PLACEHOLDER OR SIMPLE IMPLEMENTATIONS. WE WANT FULL IMPLEMENTATIONS")
- Runs tests
- If green → commits + checks the item off in
fix_plan.md + emits completion signal
- If red → leaves a note in
fix_plan.md (> blocker: X — retry next loop) and stops the iteration
The skill generates PROMPT.md from templates/PROMPT.template.md by substituting {{USECASE}}, {{SUCCESS_CRITERIA}}, {{NON_GOALS}}, {{COST_CEILING}}.
1.2 — fix_plan.md (the worklist)
Markdown checklist, one item per task. Each item has:
- [ ] [priority] short title
- 2-3 lines of context (file paths, expected behavior, acceptance test)
- Optional: link to
specs/<item>.md for long-form spec
The skill generates fix_plan.md skeleton from templates/fix_plan.template.md. Operator fills in the list before the loop starts.
1.3 — ralph.sh (the loop wrapper)
The actual shell loop. Generated from templates/ralph.template.sh (bash) and templates/ralph.template.ps1 (PowerShell). The loop:
- Caps iterations (
MAX_ITERATIONS=50 default)
- Caps wall-clock (
MAX_HOURS=8 default)
- Caps per-hour token spend (
MAX_TOKENS_PER_HOUR=200000 default)
- Checks termination after each iteration (fix_plan empty / completion-promise / circuit breaker)
- Writes journal lines to
cortex/ralph/<usecase>/journal.jsonl
- Reads
~/.cortex/STEWARD_HALT between iterations (operator killswitch)
Phase 1.5 — Plan gate (operator approval)
After Phase 1 generates all three artifacts, pause and show the operator:
- The pre-flight table (Phase 0)
fix_plan.md content (so they can edit it)
PROMPT.md content (so they spot drift triggers)
- Estimated cost ceiling at full iteration cap
- Termination conditions for this run
- Recovery instruction (
git reset --hard <baseline-sha> + path to scratch dir)
Operator approves with y / adjusts / cancels. Never start the loop without this gate — the loop spends money and modifies the repo.
Phase 2 — Run mode selection
| Mode | When to use | Behavior |
|---|
--planner-only | Spec hasn't been written yet | Loop only edits fix_plan.md + specs/ — never touches source code. Used to converge on a worklist before opening implementation. Huntley's canonical "plan" mode. |
--builder-only (default) | fix_plan + specs already exist | Loop only implements items from fix_plan, runs tests, commits, checks off. Never adds new items. |
--planner-then-builder | Long unstructured ask | First N iterations are planner mode (write fix_plan + specs); then auto-switch to builder mode when fix_plan reaches target_item_count |
--single-pass | Just one iteration as a smoke test | Run the loop body once, exit. Cheapest validation that the prompt + artifacts work. Use BEFORE long runs. |
Default to --single-pass first, then --builder-only. Never start with unbounded builder mode without a single-pass dry run.
Phase 3 — Spawn the loop
Isolate first. Before any execution surface, create a throwaway worktree so a corrupted tree never touches the primary checkout: git worktree add ../ralph-<usecase> ralph/<usecase> (or claude --worktree <usecase>), then run ralph.sh from there. The Known-risks § lethal-trifecta mitigation depends on this. Skip only for --single-pass smoke tests.
Three execution surfaces:
- Foreground bash —
./cortex/ralph/<usecase>/ralph.sh directly. Use for short runs (< 1h), to watch live, to abort fast.
- tmux pane —
tmux new-session -d -s ralph-<usecase> 'cd cortex/ralph/<usecase> && ./ralph.sh'. Use for unattended overnight. Operator attaches with tmux a -t ralph-<usecase> and detaches with Ctrl+B → D.
run_in_background Bash tool — when invoked from this session, spawn the loop in the background and monitor via journal.jsonl tail. Use sparingly — operator should drive long runs themselves.
For unattended runs, default to tmux + stream-json output (claude -p --output-format stream-json). The journal.jsonl is appended per iteration with: {iteration, started_at, ended_at, items_checked_off, cost_usd, exit_reason}.
Native monitoring alternative: instead of tailing journal.jsonl by hand, Claude Code's Monitor tool (v2.1.98+) can watch the journal + interject on exit_reason / cost-spike events without you polling — ask Claude to Monitor cortex/ralph/<usecase>/journal.jsonl and flag any exit_reason or iter_cost > $5. Pair with PushNotification for an "overnight run done" phone alert.
Phase 4 — Monitor + tune ("sit on the loop, not in it")
Huntley's verbatim guidance: "Sit on the loop, observe + tune like a guitar — don't sit in it."
The skill exposes 3 monitoring contracts:
cortex/ralph/<usecase>/journal.jsonl — append-only per-iteration record
cortex/ralph/<usecase>/STATUS — symlink to current iteration's stdout (overwritten each loop)
cortex/ralph/<usecase>/COST — running cost total
When the operator says "how's ralph doing" mid-run, read all three + report: iteration count / items closed / items added / current spend / time elapsed / estimated time to fix_plan empty.
Tuning during the run = editing PROMPT.md between iterations (the next loop picks up the new prompt). Don't edit fix_plan.md while a loop is running — race condition with the model's own check-off writes.
Phase 5 — Termination conditions
The loop stops when any one of these fires (in priority order):
fix_plan.md has zero unchecked - [ ] items — primary success exit
~/.cortex/STEWARD_HALT exists — operator killswitch, immediate exit
- Iteration cap reached (
MAX_ITERATIONS, default 50)
- Wall-clock cap reached (
MAX_HOURS, default 8)
- Cost cap reached (
MAX_COST_USD, default $20 for the whole run, separate from daily Steward cap)
- Completion promise — if
PROMPT.md declares one, the loop matches <promise>COMPLETE</promise> in stdout and exits
- Circuit breakers:
- 3+ consecutive iterations without items checked off →
NO_PROGRESS
- 5+ identical errors in journal.jsonl →
STUCK_ERROR
- 2+ consecutive
git reset --hard events → CORRUPTION
Each exit reason logs a final line to journal.jsonl and writes a one-screen summary to cortex/ralph/<usecase>/REPORT.md.
Full termination semantics + 6 circuit breakers + opt-in completion-promise format → references/termination.md.
Phase 6 — Post-loop verification
After the loop exits (for any reason), run a final sweep:
git status — confirm tree is clean (loop commits per iteration, so it should be)
npm test — full suite, not just the last iteration's slice
- R2 review pipeline — spawn
acceptance-auditor + blind-hunter + ssot-enforcer + edge-case-hunter against the full diff (loop commits aggregate into one PR-sized change)
- Cost reconciliation — sum
journal.jsonl cost_usd, compare to OpenRouter dashboard
- Recommendations file — surface any items the loop added to fix_plan but didn't close (debt for next run)
Then write REPORT.md (paste-ready PR description) and surface it. Operator decides: merge / iterate again / abandon + git reset --hard <baseline>.
Anti-patterns the skill refuses to scaffold
- fix_plan.md item with no acceptance test → reject, force operator to add a verifier
- PROMPT.md asking for "improvement" / "refactoring" without target → reject, ambiguous
- MAX_ITERATIONS unset or > 200 → reject, cost cap discipline
- Running on main branch → reject, force
ralph/<usecase> branch
- Running with dirty tree → reject
- Running without baseline commit → reject (no recovery path)
- Running when STEWARD_HALT exists → respect the killswitch
Cost discipline
Defaults that the skill enforces unless operator explicitly overrides:
MAX_ITERATIONS=50
MAX_HOURS=8 (one overnight window)
MAX_COST_USD=20 per run
MAX_TOKENS_PER_HOUR=200000
- Model:
claude-sonnet-4-6 (Ralph baseline; switch to opus only when sonnet stalls)
The benchmark from HumanLayer: "Sonnet 4.5 on a bash loop, known as Ralph, costs ~$10.42/hour." Sonnet 4.6 is similar. Budget realistically: 8h overnight = ~$80 spend ceiling on the upper bound.
Full cost-discipline framework + per-iteration spend caps + circuit breakers → references/cost-discipline.md.
Variants
Ralph isn't one pattern — it's three. Full anatomy + verbatim prompt templates for each → references/patterns.md:
- Planner / Builder split (Huntley canonical) — two prompt files, planner-only first run, then builder
- Verifier loop (Anthropic plugin) — Stop hook intercepts exit, re-feeds prompt until
<promise>COMPLETE</promise>
- Spec-driven Ralph —
@specs/stdlib/* re-injected each loop, used to reverse-engineer codebases into specs
- AFK Ralph — streaming JSON variant for unattended runs
- TDD Ralph — failing test is the next iteration's signal, items close when test goes green
- Subagent fanout Ralph — Huntley's verbatim rule: "500 sonnet subagents for reads, 1 sonnet for writes"
Companion references
The main SKILL.md keeps the runtime contract. Deep guidance lives in companion files:
Output discipline (matches voice.md)
- No greetings before scaffolding ("Tady je váš Ralph loop!" — banned)
- No emoji in operator-facing text
- Counts not praise: "Generated PROMPT.md + fix_plan.md + ralph.sh into cortex/ralph/cron-stability/. 7 items in fix_plan, estimated cost $14 at MAX_ITERATIONS=50." not "Krásný plán!"
- When unsure of a fix_plan item, ask one tight question instead of guessing
- Cite
[cortex/recall] + footnote when recalling prior Ralph runs from cortex/ralph/*/REPORT.md
Slot validation (substitution safety)
When the skill writes ralph.sh / ralph.ps1 it substitutes operator-provided values into shell heredocs and double-quoted strings. Unsanitized values are a command-injection vector. Before substitution the skill MUST validate every slot against an allowlist regex:
| Slot | Regex | Example accept | Example reject |
|---|
{{USECASE_SLUG}} | ^[a-z0-9-]{1,40}$ | cron-stability | cron"; rm -rf ~ |
{{USECASE}} (display) | ^[A-Za-z0-9 _\-./]{1,80}$ | Cron stability sweep | embedded backticks / $() / shell metas |
{{BRANCH}} | ^[a-zA-Z0-9._/-]{1,80}$ | ralph/cron-stability | main; git push |
{{BASELINE_SHA}} | ^[0-9a-f]{7,40}$ | abc1234 | --upload-pack=… |
{{TIMESTAMP}} | ^[0-9TZ:.-]{1,30}$ | ISO-8601 string | shell metas |
Reject on first violation. The scaffolder refuses to write the loop until the operator picks valid values.
Known risks v0
The R2 security review (2026-05-25) returned CANNOT SHIP AS-IS for production environments. The skill ships as v0-experimental with these caveats documented:
Architectural risks (require operator awareness)
- Lethal trifecta in one process — Ralph reads private repo data + ingests untrusted
fix_plan.md + has external network egress (model can curl / git push). --dangerously-skip-permissions disables Claude Code's in-band defense (including the block-destructive hook). Mitigation v0: run only on repos you can git reset --hard; use a fresh ralph/<usecase> branch; never run on prod credentials. Native FS isolation (available now): Claude Code exposes EnterWorktree / claude --worktree <name> + an isolation: "worktree" option on the Agent tool — run Ralph inside a throwaway worktree so a corrupted tree never touches your primary checkout (auto-cleaned if no changes land, otherwise the branch + path are returned). Prefer this over running in-place. Roadmap v1: ralph.sh auto-creates the worktree; document the container/devcontainer execution path.
- Cost cap is model-self-reported —
total_cost_usd is extracted from the model's own stream-json output. A prompt-injected fix_plan.md could ask the model to falsify the field, bypassing MAX_COST_USD. Mitigation v0: MAX_ITERATIONS cap is hard-enforced by the shell — that's your real budget ceiling. Roadmap v1: out-of-band billing-API cost gate between iterations.
- block-destructive hook disabled — when running with
--dangerously-skip-permissions, the cortex-x block-destructive hook does NOT intercept rm -rf, git push --force, git reset --hard, DROP TABLE, etc. Mitigation v0: set RALPH_REQUIRE_HOOKS=1 to run without the dangerous flag (slower, prompts on each tool call, but defense-in-depth intact). Roadmap v1: ship a Ralph-aware permission allowlist that pre-approves the safe tool subset (Read/Grep/Glob/Edit/npm test) while leaving destructive ones gated.
Implementation risks (operator monitoring)
- Branch protection not auto-verified — Phase 0 refuses main/master, but doesn't probe GitHub branch-protection rules. If the repo has no branch protection, the model can still
git push origin main --force via tool use. Mitigation v0: enable branch protection on the target remote before running. Roadmap v1: gh api repos/:owner/:repo/branches/main/protection pre-flight check.
- PROMPT.md / journal.jsonl persist on disk —
cortex/ralph/ is gitignored but stays on disk forever. If you include secrets in the usecase description, they land in 50+ iteration logs. Mitigation v0: never paste credentials into usecase / fix_plan content; pre-flight scans PROMPT.md for sk-, ghp_, xox[bp]-, AKIA, -----BEGIN and refuses. Roadmap v1: auto-purge logs > 30 days; chmod 700 on the scratch dir.
- Pre-commit hooks requiring TTY — if the repo has husky / lefthook / pre-commit hooks that prompt interactively,
--dangerously-skip-permissions doesn't help (non-interactive bash blocks). The loop will close 0 items, trip NO_PROGRESS after 3 iter and exit. Mitigation v0: disable interactive hooks for the run, or set HUSKY=0 / equivalent in the env. Roadmap v1: Phase 0 hook probe.
Acceptance for v0 use
Ralph v0 is safe to run when all apply:
- Personal repo or test fixture, never production
- Running inside a dedicated git worktree (
git worktree add / claude --worktree) — corruption stays off your primary checkout
ralph/<usecase> branch (never main/master)
- Clean tree at baseline + you remember the baseline SHA
- You can
git reset --hard <baseline> to recover
- No secrets in
PROMPT.md or fix_plan items
- Branch protection enabled on origin/main
MAX_ITERATIONS=20 for first run (caps blast radius)
- You check on it every 30 min ("sit on the loop, not in it") — or wire the Monitor tool + PushNotification so it reaches you instead
If any of those don't hold, defer Ralph and use /cortex-goal (which runs in your foreground session under normal Claude Code permissions) instead.
Sources
Research May 2026:
R2 review reports (2026-05-25): acceptance-auditor (approved-conditional), blind-hunter (8 P0, 12 P1), edge-case-hunter (5 P0, 6 P1), security-auditor (CANNOT SHIP AS-IS, 4 CRIT + 5 HIGH). The CRIT findings drove the v0-experimental label + Known risks section above.