claude-code/plugins/ralph-wiggum/scripts/setup-ralph-loop.sh
Daisy S. Hollman 68f90e05dd
feat: Add ralph-wiggum plugin for iterative self-referential development
Migrates the ralph-wiggum plugin from internal marketplace to public marketplace.
Implements Geoffrey Huntley's "Ralph Wiggum" technique using Claude Code's Stop
hook mechanism for continuous iterative development loops.

Key features:
- Interactive self-referential AI loops in current session
- Stop hook intercepts exit and feeds same prompt back
- Iteration tracking and completion promise detection
- Max iterations safety limits

Changes:
- Remove all tmux dependencies and background execution mode
- Simplify to interactive-only mode using Stop hooks
- Add comprehensive error handling with clear messages
- Fix documentation to accurately describe Stop hook mechanism
- Add input validation for all command-line arguments
- Register plugin in public marketplace

Security fixes:
- Remove eval usage (command injection vulnerability)
- Add numeric validation before arithmetic operations
- Remove silent error suppression

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-16 13:53:45 -08:00

176 lines
5.3 KiB
Bash
Executable file

#!/bin/bash
# Ralph Loop Setup Script
# Creates state file for in-session Ralph loop
set -euo pipefail
# Parse arguments
PROMPT_PARTS=()
MAX_ITERATIONS=0
COMPLETION_PROMISE="null"
# Parse options and positional arguments
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
cat << 'HELP_EOF'
Ralph Loop - Interactive self-referential development loop
USAGE:
/ralph-loop [PROMPT...] [OPTIONS]
ARGUMENTS:
PROMPT... Initial prompt to start the loop (can be multiple words without quotes)
OPTIONS:
--max-iterations <n> Maximum iterations before auto-stop (default: unlimited)
--completion-promise '<text>' Promise phrase (USE QUOTES for multi-word)
-h, --help Show this help message
DESCRIPTION:
Starts a Ralph Wiggum loop in your CURRENT session. The stop hook prevents
exit and feeds your output back as input until completion or iteration limit.
To signal completion, you must output: <promise>YOUR_PHRASE</promise>
Use this for:
- Interactive iteration where you want to see progress
- Tasks requiring self-correction and refinement
- Learning how Ralph works
EXAMPLES:
/ralph-loop Build a todo API --completion-promise 'DONE' --max-iterations 20
/ralph-loop --max-iterations 10 Fix the auth bug
/ralph-loop Refactor cache layer (runs forever)
/ralph-loop --completion-promise 'TASK COMPLETE' Create a REST API
STOPPING:
Only by reaching --max-iterations or detecting --completion-promise
No manual stop - Ralph runs infinitely by default!
MONITORING:
# View current iteration:
grep '^iteration:' .claude/ralph-loop.local.md
# View full state:
head -10 .claude/ralph-loop.local.md
HELP_EOF
exit 0
;;
--max-iterations)
if [[ -z "${2:-}" ]]; then
echo "❌ Error: --max-iterations requires a number argument" >&2
echo "" >&2
echo " Valid examples:" >&2
echo " --max-iterations 10" >&2
echo " --max-iterations 50" >&2
echo " --max-iterations 0 (unlimited)" >&2
echo "" >&2
echo " You provided: --max-iterations (with no number)" >&2
exit 1
fi
if ! [[ "$2" =~ ^[0-9]+$ ]]; then
echo "❌ Error: --max-iterations must be a positive integer or 0, got: $2" >&2
echo "" >&2
echo " Valid examples:" >&2
echo " --max-iterations 10" >&2
echo " --max-iterations 50" >&2
echo " --max-iterations 0 (unlimited)" >&2
echo "" >&2
echo " Invalid: decimals (10.5), negative numbers (-5), text" >&2
exit 1
fi
MAX_ITERATIONS="$2"
shift 2
;;
--completion-promise)
if [[ -z "${2:-}" ]]; then
echo "❌ Error: --completion-promise requires a text argument" >&2
echo "" >&2
echo " Valid examples:" >&2
echo " --completion-promise 'DONE'" >&2
echo " --completion-promise 'TASK COMPLETE'" >&2
echo " --completion-promise 'All tests passing'" >&2
echo "" >&2
echo " You provided: --completion-promise (with no text)" >&2
echo "" >&2
echo " Note: Multi-word promises must be quoted!" >&2
exit 1
fi
COMPLETION_PROMISE="$2"
shift 2
;;
*)
# Non-option argument - collect all as prompt parts
PROMPT_PARTS+=("$1")
shift
;;
esac
done
# Join all prompt parts with spaces
PROMPT="${PROMPT_PARTS[*]}"
# Validate prompt is non-empty
if [[ -z "$PROMPT" ]]; then
echo "❌ Error: No prompt provided" >&2
echo "" >&2
echo " Ralph needs a task description to work on." >&2
echo "" >&2
echo " Examples:" >&2
echo " /ralph-loop Build a REST API for todos" >&2
echo " /ralph-loop Fix the auth bug --max-iterations 20" >&2
echo " /ralph-loop --completion-promise 'DONE' Refactor code" >&2
echo "" >&2
echo " For all options: /ralph-loop --help" >&2
exit 1
fi
# Create state file for stop hook (markdown with YAML frontmatter)
mkdir -p .claude
# Quote completion promise for YAML if it contains special chars or is not null
if [[ -n "$COMPLETION_PROMISE" ]] && [[ "$COMPLETION_PROMISE" != "null" ]]; then
COMPLETION_PROMISE_YAML="\"$COMPLETION_PROMISE\""
else
COMPLETION_PROMISE_YAML="null"
fi
cat > .claude/ralph-loop.local.md <<EOF
---
active: true
iteration: 1
max_iterations: $MAX_ITERATIONS
completion_promise: $COMPLETION_PROMISE_YAML
started_at: "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
---
$PROMPT
EOF
# Output setup message
cat <<EOF
🔄 Ralph loop activated in this session!
Iteration: 1
Max iterations: $(if [[ $MAX_ITERATIONS -gt 0 ]]; then echo $MAX_ITERATIONS; else echo "unlimited"; fi)
Completion promise: $(if [[ "$COMPLETION_PROMISE" != "null" ]]; then echo "${COMPLETION_PROMISE//\"/} (ONLY output when TRUE - do not lie!)"; else echo "none (runs forever)"; fi)
The stop hook is now active. When you try to exit, the SAME PROMPT will be
fed back to you. You'll see your previous work in files, creating a
self-referential loop where you iteratively improve on the same task.
To monitor: head -10 .claude/ralph-loop.local.md
⚠️ WARNING: This loop cannot be stopped manually! It will run infinitely
unless you set --max-iterations or --completion-promise.
🔄
EOF
# Output the initial prompt if provided
if [[ -n "$PROMPT" ]]; then
echo ""
echo "$PROMPT"
fi