"Ralph is a Bash loop." — Geoffrey Huntley, creator of the Ralph pattern
The original, PRD-driven Ralph implementation. Works with Claude Code CLI, OpenAI Codex, and Kimi CLI. Converted from Ryan Carson's Amp version.
This is not the built-in Claude Code ralph skill. This is a customizable, transparent implementation that gives you full control over the autonomous loop — the way Geoffrey Huntley intended.
- Quick Start
- Step-by-Step Guide
- Why This Over the Built-in Skill?
- How It Works
- The PRD Skills (Claude Code Only)
- Writing Good User Stories
- Customization
- Debugging
- Credits
# 1. Clone this repo
git clone https://github.com/jayozer/ralph.git
cd ralph
# 2. Copy files to your project
cp ralph.sh ralph-claude.sh prompt-claude.md prd.json.example .env.example /path/to/your-project/
# 3. In your project, create prd.json from the example
cd /path/to/your-project
cp prd.json.example prd.json
# Edit prd.json with your user stories
# 4. Run Ralph
./ralph.sh claude 10 # Claude Code with 10 iterations
./ralph.sh codex 10 # OpenAI Codex with 10 iterations
./ralph.sh kimi 10 # Kimi with 10 iterations| Requirement | Installation |
|---|---|
| Claude Code CLI | Install guide |
| OpenAI Codex CLI (optional) | Install guide |
| Kimi CLI (optional) | Install guide |
| jq | brew install jq (macOS) or apt install jq (Linux) |
| Git repository | Your project must be a git repo |
Option A: Clone and copy
git clone https://github.com/jayozer/ralph.git
cd ralph
# For Claude Code:
cp ralph.sh ralph-claude.sh prompt-claude.md prd.json.example .env.example /path/to/your-project/
# For OpenAI Codex:
cp ralph.sh ralph-codex.sh prompt-codex.md prd.json.example .env.example /path/to/your-project/
# For Kimi CLI:
cp ralph.sh ralph-kimi.sh prompt-kimi.md prd.json.example .env.example /path/to/your-project/
# For all engines:
cp ralph.sh ralph-claude.sh ralph-codex.sh ralph-kimi.sh prompt-claude.md prompt-codex.md prompt-kimi.md prd.json.example .env.example /path/to/your-project/Option B: Download directly
cd /path/to/your-project
# Core files (Claude Code)
curl -sLO https://raw.githubusercontent.com/jayozer/ralph/main/ralph.sh
curl -sLO https://raw.githubusercontent.com/jayozer/ralph/main/ralph-claude.sh
curl -sLO https://raw.githubusercontent.com/jayozer/ralph/main/prompt-claude.md
curl -sLO https://raw.githubusercontent.com/jayozer/ralph/main/prd.json.example
# Additional files for Codex (optional)
curl -sLO https://raw.githubusercontent.com/jayozer/ralph/main/ralph-codex.sh
curl -sLO https://raw.githubusercontent.com/jayozer/ralph/main/prompt-codex.md
# Additional files for Kimi (optional)
curl -sLO https://raw.githubusercontent.com/jayozer/ralph/main/ralph-kimi.sh
curl -sLO https://raw.githubusercontent.com/jayozer/ralph/main/prompt-kimi.md
chmod +x ralph*.shCopy the example and edit it:
cp prd.json.example prd.jsonprd.json structure:
{
"project": "MyApp",
"branchName": "ralph/my-feature",
"description": "Add user authentication",
"userStories": [
{
"id": "US-001",
"title": "Add users table",
"description": "As a developer, I need a users table to store credentials.",
"acceptanceCriteria": [
"Create users table with id, email, password_hash",
"Add migration file",
"Typecheck passes"
],
"priority": 1,
"passes": false,
"notes": ""
},
{
"id": "US-002",
"title": "Add login endpoint",
"description": "As a user, I can log in with email and password.",
"acceptanceCriteria": [
"POST /api/login accepts email and password",
"Returns JWT token on success",
"Returns 401 on invalid credentials",
"Typecheck passes"
],
"priority": 2,
"passes": false,
"notes": ""
}
]
}Key fields:
branchName— Ralph creates/uses this branchpriority— Lower numbers run first (1, 2, 3...)passes— Set tofalse, Ralph sets totruewhen doneacceptanceCriteria— Must be verifiable (always include "Typecheck passes")
# Claude Code (default)
./ralph.sh 10 # 10 iterations
./ralph.sh claude 10 # Explicit: Claude Code
# OpenAI Codex
./ralph.sh codex 10 # 10 iterations with Codex
# Kimi CLI
./ralph.sh kimi 10 # 10 iterations with KimiWhat happens:
- Ralph creates/switches to the branch in
branchName - Picks the highest-priority story where
passes: false - Implements it, runs quality checks, commits
- Updates
prd.jsonto setpasses: true - Logs learnings to
progress.txt - Repeats until all stories pass or max iterations reached
# Watch stories complete
cat prd.json | jq '.userStories[] | {id, title, passes}'
# See learnings from iterations
cat progress.txt
# Check commits
git log --oneline -10Geoffrey Huntley explicitly stated that "Claude Code's implementation isn't it."
flowchart TB
subgraph builtin["Built-in Ralph Skill"]
B1[Single Session] --> B2[Stop Hook Blocks Exit]
B2 --> B3[Same Context Grows]
B3 --> B4[Context Eventually Fills]
B4 --> B5[Quality Degrades]
end
subgraph thisrepo["This Repo: PRD-Driven Ralph"]
R1[Bash Loop Spawns Instance] --> R2[Fresh Context Every Time]
R2 --> R3[Implement ONE Story]
R3 --> R4[Commit + Update prd.json]
R4 --> R5[Instance Exits Cleanly]
R5 --> R1
end
style builtin fill:#ffcccc,stroke:#cc0000
style thisrepo fill:#ccffcc,stroke:#00cc00
| Aspect | Built-in Skill | This Repo |
|---|---|---|
| Context per iteration | Accumulates (same session) | Fresh (new instance) |
| Memory model | In-context (degrades over time) | External files (git, prd.json, progress.txt) |
| Stop condition | Hook blocks exit | <promise>COMPLETE</promise> signal |
| Task structure | Unstructured prompt | PRD with acceptance criteria |
| Customization | Limited | Full control via prompt files |
| Progress visibility | Opaque | progress.txt + prd.json status |
| Learning persistence | Lost when session ends | Saved to CLAUDE.md/AGENTS.md files |
flowchart TB
subgraph setup["Setup Phase"]
S1["You write a PRD<br/><small>Define what you want to build</small>"]
S2["Convert to prd.json<br/><small>Break into small user stories</small>"]
S3["Run ralph.sh<br/><small>Starts the autonomous loop</small>"]
end
subgraph loop["Loop Phase (Fresh Context Each Time)"]
L1["Agent picks a story<br/><small>Finds next passes: false</small>"]
L2["Implements it<br/><small>Writes code, runs tests</small>"]
L3["Commits changes<br/><small>If tests pass</small>"]
L4["Updates prd.json<br/><small>Sets passes: true</small>"]
L5["Logs to progress.txt<br/><small>Saves learnings</small>"]
end
subgraph decision["Decision"]
D1{"More stories?"}
end
subgraph done["Complete"]
E1["Done!<br/><small>All stories complete</small>"]
end
S1 --> S2
S2 --> S3
S3 --> L1
L1 --> L2
L2 --> L3
L3 --> L4
L4 --> L5
L5 --> D1
D1 -->|Yes| L1
D1 -->|No| E1
style setup fill:#f0f7ff,stroke:#4a90d9
style loop fill:#f5f5f5,stroke:#666666
style decision fill:#fff8e6,stroke:#c9a227
style done fill:#f0fff4,stroke:#38a169
graph LR
subgraph persist["Persists Between Iterations"]
A[Git History] --> |"What was done"| D[Fresh Agent Instance]
B[prd.json] --> |"What's left to do"| D
C[progress.txt] --> |"Learnings & patterns"| D
E[CLAUDE.md / AGENTS.md] --> |"Codebase knowledge"| D
end
D --> |"Updates"| A
D --> |"Updates"| B
D --> |"Appends"| C
D --> |"May update"| E
Two optional skills help you create and convert PRDs. These are Claude Code specific.
# Global installation (available in all projects)
mkdir -p ~/.claude/skills
cp -r /path/to/ralph/.claude/skills/prd ~/.claude/skills/
cp -r /path/to/ralph/.claude/skills/ralph ~/.claude/skills/
# Or project-local installation
mkdir -p .claude/skills
cp -r /path/to/ralph/.claude/skills/* .claude/skills/flowchart LR
A[Feature Idea] --> B["/prd skill"]
B --> C["tasks/prd-feature.md"]
C --> D["/ralph skill"]
D --> E["prd.json"]
E --> F["ralph.sh"]
F --> G{All stories pass?}
G -->|No| F
G -->|Yes| H[Feature Complete]
/prd Add a task priority system with high/medium/low levels
Asks 3-5 clarifying questions, then generates a structured PRD in tasks/prd-[feature-name].md.
/ralph convert tasks/prd-task-priority.md
Converts your PRD markdown to the prd.json format that Ralph executes.
Each story must be completable in ONE Ralph iteration (one context window).
✅ Right-sized: ❌ Too big (split these):
─────────────────────────────────────────────────────────────
• Add a database column • "Build entire dashboard"
• Add a UI component • "Add authentication"
• Add a filter dropdown • "Refactor the API"
• Update a server action
Rule of thumb: If you can't describe the change in 2-3 sentences, it's too big.
| Priority | Type | Example |
|---|---|---|
| 1 | Schema/migrations | Add priority column to tasks table |
| 2 | Backend logic | Create server action for priority updates |
| 3 | UI components | Add priority badge to task cards |
| 4 | Aggregations | Add priority filter dropdown |
✅ Good (verifiable): ❌ Bad (vague):
─────────────────────────────────────────────────────────────
• Add status column with • "Works correctly"
default 'pending'
• Filter has options: All, • "User can do X easily"
Active, Completed
• Clicking delete shows • "Good UX"
confirmation dialog
• Typecheck passes • "Handles edge cases"
Always include:
"Typecheck passes"— on every story"Verify in browser"— on UI stories
Every instruction Ralph follows is in prompt-claude.md (or prompt-codex.md). Add your project's requirements:
## Quality Requirements
- ALL commits must pass `npm run typecheck`
- Run `npm test` before committing
- Use Tailwind for all styling
- Never modify files in `src/legacy/`
- Always use server actions, not API routesRalph runners read a local .env file from the same directory as the scripts.
cp .env.example .envSupported variables:
RALPH_CLAUDE_MODEL-claude-opus-4-6,claude-sonnet-4-5,claude-haiku-4-5RALPH_CLAUDE_REASONING_EFFORT-low,medium,highRALPH_CODEX_MODEL-gpt-5-2-codexRALPH_CODEX_REASONING_EFFORT- Codex reasoning effort (defaultmedium)RALPH_CODEX_INPUT_COST_PER_MILLIONRALPH_CODEX_CACHED_INPUT_COST_PER_MILLIONRALPH_CODEX_OUTPUT_COST_PER_MILLIONRALPH_KIMI_MODEL- Kimi model name passed to the CLI (defaultkimi-code/kimi-for-coding)RALPH_KIMI_THINKING-trueorfalseRALPH_KIMI_AGENT- builtin Kimi agent name (defaultdefault)RALPH_KIMI_MAX_STEPS_PER_TURN- max Kimi steps per iteration (default50)
ralph-stats.sh now shows total cost for Claude and Codex runs. Kimi support logs runtime metadata, but token and cost totals default to zero unless richer CLI stats are added later.
Kimi CLI must already be installed and configured. If Kimi is not logged in or no default LLM is set, the runner will fail with the CLI error output.
| What | How |
|---|---|
| Quality gates | Edit prompt files to require specific checks |
| Story granularity | Define exact acceptance criteria in prd.json |
| Learning persistence | progress.txt captures patterns across iterations |
| Browser verification | Add "Verify in browser" to UI story criteria |
# See which stories are done
cat prd.json | jq '.userStories[] | {id, title, passes}'
# See learnings from previous iterations
cat progress.txt
# Check git history
git log --oneline -10
# See current branch
git branch --show-current| File | Purpose |
|---|---|
ralph.sh |
Wrapper script — choose Claude Code or OpenAI Codex |
ralph-claude.sh |
Claude Code agent loop |
ralph-codex.sh |
OpenAI Codex agent loop |
ralph-kimi.sh |
Kimi CLI agent loop |
prompt-claude.md |
Instructions for Claude iterations |
prompt-codex.md |
Instructions for Codex iterations |
prompt-kimi.md |
Instructions for Kimi iterations |
prd.json |
User stories with acceptance criteria and passes status |
progress.txt |
Learnings that persist across iterations |
.env / .env.example |
Model, reasoning, and pricing config for runners |
CLAUDE.md |
Project instructions for Claude Code |
AGENTS.md |
Project instructions for OpenAI Codex |
.claude/skills/ |
Claude Code skills for PRD generation |
- Geoffrey Huntley — Created the Ralph pattern
- Ryan Carson — Original Amp implementation this repo is based on
- Claude Code — The AI that does the work
- OpenAI Codex — Alternative AI engine
- Kimi CLI — Alternative CLI coding engine
| If you want... | Use... |
|---|---|
| Quick and dirty loop | Built-in skill |
| Full control, fresh context, PRD-driven | This repo |
"That's the beauty of Ralph — the technique is deterministically bad in an undeterministic world." — Geoffrey Huntley
"Every failure leaves a breadcrumb. Every small commit adds a brick. Eventually, the breadcrumbs become a highway and the bricks become a cathedral. Ralph just keeps laying bricks." — Jay Ozer