docs: add Ralph Loop tutorial for multi-model iterative development (#6455)

This commit is contained in:
Rizel Scarlett
2026-01-13 15:21:03 -05:00
committed by GitHub
parent 653fa3a712
commit 1c0895e6b4
4 changed files with 859 additions and 0 deletions
@@ -0,0 +1,219 @@
#!/bin/bash
#
# Ralph Loop - Multi-Model Edition
#
# Fresh context per iteration + cross-model review
# Based on Geoffrey Huntley's technique
#
# Usage: ./ralph-loop.sh "your task description here"
# or: ./ralph-loop.sh /path/to/task.md
#
# Environment variables:
# RALPH_WORKER_MODEL - Model for work phase (prompts if not set)
# RALPH_WORKER_PROVIDER - Provider for work phase (prompts if not set)
# RALPH_REVIEWER_MODEL - Model for review phase (prompts if not set)
# RALPH_REVIEWER_PROVIDER - Provider for review phase (prompts if not set)
# RALPH_MAX_ITERATIONS - Max iterations (default: 10)
# RALPH_RECIPE_DIR - Recipe directory (default: ~/.config/goose/recipes)
#
set -e
INPUT="$1"
RECIPE_DIR="${RALPH_RECIPE_DIR:-$HOME/.config/goose/recipes}"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
if [ -z "$INPUT" ]; then
echo -e "${RED}Error: No task provided${NC}"
echo "Usage: $0 \"your task description\""
echo " or: $0 /path/to/task.md"
exit 1
fi
# Function to prompt for settings
prompt_for_settings() {
local default_model="${GOOSE_MODEL:-}"
local default_provider="${GOOSE_PROVIDER:-}"
# Worker model
if [ -n "$default_model" ]; then
echo -ne "${BLUE}Worker model${NC} [${default_model}]: "
read -r user_input
WORKER_MODEL="${user_input:-$default_model}"
else
echo -ne "${BLUE}Worker model${NC}: "
read -r WORKER_MODEL
if [ -z "$WORKER_MODEL" ]; then
echo -e "${RED}Error: Worker model is required${NC}"
exit 1
fi
fi
# Worker provider
if [ -n "$default_provider" ]; then
echo -ne "${BLUE}Worker provider${NC} [${default_provider}]: "
read -r user_input
WORKER_PROVIDER="${user_input:-$default_provider}"
else
echo -ne "${BLUE}Worker provider${NC}: "
read -r WORKER_PROVIDER
if [ -z "$WORKER_PROVIDER" ]; then
echo -e "${RED}Error: Worker provider is required${NC}"
exit 1
fi
fi
# Reviewer model
echo -ne "${BLUE}Reviewer model${NC} (should be different from worker): "
read -r REVIEWER_MODEL
if [ -z "$REVIEWER_MODEL" ]; then
echo -e "${RED}Error: Reviewer model is required${NC}"
echo "The reviewer should be a different model to provide fresh perspective."
exit 1
fi
# Reviewer provider
echo -ne "${BLUE}Reviewer provider${NC}: "
read -r REVIEWER_PROVIDER
if [ -z "$REVIEWER_PROVIDER" ]; then
echo -e "${RED}Error: Reviewer provider is required${NC}"
exit 1
fi
# Same model warning
if [ "$WORKER_MODEL" = "$REVIEWER_MODEL" ] && [ "$WORKER_PROVIDER" = "$REVIEWER_PROVIDER" ]; then
echo -e "${YELLOW}Warning: Worker and reviewer are the same model.${NC}"
echo "For best results, use different models for cross-model review."
echo -ne "Continue anyway? [y/N]: "
read -r confirm
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
exit 1
fi
fi
# Max iterations
echo -ne "${BLUE}Max iterations${NC} [10]: "
read -r user_input
MAX_ITERATIONS="${user_input:-10}"
}
# Initialize from environment variables
WORKER_MODEL="${RALPH_WORKER_MODEL:-}"
WORKER_PROVIDER="${RALPH_WORKER_PROVIDER:-}"
REVIEWER_MODEL="${RALPH_REVIEWER_MODEL:-}"
REVIEWER_PROVIDER="${RALPH_REVIEWER_PROVIDER:-}"
MAX_ITERATIONS="${RALPH_MAX_ITERATIONS:-10}"
# If any required setting is missing, prompt for all settings
if [ -z "$WORKER_MODEL" ] || [ -z "$WORKER_PROVIDER" ] || [ -z "$REVIEWER_MODEL" ] || [ -z "$REVIEWER_PROVIDER" ]; then
prompt_for_settings
fi
# Cost warning and confirmation loop
while true; do
echo ""
echo -e "${YELLOW}⚠️ Cost Warning:${NC} This will run up to ${MAX_ITERATIONS} iterations, each using both models."
echo " Estimated token usage could be significant depending on your task."
echo ""
echo -ne "Continue? [y/N]: "
read -r confirm
if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ]; then
break
else
echo ""
prompt_for_settings
fi
done
STATE_DIR=".goose/ralph"
mkdir -p "$STATE_DIR"
if [ -f "$INPUT" ]; then
cp "$INPUT" "$STATE_DIR/task.md"
echo -e "${BLUE}Reading task from file: $INPUT${NC}"
else
echo "$INPUT" > "$STATE_DIR/task.md"
fi
TASK=$(cat "$STATE_DIR/task.md")
rm -f "$STATE_DIR/review-result.txt"
rm -f "$STATE_DIR/review-feedback.txt"
rm -f "$STATE_DIR/work-complete.txt"
rm -f "$STATE_DIR/work-summary.txt"
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
echo -e "${BLUE} Ralph Loop - Multi-Model Edition${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}"
echo ""
echo -e " Task: ${YELLOW}$TASK${NC}"
echo -e " Worker: ${WORKER_MODEL} (${WORKER_PROVIDER})"
echo -e " Reviewer: ${REVIEWER_MODEL} (${REVIEWER_PROVIDER})"
echo -e " Max Iterations: $MAX_ITERATIONS"
echo ""
for i in $(seq 1 "$MAX_ITERATIONS"); do
echo -e "${BLUE}───────────────────────────────────────────────────────────────${NC}"
echo -e "${BLUE} Iteration $i / $MAX_ITERATIONS${NC}"
echo -e "${BLUE}───────────────────────────────────────────────────────────────${NC}"
echo "$i" > "$STATE_DIR/iteration.txt"
echo ""
echo -e "${YELLOW}▶ WORK PHASE${NC}"
GOOSE_PROVIDER="$WORKER_PROVIDER" GOOSE_MODEL="$WORKER_MODEL" goose run --recipe "$RECIPE_DIR/ralph-work.yaml" || {
echo -e "${RED}✗ WORK PHASE FAILED${NC}"
exit 1
}
if [ -f "$STATE_DIR/RALPH-BLOCKED.md" ]; then
echo ""
echo -e "${RED}✗ BLOCKED${NC}"
cat "$STATE_DIR/RALPH-BLOCKED.md"
exit 1
fi
echo ""
echo -e "${YELLOW}▶ REVIEW PHASE${NC}"
GOOSE_PROVIDER="$REVIEWER_PROVIDER" GOOSE_MODEL="$REVIEWER_MODEL" goose run --recipe "$RECIPE_DIR/ralph-review.yaml" || {
echo -e "${RED}✗ REVIEW PHASE FAILED${NC}"
exit 1
}
if [ -f "$STATE_DIR/review-result.txt" ]; then
RESULT=$(cat "$STATE_DIR/review-result.txt" | tr -d '[:space:]')
if [ "$RESULT" = "SHIP" ]; then
echo ""
echo -e "${GREEN}═══════════════════════════════════════════════════════════════${NC}"
echo -e "${GREEN} ✓ SHIPPED after $i iteration(s)${NC}"
echo -e "${GREEN}═══════════════════════════════════════════════════════════════${NC}"
echo "COMPLETE: $(date)" > "$STATE_DIR/.ralph-complete"
exit 0
else
echo ""
echo -e "${YELLOW}↻ REVISE - Feedback for next iteration:${NC}"
if [ -f "$STATE_DIR/review-feedback.txt" ]; then
cat "$STATE_DIR/review-feedback.txt"
fi
fi
else
echo -e "${RED}✗ No review result found${NC}"
exit 1
fi
rm -f "$STATE_DIR/work-complete.txt"
rm -f "$STATE_DIR/review-result.txt"
echo ""
done
echo -e "${RED}✗ Max iterations ($MAX_ITERATIONS) reached${NC}"
exit 1
@@ -0,0 +1,53 @@
version: 1.0.0
title: Ralph Review Phase
description: Cross-model review of work - returns SHIP or REVISE
instructions: |
You are a CODE REVIEWER in a Ralph Loop.
Your job: Review the work done and decide SHIP or REVISE.
You are a DIFFERENT MODEL than the worker. Your fresh perspective catches mistakes.
STATE FILES (in .goose/ralph/):
- task.md = The original task (READ THIS FIRST)
- work-summary.txt = What the worker claims to have done
- work-complete.txt = Exists if worker claims task is complete
REVIEW CRITERIA:
1. Does the code/work actually accomplish the task?
2. Does it run without errors?
3. Is it reasonably complete, not half-done?
4. Are there obvious bugs or issues?
BE STRICT but FAIR:
- Don't nitpick style if functionality is correct
- DO reject incomplete work
- DO reject code that doesn't run
- DO reject if tests fail
OUTPUT:
If approved: echo "SHIP" > .goose/ralph/review-result.txt
If needs work:
echo "REVISE" > .goose/ralph/review-result.txt
echo "specific feedback" > .goose/ralph/review-feedback.txt
prompt: |
## Ralph Review Phase
1. Read the task: `cat .goose/ralph/task.md`
2. Read work summary: `cat .goose/ralph/work-summary.txt`
3. Check if complete: `cat .goose/ralph/work-complete.txt 2>/dev/null`
4. Examine the actual files created/modified
5. Run verification (tests, build, etc.)
6. Decide: SHIP or REVISE
If SHIP: `echo "SHIP" > .goose/ralph/review-result.txt`
If REVISE:
`echo "REVISE" > .goose/ralph/review-result.txt`
`echo "specific feedback" > .goose/ralph/review-feedback.txt`
extensions:
- type: builtin
name: developer
timeout: 300
@@ -0,0 +1,48 @@
version: 1.0.0
title: Ralph Work Phase
description: Single iteration of work - fresh context each time
instructions: |
You are in a RALPH LOOP - one iteration of work.
Your work persists through FILES ONLY. You will NOT remember previous iterations.
STATE FILES (in .goose/ralph/):
- task.md = The task you need to accomplish (READ THIS FIRST)
- iteration.txt = Current iteration number
- review-feedback.txt = Feedback from last review (if any)
- work-complete.txt = Create when task is DONE (reviewer will verify)
FIRST: Check your state
1. cat .goose/ralph/task.md (YOUR TASK)
2. cat .goose/ralph/iteration.txt 2>/dev/null || echo "1"
3. cat .goose/ralph/review-feedback.txt 2>/dev/null
4. ls -la to see existing work
THEN: Make progress
- If review-feedback.txt exists, ADDRESS THAT FEEDBACK FIRST
- Read existing code/files before modifying
- Make meaningful incremental progress
- Run tests/verification if applicable
FINALLY: Signal status
- If task is complete: echo "done" > .goose/ralph/work-complete.txt
- Always write a summary: echo "what I did" > .goose/ralph/work-summary.txt
prompt: |
## Ralph Work Phase
Read your task from: .goose/ralph/task.md
1. Read the task: `cat .goose/ralph/task.md`
2. Check iteration: `cat .goose/ralph/iteration.txt 2>/dev/null || echo "1"`
3. Check for review feedback: `cat .goose/ralph/review-feedback.txt 2>/dev/null`
4. List existing files: `ls -la`
5. Do the work (address feedback if any, otherwise make progress)
6. Write summary: `echo "summary" > .goose/ralph/work-summary.txt`
7. If complete: `echo "done" > .goose/ralph/work-complete.txt`
extensions:
- type: builtin
name: developer
timeout: 600