What it does
Ralph spawns fresh AI coding tool instances (Amp or Claude Code) in a loop, each one picking up the next incomplete user story from a prd.json file. When every story passes, the loop exits. That's the entire concept.
Why I starred it
The idea of wrapping an AI agent in a bash for loop sounds almost too simple to work. But that simplicity is the point. Each iteration gets a clean context window, avoids the token bloat that kills long sessions, and persists memory through the only thing that always survives: git commits.
The pattern comes from Geoffrey Huntley's original Ralph concept, and this repo is the cleanest implementation I've seen. 14k+ stars suggest others agree.
How it works
The entire orchestration lives in ralph.sh -- 113 lines of bash. The core loop at line 84 is almost comically straightforward:
for i in $(seq 1 $MAX_ITERATIONS); do
if [[ "$TOOL" == "amp" ]]; then
OUTPUT=$(cat "$SCRIPT_DIR/prompt.md" | amp --dangerously-allow-all 2>&1 | tee /dev/stderr) || true
else
OUTPUT=$(claude --dangerously-skip-permissions --print < "$SCRIPT_DIR/CLAUDE.md" 2>&1 | tee /dev/stderr) || true
fi
if echo "$OUTPUT" | grep -q "<promise>COMPLETE</promise>"; then
echo "Ralph completed all tasks!"
exit 0
fi
done
The stop condition is a grep for <promise>COMPLETE</promise> in the agent's output. No API calls, no webhooks, no state machine -- just string matching on stdout. The agent itself decides when it's done by checking if all stories in prd.json have passes: true.
Memory model
Each iteration is a blank slate. Memory survives through three channels:
prd.json-- the task list withpassesbooleansprogress.txt-- append-only log where each iteration dumps learnings- Git history -- the actual code changes
The progress.txt approach is clever. The prompt instructs agents to write a "Codebase Patterns" section at the top of the file with reusable discoveries ("sql<number> template for aggregations", "always use IF NOT EXISTS for migrations"). Future iterations read this first, so institutional knowledge accumulates across the run.
Archiving
Lines 43-64 in ralph.sh handle run archiving. When prd.json exists and the branchName field differs from the last run, Ralph copies the old prd.json and progress.txt into archive/YYYY-MM-DD-feature-name/ before starting fresh. State is tracked via a .last-branch file -- minimal but functional.
The skills system
Ralph ships two skills as SKILL.md files: a PRD generator (skills/prd/SKILL.md) and a PRD-to-JSON converter (skills/ralph/SKILL.md). The PRD skill asks 3-5 clarifying questions with lettered options so users can respond "1A, 2C, 3B" for quick iteration. The converter enforces strict story sizing -- each story must fit in one context window, with explicit examples of what's too big ("Build the entire dashboard" -- split it).
The repo also ships a Claude Code plugin manifest (.claude-plugin/plugin.json) for marketplace distribution, so the skills auto-invoke when you say "create a prd" or "convert this prd".
Using it
# Clone and set up
cp ralph.sh scripts/ralph/
cp CLAUDE.md scripts/ralph/
# Generate a PRD interactively
# (via skill: "create a prd for task priority system")
# Convert to ralph format
# (via skill: "convert tasks/prd-task-priority.md to prd.json")
# Let it rip
./scripts/ralph/ralph.sh --tool claude 20
The prd.json format is minimal:
{
"project": "MyApp",
"branchName": "ralph/task-priority",
"userStories": [
{
"id": "US-001",
"title": "Add priority field to database",
"acceptanceCriteria": ["Add priority column", "Typecheck passes"],
"priority": 1,
"passes": false
}
]
}
Each story gets worked in priority order. The agent commits with feat: [Story ID] - [Story Title], updates the JSON, appends to progress.txt, and the next iteration picks up where it left off.
Rough edges
No tests. The repo is a bash script, two prompt files, and a React Flow flowchart for presentations. That's fine for what it is, but it means you're trusting the agent prompts to do the right thing without any verification harness around Ralph itself.
The --dangerously-allow-all and --dangerously-skip-permissions flags are right there in the core loop. Necessary for autonomy, but worth understanding what you're handing over. There's no sandboxing, no rollback mechanism, no budget limits on iterations.
Story sizing is entirely manual. If you write a story that's too big for one context window, Ralph will burn an iteration producing broken code and move on. The skills try to enforce good sizing through documentation, but there's no runtime check.
The Amp-first design shows in small ways -- the Claude Code path was added later, and things like the thread URL format in prompt.md (https://ampcode.com/threads/$AMP_CURRENT_THREAD_ID) are Amp-specific.
Bottom line
Ralph is for anyone running AI coding tools on real projects who's tired of babysitting long sessions. The architecture is almost aggressively simple -- a bash loop, a JSON task list, and append-only memory -- but that's exactly why it works. Context stays fresh, state stays minimal, and the agents do what they're good at: focused, single-task execution.
