Ralph is a CLI tool that runs Claude Code in an autonomous loop until your task is complete. You give it a prompt (or a PRD file), and Ralph keeps iterating until Claude outputs a completion signal.
Key insight: Instead of babysitting AI coding tools, you become the product designer. Ralph becomes your tireless engineering team that works while you sleep.
- Autonomous Loop: Runs Claude Code repeatedly until completion
- Rich TUI: Beautiful terminal interface built with Ink (React for CLI)
- Performance Tracking: Stock-style delta comparison for iteration timing
- Live Output Streaming: 50-line rolling preview with ANSI support
- History: Full iteration history saved to
~/.ralph/history - Smart Exit Detection: Semantic promise tags for completion, blocking, and decisions
- Notifications: Desktop notifications + sound alerts when attention needed
- Safe Exit: Double Ctrl+C required to prevent accidental exits
# Clone the repository
git clone https://github.com/your-username/ralph-cli.git
cd ralph-cli
# Install dependencies
bun install
# Run directly
bun run src/cli.tsx "Your prompt here"
# Or build and install globally
bun run build
npm link
ralph "Your prompt here"# With inline prompt
ralph "Build a REST API with user authentication"
# With a prompt file (PRD)
ralph ./my-prd.md
# Specify max iterations
ralph -m 50 "Implement feature X"| Option | Description | Default |
|---|---|---|
-m, --max <n> |
Maximum iterations | 200 |
-u, --unlimited |
Run indefinitely until completion | false |
-s, --signal <text> |
Completion signal | <promise>COMPLETE</promise> |
-M, --model <model> |
Claude model (opus, sonnet, haiku) | opus |
-d, --dangerously-skip |
Skip permission prompts | false |
-v, --verbose |
Show full Claude output | false |
--headless |
Run without TUI (for AFK/background) | false |
--no-splash |
Skip splash screen | - |
--no-notify |
Disable desktop notifications | - |
--no-sound |
Disable sound alerts | - |
--debug |
Enable debug logging | false |
--preflight-only |
Only run pre-flight checks | - |
--sandbox |
Run Claude in Docker sandbox | false |
--no-sandbox |
Disable Docker sandbox (default) | - |
--auto-commit |
Commit after each iteration | true |
--no-auto-commit |
Disable automatic commits | - |
During execution:
p- Pause/resume the loopr- Resume from blocked/decide stateq- QuitCtrl+C(twice) - Force exit
Ralph uses semantic promise tags to communicate with Claude:
<promise>COMPLETE</promise>
Output this when all tasks are done. Ralph will stop and celebrate.
<promise>BLOCKED: reason here</promise>
Output this when you can't continue without human help. Ralph will pause and notify.
<promise>DECIDE: question here</promise>
Output this when you need a user decision. Ralph will pause and wait.
Ralph is most effective when used with the canonical pattern, which keeps AI operating in its smartest mode by wiping context completely after every iteration.
Previous versions of Ralph injected iteration numbers and instructions into the prompt. This is removed because:
- Context pollution: Every token injected is a token not available for the actual task
- LLMs get worse as context grows: Old code, previous attempts, and failed approaches create noise
- Unnecessary: Claude can read iteration state from files (PRD, progress.txt)
- Anti-pattern: The canonical ralph keeps prompts static
The TUI still shows iteration progress for YOUR visibility - it's just not sent to Claude.
- Static Prompt: Your prompt file contains instructions AND task definitions
- Fresh Context: Each iteration starts with a completely clean context
- Progress via Files: Claude reads/writes project files (not injected context)
- External Loop: Ralph controls iteration, not Claude
Your prompt file (e.g., task.md) should include:
-
Instructions - Tell Claude how to work:
- Read the task list below
- Pick the highest priority incomplete task
- Implement it fully
- Mark it as complete
- Run tests/checks
- Commit if passing
-
Task List - Concrete, verifiable tasks:
## Tasks ### US-001: Add user authentication [passes: false] - Add POST /auth/login endpoint - Add POST /auth/register endpoint - Use bcrypt for password hashing - Tests pass ### US-002: Add password reset [passes: false] - Add POST /auth/forgot-password endpoint - Send reset email - Tests pass
-
Completion Signal:
When ALL tasks show [passes: true], output: <promise>COMPLETE</promise>
Instruct Claude to append learnings to progress.txt after each iteration:
After completing work, append a brief summary to progress.txt:
- What was implemented
- Any issues encountered
- Patterns discovered for future iterationsThis creates a log that:
- Gives you visibility into what happened
- Can be read by future iterations (Claude reads it fresh each time)
- Doesn't bloat context (it's a file, not injected)
# Unlimited iterations until all tasks complete
ralph ./my-feature.md --unlimited
# With iteration limit (safety)
ralph ./my-feature.md -m 50
# Headless for AFK/overnight runs
ralph ./my-feature.md --unlimited --headless
# Combine with verbose output
ralph ./my-feature.md -u --headless -vThe key to success with Ralph is writing clear, specific prompts:
-
Be Specific: "Add a login button" is vague. "Add a login button in the top-right of the header that opens a modal with email/password fields" is better.
-
Include Success Criteria: Tell Claude exactly how to verify the task is done.
-
Break Down Complex Tasks: Each task should be completable in one Claude session.
-
Example Prompt:
## Task
Implement user authentication for the Express API.
## Requirements
- Add POST /auth/login endpoint
- Add POST /auth/register endpoint
- Use bcrypt for password hashing
- Use JWT for session tokens
- Add auth middleware for protected routes
## Success Criteria
- All endpoints return proper status codes
- Passwords are hashed before storage
- JWT tokens expire after 24 hours
- Protected routes return 401 without valid token
When complete, output: <promise>COMPLETE</promise>All runs are saved to ~/.ralph/history/ as JSON files:
{
"id": "abc123",
"timestamp": "2024-01-15T10:30:00Z",
"projectRoot": "/Users/you/project",
"prompt": "...",
"iterations": [
{
"number": 1,
"duration": 45000,
"output": "...",
"promiseTag": null
}
],
"result": "completed",
"totalDuration": 180000
}By default, Ralph commits changes after each successful iteration. This provides:
- Safety against interrupted runs
- Clear history of what each iteration accomplished
- Easy rollback if something goes wrong
Claude provides commit messages via the <commit_message> tag. If not provided, Ralph generates a default message based on the git diff.
# Disable automatic commits
ralph ./task.md --no-auto-commit
# Re-enable (default)
ralph ./task.md --auto-commitIn your prompt, instruct Claude to provide commit messages:
When you make code changes, provide a commit message:
<commit_message>Brief description of changes</commit_message>Claude Code has a known bug (#12261) where sub-agents (like Plan mode, ultrathink) may still prompt for permissions even with --dangerously-skip-permissions.
Workaround: Avoid using /plan or complex sub-agent features in AFK ralph loops. Keep prompts focused on direct implementation tasks.
Ralph runs several checks before starting:
- Claude CLI installed and in PATH
- Prompt file exists (if file path provided)
- Model is valid
~/.ralphdirectory exists- No other Ralph process running
- Max iterations is reasonable
Run ralph --preflight-only to test without starting the loop.
For enhanced security during AFK or overnight runs, Ralph supports running Claude inside a Docker sandbox container.
- Docker Desktop 4.50+ installed and running
- Docker sandbox plugin enabled
# Run with Docker sandbox
ralph --sandbox "Your prompt here"
# Combine with other options
ralph --sandbox -m 100 -M sonnet ./my-prd.mdWhen sandbox mode is enabled, Ralph runs Claude via Docker's sandbox feature:
docker sandbox run --credentials host claude [args]This provides:
- Isolated execution: Claude runs in a container, not directly on your host
- Controlled access: Uses
--credentials hostto pass through your Claude credentials - Same functionality: All Claude features work normally inside the sandbox
If Docker sandbox is not available (Docker not installed, not running, or missing the sandbox plugin), Ralph will prompt you to:
- Continue without sandbox (runs Claude directly)
- Exit and fix Docker setup
# Install dependencies
bun install
# Run in development
bun run dev "Test prompt"
# Run tests
bun test
# Run tests in watch mode
bun test --watch
# Type check
bun run typecheck
# Lint
bun run lint
# Format
bun run formatsrc/
├── cli.tsx # Entry point, argument parsing
├── app.tsx # Main Ink application
├── components/ # React/Ink UI components
│ ├── Splash.tsx # ASCII art splash screen
│ ├── Header.tsx # Status header
│ ├── IterationPanel.tsx
│ ├── OutputPreview.tsx
│ ├── Spinner.tsx
│ ├── TimingStats.tsx
│ └── Logger.tsx
├── hooks/ # React hooks
│ ├── useClaudeLoop.ts # Main loop orchestration
│ ├── useTiming.ts # Performance tracking
│ ├── useOutputCapture.ts
│ └── useExitHandler.ts
├── lib/ # Utilities
│ ├── claude.ts # Claude CLI wrapper
│ ├── history.ts # History management
│ ├── notifications.ts
│ ├── preflight.ts
│ ├── promiseParser.ts
│ └── logger.ts
└── types/ # TypeScript definitions
Ralph Wiggum is known for his cheerful persistence and optimistic outlook, no matter how many times things go wrong. That's exactly what this tool does - it keeps trying until it succeeds.
"Me fail English? That's unpossible!" - Ralph Wiggum
MIT
- Inspired by Geoffrey Huntley's Ralph technique
- Built with Ink (React for CLI)
- Uses Claude Code by Anthropic