diff --git a/documentation/docs/tutorials/ralph-loop.md b/documentation/docs/tutorials/ralph-loop.md new file mode 100644 index 000000000000..f99e57298f0f --- /dev/null +++ b/documentation/docs/tutorials/ralph-loop.md @@ -0,0 +1,539 @@ +--- +title: Ralph Loop +description: Run goose in a loop with fresh context per iteration and cross-model review +--- + +Ralph Loop, based on [Geoffrey Huntley's Ralph Wiggum technique](https://ghuntley.com/ralph/), is an iterative development pattern that keeps goose working on a task until it's genuinely complete. + +Standard agent loops suffer from context accumulation. Every failed attempt stays in the conversation history, which means that after a few iterations, the model must process a long history of noise before it can focus on the task. Ralph Loop solves this by starting each iteration with fresh context, the core insight behind Geoffrey's approach. This implementation extends the technique with cross-model review: one model does the work, a different model reviews it, and the loop continues until the task is ready to ship. + +After each iteration, the worker and reviewer models store a summary and feedback in files. These files persist between iterations but the conversation history does not. This allows a new session to start where the next model reads the files to pick up exactly where the last iteration left off. + +In this tutorial, we'll use Ralph Loop to build a simple Electron-based browser and see how the iteration cycle catches missing features before shipping. + +### Prerequisites + +- [Install the goose CLI](/docs/getting-started/installation) because the Ralph Loop runs via the terminal. +- [Configure two models](/docs/getting-started/providers) to serve as the worker and reviewer. Using different models is recommended for higher quality reviews, though the loop still works if you use the same model for both roles. + +
+Download the Ralph Loop Recipes + +Copy and paste this in your terminal to download the Ralph Loop recipes: + +```bash +mkdir -p ~/.config/goose/recipes + +curl -sL https://raw.githubusercontent.com/block/goose/main/documentation/src/pages/recipes/data/recipes/ralph-loop.sh -o ~/.config/goose/recipes/ralph-loop.sh +curl -sL https://raw.githubusercontent.com/block/goose/main/documentation/src/pages/recipes/data/recipes/ralph-work.yaml -o ~/.config/goose/recipes/ralph-work.yaml +curl -sL https://raw.githubusercontent.com/block/goose/main/documentation/src/pages/recipes/data/recipes/ralph-review.yaml -o ~/.config/goose/recipes/ralph-review.yaml + +chmod +x ~/.config/goose/recipes/ralph-loop.sh +``` + +
+ +:::warning Cost Warning +Ralph Loop runs your agent multiple times in a loop (up to 10 iterations by default). Monitor your usage and adjust `RALPH_MAX_ITERATIONS` if needed. +::: + +### Step 1: Start the Loop + +To start the process, run the script from your terminal and provide your prompt in quotes. This command triggers the first iteration of the worker and reviewer cycle: + +```bash +~/.config/goose/recipes/ralph-loop.sh "Create a simple browser using Electron and React" +``` + +:::tip For Complex Tasks +You can pass a file path instead of a string. This works well for PRDs, detailed specs, or any multi-step task that benefits from iterative development: + +```bash +~/.config/goose/recipes/ralph-loop.sh ./prd.md +``` +::: + +### Step 2: Configure Models + +The script will ask you to set your environment variables for the session: + +``` +Worker model [gpt-4o]: +Worker provider [openai]: +Reviewer model (should be different from worker): claude-sonnet-4-20250514 +Reviewer provider: anthropic +Max iterations [10]: + +⚠️ Cost Warning: This will run up to 10 iterations, each using both models. + Estimated token usage could be significant depending on your task. + +Continue? [y/N]: y +``` + +| Variable | Description | +|--------|-------------| +| Worker model | The model that does the actual coding work. Defaults to `GOOSE_MODEL` if set. | +| Worker provider | The provider for the worker model (e.g., `openai`, `anthropic`). Defaults to `GOOSE_PROVIDER` if set. | +| Reviewer model | The model that reviews the work. Should be different from the worker for best results. | +| Reviewer provider | The provider for the reviewer model. | +| Max iterations | How many work/review cycles before giving up. Defaults to 10. | + +:::tip Directly Set Environment Variables +You can skip the interactive prompts by setting environment variables directly + +```bash +RALPH_WORKER_MODEL="gpt-4o" \ +RALPH_WORKER_PROVIDER="openai" \ +RALPH_REVIEWER_MODEL="claude-sonnet-4-20250514" \ +RALPH_REVIEWER_PROVIDER="anthropic" \ +~/.config/goose/recipes/ralph-loop.sh "Create a simple browser using Electron and React" +``` +::: + +### Step 3: Watch It Run + +The terminal will show goose moving through the worker and reviewer phases. Each iteration starts with a fresh session to keep the context clean. Here's what a successful run looks like: + +``` +═══════════════════════════════════════════════════════════════ + Ralph Loop - Multi-Model Edition +═══════════════════════════════════════════════════════════════ + + Task: Create a simple browser using Electron and React + Worker: gpt-4o (openai) + Reviewer: claude-sonnet-4-20250514 (anthropic) + Max Iterations: 10 + +─────────────────────────────────────────────────────────────── + Iteration 1 / 10 +─────────────────────────────────────────────────────────────── + +▶ WORK PHASE +... (goose creates initial implementation) ... + +▶ REVIEW PHASE +... (goose reviews the work) ... + +↻ REVISE - Feedback for next iteration: +Missing error handling for invalid URLs. Also needs back/forward navigation buttons. + +─────────────────────────────────────────────────────────────── + Iteration 2 / 10 +─────────────────────────────────────────────────────────────── + +▶ WORK PHASE +... (goose addresses feedback) ... + +▶ REVIEW PHASE +... (goose reviews again) ... + +═══════════════════════════════════════════════════════════════ + ✓ SHIPPED after 2 iteration(s) +═══════════════════════════════════════════════════════════════ +``` + +## How It Works + +``` +Iteration 1: + WORK PHASE → Model A does work, writes to files + REVIEW PHASE → Model B reviews the work + → SHIP? Exit successfully ✓ + → REVISE? Write feedback, continue to iteration 2 + +Iteration 2: + WORK PHASE → Model A reads feedback, fixes things (fresh context!) + REVIEW PHASE → Model B reviews again + → SHIP? Exit successfully ✓ + → REVISE? Continue... + +... repeats until SHIP or max iterations +``` + +### State Files + +Ralph Loop uses files in `.goose/ralph/` to persist state between iterations. This is how the worker knows what to do and the reviewer knows what was done, even though each iteration starts with fresh context. + +| File | Purpose | +|------|---------| +| `task.md` | The task description | +| `iteration.txt` | Current iteration number | +| `work-summary.txt` | What the worker did this iteration | +| `work-complete.txt` | Exists when worker claims done | +| `review-result.txt` | `SHIP` or `REVISE` | +| `review-feedback.txt` | Feedback for next iteration | +| `.ralph-complete` | Created on successful completion | +| `RALPH-BLOCKED.md` | Created if worker is stuck | + +### Recipe Files + +The Ralph Loop uses three files: a bash script that orchestrates the work/review cycle, a work recipe that tells the worker model how to make progress, and a review recipe that tells the reviewer model how to evaluate the work. Below are the contents of each file. You can [download](#prerequisites) them or copy directly from here. + +
+The Bash Wrapper (`ralph-loop.sh`) + +```bash +#!/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 +``` + +
+ +
+Work Phase Recipe (`ralph-work.yaml`) + +```yaml +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 +``` + +
+ +
+Review Phase Recipe (`ralph-review.yaml`) + +```yaml +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 +``` + +
+ +## Usage Tips + +### When to Use Ralph Loop + +Ralph Loop works best for: + +- **Complex, multi-step tasks** that benefit from iteration +- **Tasks with clear completion criteria** (tests pass, builds succeed) +- **Situations where you want quality gates** before shipping + +It's overkill for: + +- Simple one-shot tasks +- Interactive/exploratory work +- Tasks without verifiable completion criteria + +### Resetting + +If you want to start a completely new task, or if a previous run got stuck and you want to start over, you can clear the state directory: + +```bash +rm -rf .goose/ralph +``` + diff --git a/documentation/src/pages/recipes/data/recipes/ralph-loop.sh b/documentation/src/pages/recipes/data/recipes/ralph-loop.sh new file mode 100644 index 000000000000..122326b09297 --- /dev/null +++ b/documentation/src/pages/recipes/data/recipes/ralph-loop.sh @@ -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 diff --git a/documentation/src/pages/recipes/data/recipes/ralph-review.yaml b/documentation/src/pages/recipes/data/recipes/ralph-review.yaml new file mode 100644 index 000000000000..6b7f739c3eda --- /dev/null +++ b/documentation/src/pages/recipes/data/recipes/ralph-review.yaml @@ -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 diff --git a/documentation/src/pages/recipes/data/recipes/ralph-work.yaml b/documentation/src/pages/recipes/data/recipes/ralph-work.yaml new file mode 100644 index 000000000000..590dd24c5edb --- /dev/null +++ b/documentation/src/pages/recipes/data/recipes/ralph-work.yaml @@ -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