Ralph is a lightweight agentic loop harness for autonomous AI-driven development. It iteratively runs an AI agent against a set of user stories until all acceptance criteria pass - or a maximum iteration count is reached.
Ralph operates on a simple loop:
┌─────────────────────────────────────────────────────┐
│ │
│ prompt.md ──▶ AI Agent ──▶ Code Changes │
│ ▲ │ │
│ │ ▼ │
│ └────── prd.json ◀── Tests/Validation │
│ │
│ Repeat until: <promise>COMPLETE</promise> │
│ or max iterations reached │
│ │
└─────────────────────────────────────────────────────┘
your-project/
├── scripts/
│ └── ralph/
│ ├── ralph.sh # Main loop runner (required)
│ ├── ui.sh # UI toolkit (gum-enhanced output; plain fallback)
│ ├── prompt.md # Feature-mode agent instructions (required for feature mode)
│ ├── prd.json # Feature-mode user stories (created by init.sh if missing)
│ ├── progress.txt # Optional running log (created by init.sh if missing)
│ ├── prd_prompt.txt # Optional template for generating prd.json
│ ├── ralph-understand.sh # Understanding-mode wrapper (created by init.sh if missing)
│ ├── understand_prompt.md # Understanding-mode prompt (created by init.sh if missing)
│ └── codebase_map.md # Understanding-mode output (created by init.sh if missing)
└── ...
- bash (macOS default Bash 3.2 supported)
- python3 (used for PRD parsing/validation and branch selection)
- git (optional but recommended; enables branch checkout +
ALLOWED_PATHSenforcement) - gum (optional; makes output prettier):
brew install gum - An agent CLI:
- Default: OpenAI Codex CLI (
codex) - Or set
AGENT_CMDto any command that reads a prompt from stdin and prints a response
- Default: OpenAI Codex CLI (
Copy the Ralph files into your project:
mkdir -p scripts/ralph
cp prompt.md prd.json progress.txt ralph.sh ui.sh prd_prompt.txt understand_prompt.md codebase_map.md ralph-understand.sh scripts/ralph/Run the initialization script to validate your setup:
./init.sh /path/to/your-projectAlternatively, copy init.sh into your project root and run it in-place:
cp init.sh /path/to/your-project/init.sh
cd /path/to/your-project
./init.shThis will:
- Validate that required files exist
- Create defaults if missing:
prd.json,progress.txt,codebase_map.md,understand_prompt.md,ralph-understand.sh - Validate the PRD schema (
scripts/ralph/prd.json) - Make loop scripts executable
- Print a quick status summary
You can write prd.json manually or generate it with an LLM using the included prompt template.
Use prd_prompt.txt as a template. It contains structured sections for you to fill in:
-
Copy the template to your project:
cp prd_prompt.txt scripts/ralph/prd_prompt.txt
-
Fill in the context sections at the bottom:
- Feature Overview - what you're building
- Branch Name - git branch for this work
- Requirements - specific things the feature must do
- Tech Stack - languages, frameworks, testing tools
- Verification Commands - exact commands to run typecheck/tests
- Constraints - limitations or non-functional requirements
-
Feed it to an LLM:
# Generate PRD with Claude cat scripts/ralph/prd_prompt.txt | claude --print > scripts/ralph/prd.json # Or any LLM CLI that accepts stdin cat scripts/ralph/prd_prompt.txt | your-llm-cli > scripts/ralph/prd.json
The template instructs the LLM to output valid JSON with properly scoped, testable user stories.
Create scripts/ralph/prd.json with your user stories:
{
"branchName": "ralph/my-feature",
"userStories": [
{
"id": "US-001",
"title": "User can log in with email",
"acceptanceCriteria": [
"Login form accepts email and password",
"Submitting an invalid email shows a validation error",
"Typecheck passes (run the project's typecheck)",
"Tests pass (run the project's tests)"
],
"priority": 1,
"passes": false,
"notes": ""
}
]
}Edit scripts/ralph/prompt.md with instructions for the AI agent. This typically includes:
- Reference to
prd.jsonfor the current user stories - Instructions on how to validate acceptance criteria
- Guidelines for updating
progress.txt - The completion signal:
<promise>COMPLETE</promise>
./scripts/ralph/ralph.sh 25By default (git repos only), Ralph will checkout/create the branch specified in scripts/ralph/prd.json (branchName) before starting iterations.
Override it (git repos only):
RALPH_BRANCH="ralph/my-feature" ./scripts/ralph/ralph.sh 25Skip branch management entirely:
RALPH_BRANCH="" ./scripts/ralph/ralph.sh 25Before implementing changes in an existing repo, you can run a read-only mapping loop that builds a codebase map over multiple iterations.
It writes findings to:
scripts/ralph/codebase_map.md
Understanding mode does not require prd.json.
Run it with the convenience wrapper:
# Uses scripts/ralph/understand_prompt.md and writes to scripts/ralph/codebase_map.md
./scripts/ralph/ralph-understand.sh 10By default, understanding mode will checkout/create the branch:
ralph/understanding
Override it (git repos only):
RALPH_BRANCH="ralph/codebase-map" ./scripts/ralph/ralph-understand.sh 10Stay on the current branch (skip checkout/creation):
RALPH_BRANCH="" ./scripts/ralph/ralph-understand.sh 10With Claude + human review after each iteration:
INTERACTIVE=1 AGENT_CMD="claude --print" ./scripts/ralph/ralph-understand.sh 10Under the hood, this uses:
PROMPT_FILE=scripts/ralph/understand_prompt.mdALLOWED_PATHS=scripts/ralph/codebase_map.md(git repos only; blocks other file edits)RALPH_BRANCH=ralph/understanding(git repos only; wrapper default)
Note: ALLOWED_PATHS also counts untracked files as changes. If you just copied scripts/ralph/ into a repo and haven't committed it yet, either commit once or loosen/disable the guard:
# Allow changes anywhere under scripts/ralph/
ALLOWED_PATHS="scripts/ralph/" ./scripts/ralph/ralph-understand.sh 10
# Or disable enforcement entirely
ALLOWED_PATHS="" ./scripts/ralph/ralph-understand.sh 10This repo includes a self-contained example project you can use to try Ralph end-to-end:
examples/uv-python/— a minimal uv-managed Python project (pyproject.toml) that vendors Ralph underscripts/ralph/.
Quick run:
cd examples/uv-python
uv sync
uv run pytest
# In this mono-repo, disable branch checkout while experimenting:
AGENT_CMD="printf 'hello\n<promise>COMPLETE</promise>\n'" RALPH_BRANCH="" ./scripts/ralph/ralph.sh 1# Run with default settings (codex agent, 10 iterations)
./scripts/ralph/ralph.sh
# Specify max iterations
./scripts/ralph/ralph.sh 25
# Run from project root (script finds its own location)
cd /path/to/your-project
./scripts/ralph/ralph.sh 50# Use OpenAI Codex (default)
./scripts/ralph/ralph.sh 25
# Use Codex with a specific model
MODEL=gpt-5-codex ./scripts/ralph/ralph.sh 25
# Use Claude CLI
AGENT_CMD="claude --print" ./scripts/ralph/ralph.sh 25
# Use Anthropic API directly via curl
AGENT_CMD="curl -s https://api.anthropic.com/v1/messages -H 'x-api-key: $ANTHROPIC_API_KEY' ..." ./scripts/ralph/ralph.sh 25
# Use any CLI that reads from stdin
AGENT_CMD="my-custom-agent --input-stdin" ./scripts/ralph/ralph.sh 25# Faster iterations (1 second between each)
SLEEP_SECONDS=1 ./scripts/ralph/ralph.sh 25
# Slower iterations (10 seconds, for rate-limited APIs)
SLEEP_SECONDS=10 ./scripts/ralph/ralph.sh 25
# No delay (not recommended for most APIs)
SLEEP_SECONDS=0 ./scripts/ralph/ralph.sh 25# Dry run - see what prompt would be sent (no actual agent call)
AGENT_CMD="cat" ./scripts/ralph/ralph.sh 1
# Dry run - discard output silently
AGENT_CMD="cat > /dev/null" ./scripts/ralph/ralph.sh 1
# Test completion detection
AGENT_CMD="echo '<promise>COMPLETE</promise>'" ./scripts/ralph/ralph.sh 1
# Log all output to a file while running
./scripts/ralph/ralph.sh 25 2>&1 | tee ralph-output.log# Pause after each iteration for human review
INTERACTIVE=1 ./scripts/ralph/ralph.sh 25
# Interactive mode with Claude
INTERACTIVE=1 AGENT_CMD="claude --print" ./scripts/ralph/ralph.sh 25When interactive mode is enabled, Ralph pauses after each iteration and prompts:
- Enter - Continue to next iteration
- s - Skip to autonomous mode (disable pausing)
- q - Quit immediately
This lets you review the agent's changes, edit files manually, or adjust the PRD between iterations.
# Claude with fast iterations and high limit
AGENT_CMD="claude --print" SLEEP_SECONDS=1 ./scripts/ralph/ralph.sh 50
# Codex with custom delay
MODEL=gpt-5-codex SLEEP_SECONDS=5 ./scripts/ralph/ralph.sh 30
# Interactive Claude with slow iterations
INTERACTIVE=1 AGENT_CMD="claude --print" SLEEP_SECONDS=5 ./scripts/ralph/ralph.sh 25| Variable | Default | Description |
|---|---|---|
AGENT_CMD |
(empty) | Custom agent command (prompt piped to stdin). Takes precedence over codex. |
MODEL |
(empty) | Model override for codex (passed as codex -m ...). If unset, codex uses its own defaults from ~/.codex/config.toml. |
MODEL_REASONING_EFFORT |
(empty) | Codex reasoning effort override (passed as codex -c model_reasoning_effort="..."). Common values are low, medium, high, xhigh (model-dependent). |
SLEEP_SECONDS |
2 |
Seconds to wait between iterations |
INTERACTIVE |
(empty) | Set to 1 for human-in-the-loop mode (pause after each iteration) |
PROMPT_FILE |
scripts/ralph/prompt.md |
Override prompt file path |
ALLOWED_PATHS |
(empty) | Comma-separated repo-root-relative paths allowed to change (git repos only). Entries can be exact files or directory prefixes ending with /. Set to empty (ALLOWED_PATHS="") to disable enforcement. |
PRD_FILE |
scripts/ralph/prd.json |
PRD file path used for branch selection (git repos only) |
RALPH_BRANCH |
(unset) | Branch to checkout/create before running (git repos only). If set to empty (RALPH_BRANCH=""), branch checkout is skipped. Takes precedence over PRD branchName when non-empty. |
RALPH_UI |
auto |
UI mode: auto (use gum if available), gum (force), plain (disable gum) |
GUM_FORCE |
(empty) | If set to 1, force gum even when not a TTY (not recommended for CI logs) |
NO_COLOR |
(empty) | Disable ANSI colors |
RALPH_ASCII |
(empty) | If set to 1, use ASCII separators instead of box-drawing chars |
RALPH_AI_SHOW_PROMPT |
(empty) | Show the prompt echoed by Codex in logs (by default it is collapsed/hidden) |
RALPH_AI_RAW |
(empty) | Stream raw Codex output (disables the Codex transcript pretty-printer) |
RALPH_AI_PROMPT_PROGRESS_EVERY |
50 |
When the Codex echoed prompt is hidden, print a progress line every N suppressed lines (set to 0 to disable) |
# Use codex with a specific model
MODEL=gpt-5-codex ./scripts/ralph/ralph.sh 25
# Use a custom agent command (prompt is piped to stdin)
AGENT_CMD="claude --print" ./scripts/ralph/ralph.sh 25
# Human-in-the-loop mode (pause after each iteration)
INTERACTIVE=1 ./scripts/ralph/ralph.sh 25
# Use any CLI that accepts stdin
AGENT_CMD="my-agent --stdin --json" ./scripts/ralph/ralph.sh 25
# Dry run with a no-op agent (useful for testing)
AGENT_CMD="cat > /dev/null" ./scripts/ralph/ralph.sh 1
# Faster iteration (1 second delay)
SLEEP_SECONDS=1 ./scripts/ralph/ralph.sh 25The prd.json file must conform to this schema:
| Field | Type | Description |
|---|---|---|
branchName |
string |
Git branch name for this feature |
userStories |
array |
Array of user story objects |
Each user story object:
| Field | Type | Description |
|---|---|---|
id |
string |
Unique identifier (e.g., "US-001") |
title |
string |
Brief description of the story |
acceptanceCriteria |
string[] |
Explicit, testable, ordered checks |
priority |
integer |
Lower = higher priority (unique, starting at 1) |
passes |
boolean |
Whether all criteria are met (start as false) |
notes |
string |
Agent notes/observations |
From prd_prompt.txt:
- Stories must be small and atomic: each story should be implementable and verifiable in a single iteration
- Acceptance criteria must be testable: explicit checks with expected outcomes
- Priorities must be unique: lower number = higher priority, starting at 1
- Don't invent UI or endpoints: only reference what exists in your codebase
- Cover core flows first: then important edge cases
The agent signals completion by outputting:
<promise>COMPLETE</promise>
When Ralph detects this in the agent's output, it exits successfully (code 0).
| Code | Meaning |
|---|---|
0 |
All stories complete (agent signaled <promise>COMPLETE</promise>) |
1 |
Max iterations reached without completion, or missing required files |
2 |
Configuration error (invalid arguments) |
| File | Required | Purpose |
|---|---|---|
ralph.sh |
Yes | Main loop script (lives in scripts/ralph/) |
prompt.md |
Yes (feature mode) | AI agent instructions for feature work |
prd.json |
Yes (feature mode) | User stories and acceptance criteria (auto-created by init.sh if missing) |
progress.txt |
No | Running log of patterns and progress (auto-created by init.sh if missing) |
init.sh |
No | Initialization/validation script (creates optional files + validates PRD) |
prd_prompt.txt |
No | Fillable template for generating PRDs with an LLM |
understand_prompt.md |
Yes (understanding mode) | Read-only prompt for codebase understanding (auto-created by init.sh if missing) |
codebase_map.md |
No | Output file for the codebase map (auto-created by init.sh if missing) |
ralph-understand.sh |
No | Convenience wrapper for understanding mode (auto-created by init.sh if missing) |
ui.sh |
No | Output/UI helpers (uses gum if installed; falls back to plain output) |
- Start small: Begin with 1-2 user stories to validate your prompt works
- Be specific: Acceptance criteria should be testable and unambiguous
- Use progress.txt: Encourage the agent to log patterns it discovers
- Set realistic limits: Complex features may need 20-50 iterations
- Monitor output: The loop streams agent output so you can watch progress
- Generate PRDs: Use
prd_prompt.txtwith your favorite LLM to create well-structured PRDs
MIT