Files
fete/ralph.sh
nitrix 7b460dd322 initial commit
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 13:03:47 +01:00

165 lines
4.1 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage: ralph.sh <run-directory> [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" <<EOF
# Run: $RUN_NAME
- **Created**: $TODAY
- **Description**: (add description here)
- **Model**: $MODEL
- **Max iterations**: $MAX_ITERATIONS
EOF
echo "Created $RUN_DIR/meta.md"
fi
if [[ ! -f "$RUN_DIR/chief-wiggum.md" ]]; then
cat > "$RUN_DIR/chief-wiggum.md" <<'EOF'
# Chief Wiggum's Notes
<!-- This file is written by the Chief Wiggum session. Ralph reads it but never modifies it. -->
## 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
<!-- Human answers to open questions. Ralph processes these one per iteration. -->
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="<promise>COMPLETE</promise>"
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