#!/usr/bin/env bash set -euo pipefail usage() { cat <<'EOF' Usage: ralph.sh [options] Arguments: run-directory Path to the Ralph run directory (must contain instructions.md) Options: -n, --max-iterations N Maximum iterations (default: 20) -m, --model MODEL Claude model to use (default: opus) -t, --tools TOOLS Allowed tools, quoted (default: "Read Edit Write") -h, --help Show this help message Examples: ./ralph.sh .ralph/my-run ./ralph.sh .ralph/my-run -n 10 -m sonnet ./ralph.sh .ralph/my-run -n 30 -t "Read Edit Write Bash Glob Grep" EOF exit 0 } # Defaults MAX_ITERATIONS=20 MODEL="opus" TOOLS="Read Edit Write" RUN_DIR="" # Parse args while [[ $# -gt 0 ]]; do case $1 in -n|--max-iterations) MAX_ITERATIONS="$2"; shift 2 ;; -m|--model) MODEL="$2"; shift 2 ;; -t|--tools) TOOLS="$2"; shift 2 ;; -h|--help) usage ;; -*) echo "Error: Unknown option: $1" >&2; exit 1 ;; *) RUN_DIR="$1"; shift ;; esac done if [[ -z "$RUN_DIR" ]]; then echo "Error: No run directory specified." >&2 echo "Run './ralph.sh --help' for usage." >&2 exit 1 fi if [[ ! -d "$RUN_DIR" ]]; then echo "Error: Run directory '$RUN_DIR' does not exist." >&2 exit 1 fi if [[ ! -f "$RUN_DIR/instructions.md" ]]; then echo "Error: '$RUN_DIR/instructions.md' not found." >&2 echo "Create an instructions.md in the run directory before starting." >&2 exit 1 fi # Auto-create template files if they don't exist RUN_NAME=$(basename "$RUN_DIR") TODAY=$(date +%Y-%m-%d) if [[ ! -f "$RUN_DIR/meta.md" ]]; then cat > "$RUN_DIR/meta.md" < "$RUN_DIR/chief-wiggum.md" <<'EOF' # Chief Wiggum's Notes ## Action Required (No action items.) ## Observations (No observations.) EOF echo "Created $RUN_DIR/chief-wiggum.md" fi if [[ ! -f "$RUN_DIR/answers.md" ]]; then cat > "$RUN_DIR/answers.md" <<'EOF' # Answers EOF echo "Created $RUN_DIR/answers.md" fi if [[ ! -f "$RUN_DIR/questions.md" ]]; then cat > "$RUN_DIR/questions.md" <<'EOF' # Questions ## Open (No open questions.) ## Resolved (No resolved questions.) EOF echo "Created $RUN_DIR/questions.md" fi if [[ ! -f "$RUN_DIR/progress.txt" ]]; then cat > "$RUN_DIR/progress.txt" <<'EOF' # Ralph Loop Progress Log # Each iteration appends its findings and decisions here. EOF echo "Created $RUN_DIR/progress.txt" fi # Prepare prompt with {{RUN_DIR}} substitution PROMPT=$(sed "s|{{RUN_DIR}}|$RUN_DIR|g" "$RUN_DIR/instructions.md") COMPLETION_SIGNAL="COMPLETE" TIMESTAMP=$(date +%Y-%m-%dT%H:%M:%S) # Append to run.log echo "" >> "$RUN_DIR/run.log" echo "=== Run started: $TIMESTAMP | model=$MODEL | max=$MAX_ITERATIONS ===" >> "$RUN_DIR/run.log" echo "=== Ralph Loop ===" echo "Run dir: $RUN_DIR" echo "Model: $MODEL" echo "Max iter: $MAX_ITERATIONS" echo "Tools: $TOOLS" echo "" for ((i = 1; i <= MAX_ITERATIONS; i++)); do echo "--- Iteration $i/$MAX_ITERATIONS ---" OUTPUT=$(echo "$PROMPT" | claude --print --model "$MODEL" --allowedTools "$TOOLS" 2>&1) ITER_TIME=$(date +%H:%M:%S) if [[ "$OUTPUT" == *"$COMPLETION_SIGNAL"* ]]; then echo "[$ITER_TIME] COMPLETE after $i iteration(s)" >> "$RUN_DIR/run.log" echo "Loop complete after $i iteration(s)." exit 0 fi echo "[$ITER_TIME] Iteration $i done" >> "$RUN_DIR/run.log" echo "Iteration $i done. Continuing..." echo "" sleep 2 done ITER_TIME=$(date +%H:%M:%S) echo "[$ITER_TIME] WARNING: Max iterations ($MAX_ITERATIONS) reached without completion" >> "$RUN_DIR/run.log" echo "WARNING: Max iterations ($MAX_ITERATIONS) reached without completion." exit 1