ralph
Ralph — Autonomous Agent Runner
Ralph is a bash script that runs Claude autonomously to implement features from a PRD. It processes one user story per iteration, commits after each, and stops when the PRD is complete.
First-time Setup
When the user first invokes Ralph, check if the project is set up:
- If
ralph.shdoesn't exist in the project root, create it fromreferences/ralph-script.md(in this skill's directory) - Make it executable:
chmod +x ralph.sh - Add to
.gitignoreif not already present:prd.json,progress.txt - Create
tasks/directory if it doesn't exist - Create empty
progress.txtif it doesn't exist - Verify
jqis installed (which jq); if not, tell the user to install it (brew install jq)
Workflow
- Create a PRD using the
prdskill → saves totasks/prd-[feature-name].md - Convert the PRD to
prd.jsonusing the conversion rules below - Run Ralph in a separate terminal:
./ralph.sh 10(number = max iterations) - Wait for completion — Ralph implements each story and commits
PRD to prd.json Conversion
Output Format
{
"project": "[Project Name]",
"branchName": "ralph/[feature-name-kebab-case]",
"description": "[Feature description from PRD title/intro]",
"userStories": [
{
"id": "US-001",
"title": "[Story title]",
"description": "As a [user], I want [feature] so that [benefit]",
"acceptanceCriteria": [
"Criterion 1",
"Criterion 2",
"Typecheck passes"
],
"priority": 1,
"passes": false,
"notes": ""
}
]
}
Conversion Rules
- Each user story becomes one JSON entry
- IDs: Sequential (US-001, US-002, etc.)
- Priority: Based on dependency order, then document order
- All stories:
passes: falseand emptynotes - branchName: Derive from feature name, kebab-case, prefixed with
ralph/ - Always add: "Typecheck passes" to every story's acceptance criteria
Story Size: The Number One Rule
Each story must be completable in ONE Ralph iteration (one context window).
Ralph spawns a fresh Claude instance per iteration with no memory of previous work. If a story is too big, the LLM runs out of context before finishing and produces broken code.
Right-sized stories:
- Add a database column and migration
- Add a UI component to an existing page
- Update a server action with new logic
- Add a filter dropdown to a list
Too big (split these):
- "Build the entire dashboard" → Split into: schema, queries, UI components, filters
- "Add authentication" → Split into: schema, middleware, login UI, session handling
- "Refactor the API" → Split into one story per endpoint or pattern
Rule of thumb: If you cannot describe the change in 2-3 sentences, it is too big.
Story Ordering: Dependencies First
Stories execute in priority order. Earlier stories must not depend on later ones.
Correct order:
- Schema/database changes (migrations)
- Server actions / backend logic
- UI components that use the backend
- Dashboard/summary views that aggregate data
Wrong order:
- UI component (depends on schema that does not exist yet)
- Schema change
Acceptance Criteria: Must Be Verifiable
Each criterion must be something Ralph can CHECK, not something vague.
Good criteria (verifiable):
- "Add
statuscolumn to tasks table with default 'pending'" - "Filter dropdown has options: All, Active, Completed"
- "Clicking delete shows confirmation dialog"
- "Typecheck passes"
- "Tests pass"
Bad criteria (vague):
- "Works correctly"
- "User can do X easily"
- "Good UX"
- "Handles edge cases"
Always include as final criterion:
"Typecheck passes"
For stories with testable logic, also include:
"Tests pass"
For stories that change UI, also include:
"Verify in browser"
Frontend stories are NOT complete until visually verified in the browser.
Archiving Previous Runs & Reset
Before writing a new prd.json, check if there is an existing one from a different feature:
- Read the current
prd.jsonif it exists - Check if
branchNamediffers from the new feature's branch name - If different AND
progress.txthas content:- Create archive folder:
archive/YYYY-MM-DD-feature-name/ - Copy current
prd.jsonandprogress.txtto archive
- Create archive folder:
ALWAYS reset progress.txt:
After writing the new prd.json, reset progress.txt to empty:
echo "" > progress.txt
How Ralph Works (for reference)
Each iteration:
- Find highest-priority story with
passes: false - Implement the feature
- Run type checks
- Update
prd.json: setpasses: trueand add notes - Append progress to
progress.txt - Create a git commit
Stops when all stories have passes: true or iterations exhausted.
Running Ralph
./ralph.sh 10 # Run up to 10 iterations
Requirements
jqinstalled (brew install jq)- Claude CLI configured and authenticated
Safety
- Ralph auto-switches to the branch specified in
prd.json - Refuses to run on
mainormaster
Checklist Before Saving prd.json
- Previous run archived (if prd.json exists with different branchName)
- Each story is completable in one iteration (small enough)
- Stories are ordered by dependency (schema → backend → UI)
- Every story has "Typecheck passes" as criterion
- UI stories have "Verify in browser" as criterion
- Acceptance criteria are verifiable (not vague)
- No story depends on a later story
- progress.txt reset to empty after writing prd.json