- Update "All complete" detection behavior in CLAUDE.md and ralph-wiggum-guide.md - Add UI Behaviors section documenting auto-focus, scroll preservation, consistent icons Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
22 KiB
Ralph Wiggum Loop: Complete Guide
This document consolidates official Anthropic documentation, community best practices, and implementation details for autonomous Claude Code loops.
Last Updated: 2026-01-20 Sources: Official Anthropic Plugin, Claude Code Docs, Claude Code Best Practices
Table of Contents
- Overview
- Core Concept
- Official Plugin Reference
- The Promise Tag Contract
- TodoWrite Tool Integration
- Hooks System
- Best Practices
- Prompt Templates
- When to Use (and Not Use)
- Real-World Examples
- Claudeman Implementation
- Troubleshooting
Overview
Ralph Wiggum is an autonomous loop technique for Claude Code, named after The Simpsons character. It enables Claude to work iteratively on tasks for hours without human intervention, self-correcting until completion criteria are met.
Core Philosophy:
- Iteration > Perfection: Don't aim for perfect on first try; let the loop refine
- Failures Are Data: "Deterministically bad" means failures are predictable and informative
- Operator Skill Matters: Success depends on writing good prompts, not just having a good model
- Persistence Wins: Keep trying until success; the loop handles retry logic
Origin: Created by Geoffrey Huntley, formalized into an official Anthropic plugin by Boris Cherny (Head of Claude Code) in late 2025.
Core Concept
The simplest form of a Ralph loop:
while :; do cat PROMPT.md | claude ; done
How It Works:
- Claude processes a task prompt
- Attempts to exit when "done"
- A Stop hook intercepts the exit
- Checks for completion promise (e.g.,
<promise>COMPLETE</promise>) - If not found, re-feeds the same prompt
- Files from previous iteration persist, so Claude sees its own work
- Cycle repeats until completion or max iterations reached
Key insight: The prompt never changes between iterations, but Claude's previous work persists in files, allowing autonomous improvement by reading past work.
Official Plugin Reference
Installation
# Add Anthropic's official plugin marketplace
/plugin marketplace add anthropics/claude-plugins-official
# Install Ralph Wiggum plugin
/plugin install ralph-wiggum@claude-plugins-official
Commands
/ralph-loop:ralph-loop
Start an autonomous loop in the current session.
/ralph-loop:ralph-loop
When invoked, this skill prompts you to configure:
- Task prompt: The work to be done (persists across iterations)
- Max iterations: Safety limit on iterations (recommended: always set this)
- Completion promise: The phrase that signals completion (e.g.,
COMPLETE)
/ralph-loop:cancel-ralph
Cancel the active Ralph loop.
/ralph-loop:cancel-ralph
/ralph-loop:help
Show help and usage information.
/ralph-loop:help
State File
The plugin persists state to .claude/ralph-loop.local.md:
---
enabled: true
iteration: 5
max-iterations: 50
completion-promise: "COMPLETE"
---
# Original Prompt
Build a REST API for todos...
YAML Fields:
enabled(boolean): Controls hook activationiteration(integer): Current iteration count (0-indexed)max-iterations(integer): Optional maximumcompletion-promise(string): Optional completion text
The Promise Tag Contract
The completion phrase pattern is the core contract between Claude and the loop system:
<promise>PHRASE</promise>
Examples:
<promise>COMPLETE</promise>- Generic completion<promise>TESTS_PASS</promise>- Test-specific completion<promise>TIME_COMPLETE</promise>- Time-aware loop completion<promise>FIXED</promise>- Bug fix completion
How Completion Detection Works
- Exact String Matching: The
--completion-promiseuses case-sensitive exact matching - Output Scanning: The Stop hook scans Claude's final output for the promise tag
- Exit Control: If found, exit is allowed. If not, loop continues.
False Positive Prevention
The official implementation (and Claudeman) prevents false positives when completion phrases appear in:
- Initial prompts
- Documentation or examples
- Comments
Solution: Claudeman uses occurrence-based detection to distinguish prompts from actual completions:
- 1st occurrence: Store as expected phrase (likely in the prompt)
- 2nd occurrence: Emit
completionDetected(actual completion) - If loop already active: Emit immediately (explicit loop start via
/ralph-loop:ralph-loop)
// From claudeman/src/inner-loop-tracker.ts
private handleCompletionPhrase(phrase: string): void {
const count = (this._completionPhraseCount.get(phrase) || 0) + 1;
this._completionPhraseCount.set(phrase, count);
// Store phrase on first occurrence
if (!this._loopState.completionPhrase) {
this._loopState.completionPhrase = phrase;
this._loopState.lastActivity = Date.now();
this.emit('loopUpdate', this.loopState);
}
// Emit completion if loop is active OR this is 2nd+ occurrence
if (this._loopState.active || count >= 2) {
this._loopState.active = false;
this._loopState.lastActivity = Date.now();
this.emit('completionDetected', phrase);
this.emit('loopUpdate', this.loopState);
}
}
This approach handles both scenarios:
- Explicit loop start: User runs
/ralph-loop:ralph-loop, loop is active, first completion phrase triggers - Implicit completion: Phrase appears in prompt (1st), then Claude outputs it on completion (2nd)
TodoWrite Tool Integration
The TodoWrite tool is Claude Code's built-in task management system that integrates with Ralph loops.
How It Works
Claude uses TodoWrite to:
- Break complex tasks into subtasks
- Track progress through iterations
- Provide visibility into current state
- Resume work after context resets
Todo Formats Detected
Format 1: Markdown Checkboxes
- [ ] Pending task
- [x] Completed task
- [X] Completed task (uppercase)
Format 2: Status Indicators
Todo: ☐ Pending task
Todo: ◐ In progress task
Todo: ✓ Completed task
Format 3: Parenthetical Status
- Task name (pending)
- Task name (in_progress)
- Task name (completed)
System Reminder Integration
From official Claude Code documentation:
After commands like an ls -la run via bash tool, system-reminder tags are injected to remind the model to use the TodoWrite tool if it hasn't been using it so far.
The system prompt includes:
"IMPORTANT: Always use the TodoWrite tool to plan and track tasks throughout the conversation."
Checklists for Complex Workflows
From Anthropic Best Practices:
For large tasks with multiple steps or requiring exhaustive solutions—like code migrations, fixing numerous lint errors, or running complex build scripts—improve performance by having Claude use a Markdown file (or even a GitHub issue!) as a checklist and working scratchpad.
Hooks System
Ralph loops are powered by Claude Code's hooks system. Understanding hooks is essential for customization.
Hook Events Reference
| Event | When | Use Case |
|---|---|---|
PreToolUse |
Before tool execution | Validate, modify, or block tool calls |
PostToolUse |
After tool completes | Provide feedback, run formatters/linters |
Stop |
When Claude finishes | Ralph loop control - block exit, refeed prompt |
SubagentStop |
When subagent finishes | Control nested loops |
UserPromptSubmit |
User submits prompt | Add context, validate input |
SessionStart |
Session begins | Load environment, context |
SessionEnd |
Session ends | Cleanup, logging |
PermissionRequest |
Permission dialog shown | Auto-approve/deny |
PreCompact |
Before compact | Backup, preprocessing |
Stop Hook for Ralph Loops
The Stop hook is the key mechanism:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "./scripts/ralph-stop-hook.sh"
}
]
}
]
}
}
Stop Hook Logic:
- Check if
.claude/ralph-loop.local.mdexists - Read
enabledflag from YAML frontmatter - Check for
completion-promisein output - Check if
iteration >= max-iterations - If none match, block exit and refeed prompt
Hook Output for Stop Events
{
"decision": "block",
"reason": "Completion promise not found. Restarting iteration."
}
Or to allow exit:
{
"continue": true,
"stopReason": "Completion promise detected"
}
Prompt-Based Hooks
For more sophisticated evaluation, use LLM-based hooks:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "Check if the task is complete. Context: $ARGUMENTS\n\nRespond with {\"ok\": true} if done, {\"ok\": false, \"reason\": \"...\"} if not.",
"timeout": 30
}
]
}
]
}
}
Best Practices
1. Always Set --max-iterations
This cannot be overstated: always set
--max-iterations. Autonomous loops consume tokens rapidly. A typical 50-iteration loop on a medium-sized codebase can cost $50-100+ in API usage.
/ralph-loop:ralph-loop
# Then configure: max-iterations=30, completion-promise="DONE"
2. Define Clear, Measurable Success Criteria
Bad:
Build a todo API and make it good.
Good:
Build a REST API for todos.
Completion criteria:
- All CRUD endpoints working (GET, POST, PUT, DELETE)
- Input validation with error messages
- Tests passing with >80% coverage
- README with API documentation
Output <promise>COMPLETE</promise> when ALL criteria are met.
3. Use Test-Driven Verification
The most effective Ralph Loop tasks include built-in verification. This creates a natural feedback loop within the loop.
Implement user authentication using TDD:
1. Write failing tests for each requirement
2. Implement feature to make tests pass
3. Run tests after each change
4. If any fail, debug and fix
5. Refactor if needed
6. Output <promise>TESTS_PASS</promise> when all tests green
4. Include Escape Hatches
Primary task: Implement feature X
If stuck after 10 iterations:
- Document what's blocking progress
- List approaches that were attempted
- Suggest alternative approaches
- Output <promise>BLOCKED</promise>
5. Incremental Goals for Large Tasks
Bad:
Create a complete e-commerce platform.
Good:
Build e-commerce platform in phases:
Phase 1: User authentication
- JWT-based auth
- Tests passing
- Commit: "feat: add user auth"
Phase 2: Product catalog
- CRUD for products
- Search functionality
- Tests passing
- Commit: "feat: add product catalog"
Phase 3: Shopping cart
- Add/remove items
- Persist cart state
- Tests passing
- Commit: "feat: add shopping cart"
Output <promise>COMPLETE</promise> when all phases done.
6. Commit Frequently
After each meaningful completion:
1. git add .
2. git commit -m "descriptive message"
This creates recovery points and shows progress in git history.
7. Test Before Long Runs
Pro tip: Test manually with one iteration before running 50-iteration loops.
# Test with 1 iteration first
/ralph-loop:ralph-loop
# Configure: max-iterations=1
# Then run full loop
/ralph-loop:ralph-loop
# Configure: max-iterations=50
8. Use Git for Safety
Always run Ralph loops in a git-tracked directory. If something goes wrong, you can revert. Each iteration adds to git history, giving you a clear trail of what changed.
Prompt Templates
Template 1: Test-Driven Development
# Task: [FEATURE_NAME]
## Requirements
- [Requirement 1]
- [Requirement 2]
- [Requirement 3]
## Approach
Follow TDD methodology:
1. Write failing tests for each requirement
2. Implement minimal code to pass tests
3. Run tests: `npm test`
4. If tests fail, read error, fix, repeat
5. When all tests pass, refactor if needed
6. Commit: `git add . && git commit -m "feat: [feature]"`
## Completion
Output <promise>TESTS_PASS</promise> when:
- All tests pass
- Code is committed
- No lint errors
Template 2: Migration/Refactor
# Task: Migrate from [OLD] to [NEW]
## Scope
Files to migrate: `src/**/*.ts`
## Migration Steps
For each file:
1. Update imports
2. Replace deprecated patterns
3. Run type check: `npx tsc --noEmit`
4. If errors, fix them
5. Run tests: `npm test`
6. Commit: `git commit -m "refactor: migrate [file]"`
## Completion
Output <promise>MIGRATION_COMPLETE</promise> when:
- All files migrated
- Type check passes
- All tests pass
- All changes committed
Template 3: Bug Fix
# Bug: [BUG_DESCRIPTION]
## Reproduction
[Steps to reproduce]
## Investigation
1. Find the root cause
2. Document findings
## Fix
1. Write a failing test that reproduces the bug
2. Implement the fix
3. Verify test passes
4. Check for regressions: `npm test`
5. Commit: `git commit -m "fix: [description]"`
## Completion
Output <promise>FIXED</promise> when:
- Bug is fixed
- Test added to prevent regression
- All tests pass
Template 4: Time-Aware Loop
# Task: Optimize API performance
## Primary Goals
1. Profile existing endpoints
2. Identify bottlenecks
3. Implement optimizations
4. Verify improvements
## Duration
Minimum runtime: 4 hours
## Self-Generated Tasks
If primary goals complete before 4 hours:
- Add caching layers
- Optimize database queries
- Add request batching
- Improve error handling
- Add performance tests
## Completion
Output <promise>TIME_COMPLETE</promise> when:
- All primary goals achieved
- Minimum 4 hours elapsed
- All tests pass
When to Use (and Not Use)
Good Use Cases
| Use Case | Why It Works |
|---|---|
| Large refactors | Clear mechanical steps, verifiable via tests |
| Framework migrations | Repetitive patterns, type checking validates |
| Test coverage | "Add tests for uncovered functions" is measurable |
| Greenfield projects | Can run overnight, tests verify correctness |
| Batch operations | Same operation across many files |
| Dependency upgrades | API changes are well-documented |
Poor Use Cases
| Use Case | Why It Fails |
|---|---|
| Ambiguous requirements | Can't define success criteria |
| Architectural decisions | Requires human judgment |
| Security-critical code | Needs human review |
| Production debugging | Often requires context not in code |
| UX/design decisions | Subjective, not automatable |
| Exploratory work | "Figure out why it's slow" has no clear endpoint |
Decision Framework
Ask yourself:
- Can I define "done" objectively? (tests pass, lint clean, etc.)
- Is there automatic verification? (tests, type checking, linting)
- Is the task mechanical or creative? (mechanical = good for Ralph)
- What's the cost of failure? (high cost = needs human review)
Real-World Examples
Example 1: Y Combinator Hackathon
- Task: Generate multiple repositories overnight
- Result: 6 repositories generated autonomously
- Key: Each repo had clear completion criteria
Example 2: $50K Contract
- Task: Large codebase migration
- Result: Completed for $297 in API costs
- Key: Well-defined migration patterns, comprehensive tests
Example 3: Programming Language (Cursed)
- Task: "Make me a programming language like Golang but with Gen Z slang keywords"
- Result: Functional compiler with LLVM backend, standard library, editor support
- Duration: 3 months of autonomous iteration
- Keywords:
slay(function),sus(variable),based(true)
Example 4: React Migration
- Task: Upgrade from React v16 to v19
- Result: 14-hour autonomous session, complete migration
- Key: Clear deprecation warnings, comprehensive test suite
Claudeman Implementation
Claudeman implements Ralph Wiggum tracking via the InnerLoopTracker class in src/inner-loop-tracker.ts.
Auto-Detection Patterns
The tracker automatically enables when detecting:
| Pattern | Example | Regex |
|---|---|---|
| Ralph command | /ralph-loop:ralph-loop |
/\/ralph-loop|starting ralph/i |
| Promise tag | <promise>COMPLETE</promise> |
/<promise>([^<]+)<\/promise>/ |
| TodoWrite | Todos have been modified |
/TodoWrite|todos?\s*(?:updated|written)/i |
| Iteration | Iteration 5/50 or [5/50] |
/(?:iteration)\s*#?(\d+)(?:\s*[\/of]\s*(\d+))?/i |
| Todo checkbox | - [ ] Task |
/^[-*]\s*\[([xX ])\]\s+(.+)$/gm |
| Todo indicator | Todo: ☐ Task |
/Todo:\s*(☐|◐|✓)/g |
| All complete | All tasks completed |
/all\s+tasks?\s+completed?|all\s+done/i |
| Task done | Task 8 is done |
/task\s*#?\d+\s*(?:is\s+)?done/i |
Completion Detection
Multi-strategy detection to catch various completion signals:
- Tagged phrase:
<promise>PHRASE</promise>- First occurrence stores phrase, second triggers completion - Bare phrase: Detects phrase without tags once expected phrase is known (e.g., Claude outputs
COMPLETEinstead of<promise>COMPLETE</promise>) - All complete signals: Detects "All X files/tasks created/completed" messages, marks all todos complete and emits completion
- Explicit task completion: Matches "Task N is done" patterns
Session Lifecycle
Each session has its own independent tracker:
| Action | Result |
|---|---|
| New session opened | Fresh tracker, no carryover |
| Tab closed | Tracker state cleared, UI panel hides |
| Switch tabs | Panel shows tracker for active session |
tracker.reset() |
Clears todos/state, keeps enabled status |
tracker.fullReset() |
Complete reset to initial state |
State Structure
interface InnerLoopState {
enabled: boolean; // Tracker active?
active: boolean; // Loop running?
completionPhrase: string | null;
startedAt: number | null;
cycleCount: number;
maxIterations: number | null;
lastActivity: number;
elapsedHours: number | null;
}
interface InnerTodoItem {
id: string;
content: string;
status: 'pending' | 'in_progress' | 'completed';
detectedAt: number;
}
API Endpoints
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/sessions/:id/inner-state |
Get loop state and todos |
| POST | /api/sessions/:id/inner-config |
Configure tracker settings |
POST /inner-config Options:
{
"enabled": true, // Enable/disable tracker
"reset": true, // Soft reset (clears state, keeps enabled)
"reset": "full", // Full reset (clears everything)
"completionPhrase": "DONE" // Set expected completion phrase
}
GET Response:
{
"success": true,
"data": {
"loop": {
"enabled": true,
"active": true,
"completionPhrase": "COMPLETE",
"cycleCount": 5,
"maxIterations": 50,
"elapsedHours": 2.5
},
"todos": [
{ "id": "todo-abc", "content": "Fix auth", "status": "completed" },
{ "id": "todo-def", "content": "Add tests", "status": "in_progress" }
],
"todoStats": { "total": 5, "pending": 2, "inProgress": 1, "completed": 2 }
}
}
SSE Events
| Event | Data | When |
|---|---|---|
session:innerLoopUpdate |
InnerLoopState |
Loop state changes |
session:innerTodoUpdate |
InnerTodoItem[] |
Todos detected/updated |
session:innerCompletionDetected |
{ phrase: string } |
Completion phrase found |
Skill Commands
/ralph-loop:ralph-loop # Start Ralph Loop in current session
/ralph-loop:cancel-ralph # Cancel active Ralph Loop
/ralph-loop:help # Show help and usage
Troubleshooting
Loop Never Completes
Cause: Completion criteria aren't clear enough.
Solution: Be more specific about what "done" means. Include testable criteria:
Output <promise>DONE</promise> when:
- `npm test` exits with code 0
- `npm run lint` exits with code 0
- All files committed
Same Error Every Iteration
Cause: Claude is stuck in a failure loop.
Solution: Add escape hatch to prompt:
If stuck after 10 iterations with the same error:
1. Document the error and what was tried
2. Suggest alternative approaches
3. Output <promise>STUCK</promise>
High API Costs
Cause: Too many iterations, large context.
Solutions:
- Always set
--max-iterations - Use
/clearbetween major phases - Keep files small and focused
- Test with 1 iteration first
False Completion Detection
Cause: Completion phrase appears in prompt or documentation.
Solution: Use unique, unlikely phrases:
# Bad (might appear in docs)
<promise>COMPLETE</promise>
# Good (unique)
<promise>TASK_XYZ_VERIFIED_DONE</promise>
Tracker Not Enabling
Cause: No Ralph patterns detected in output.
Solution:
- Manually enable:
POST /api/sessions/:id/inner-config { "enabled": true } - Or ensure Claude outputs recognizable patterns
Context Window Exhaustion
Cause: Long-running loops accumulate context.
Solution: Configure auto-clear:
POST /api/sessions/:id/auto-clear
{ "enabled": true, "threshold": 140000 }
References
Official Documentation
- Anthropic Ralph Wiggum Plugin
- Claude Code Hooks Reference
- Claude Code Best Practices
- Claude Code Overview
Community Resources
Related Claudeman Files
src/inner-loop-tracker.ts- Core detection enginesrc/ralph-loop.ts- Task orchestrationsrc/respawn-controller.ts- Session cyclingsrc/types.ts- Type definitions
This documentation is maintained as part of the Claudeman project. For updates, see the main CLAUDE.md.