Enhance Ralph hook with background task spawning

BREAKING CHANGE: Ralph now runs as background process (non-blocking)

Changes:
- Enhanced ralph-auto-trigger.sh to spawn Ralph in background
- Hook immediately returns to Claude Code (NON-BLOCKING)
- Ralph runs via nohup (survives terminal close)
- Added PID tracking: ~/.claude/ralph.pid
- Added lock file: ~/.claude/ralph.lock
- Added log file: ~/.claude/ralph-output.log
- Added trigger log: ~/.claude/ralph-trigger.log
- Added RALPH_MAX_ITERATIONS environment variable (default: 50)

Features:
- Background execution: Claude Code continues immediately
- Process tracking: PID saved for monitoring/stopping
- Lock mechanism: Prevents duplicate Ralph instances
- Real-time monitoring: tail -f ~/.claude/ralph-output.log
- Graceful cleanup: Auto-cleanup of dead process locks

Updated files:
- MASTER-PROMPT.md: Enhanced hook script + usage instructions
- interactive-install-claude.sh: Enhanced install_ralph() function
- ~/.claude/hooks/ralph-auto-trigger.sh: Updated local installation

Usage:
- Ralph auto-starts in background when agents are requested
- Monitor: tail -f ~/.claude/ralph-output.log
- Stop: kill $(cat ~/.claude/ralph.pid)
- Configure: export RALPH_AUTO_MODE=agents|always|off
- Configure: export RALPH_MAX_ITERATIONS=100

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
uroma
2026-01-16 10:03:31 +00:00
Unverified
parent eca57c93c6
commit 99cb591bf7
2 changed files with 353 additions and 104 deletions

View File

@@ -1151,15 +1151,63 @@ install_ralph() {
# Create hooks directory
mkdir -p "$CLAUDE_DIR/hooks"
# Create ralph-auto-trigger.sh script
log_info "Creating Ralph auto-trigger hook..."
# Create ralph-auto-trigger.sh script (Enhanced with Background Spawning)
log_info "Creating Ralph auto-trigger hook with background spawning..."
cat > "$CLAUDE_DIR/hooks/ralph-auto-trigger.sh" << 'RALPH_HOOK_EOF'
#!/bin/bash
# Ralph Auto-Trigger Hook
# Detects agent requests and manages Ralph state for autonomous looping
# Ralph Auto-Trigger Hook - Enhanced with Background Task Spawning
# Automatically starts Ralph CLI in background when needed
#
# Modes (via RALPH_AUTO_MODE environment variable):
# "always" - Start Ralph for every request
# "agents" - Only for agent requests (default)
# "off" - Disable auto-trigger
#
# Background Execution:
# - Ralph runs as background process (non-blocking)
# - Claude Code continues immediately
# - Ralph output logged to: ~/.claude/ralph-output.log
# - Ralph PID tracked in: ~/.claude/ralph.pid
STATE_FILE="$HOME/.claude/ralph-loop.local.md"
RALPH_MODE="${RALPH_AUTO_MODE:-agents}" # Options: always, agents, off
set -euo pipefail
# Configuration
CLAUDE_DIR="$HOME/.claude"
RALPH_STATE_FILE="$CLAUDE_DIR/ralph-loop.local.md"
RALPH_PID_FILE="$CLAUDE_DIR/ralph.pid"
RALPH_LOG_FILE="$CLAUDE_DIR/ralph-output.log"
RALPH_LOCK_FILE="$CLAUDE_DIR/ralph.lock"
# Read hook input from stdin
HOOK_INPUT=$(cat)
USER_PROMPT=$(echo "$HOOK_INPUT" | jq -r '.prompt // empty' 2>/dev/null || echo "")
# Fallback: if no JSON input, use first argument
if [[ -z "$USER_PROMPT" && $# -gt 0 ]]; then
USER_PROMPT="$1"
fi
# Get Ralph mode (default: agents)
RALPH_AUTO_MODE="${RALPH_AUTO_MODE:-agents}"
RALPH_MAX_ITERATIONS="${RALPH_MAX_ITERATIONS:-50}"
# Exit if auto-trigger is disabled
if [[ "$RALPH_AUTO_MODE" == "off" ]]; then
exit 0
fi
# Check if Ralph is already running (via lock file)
if [[ -f "$RALPH_LOCK_FILE" ]]; then
# Check if process is still alive
LOCK_PID=$(cat "$RALPH_LOCK_FILE" 2>/dev/null || echo "")
if [[ -n "$LOCK_PID" ]] && kill -0 "$LOCK_PID" 2>/dev/null; then
# Ralph is already running, don't start another instance
exit 0
else
# Lock file exists but process is dead, clean up
rm -f "$RALPH_LOCK_FILE" "$RALPH_PID_FILE"
fi
fi
# Agent detection list (lowercase for matching)
AGENTS=(
@@ -1176,16 +1224,9 @@ AGENTS=(
"api-tester" "performance-benchmarker" "test-results-analyzer"
"tool-evaluator" "workflow-optimizer"
"joker" "agent-updater"
"explore" "plan" "general-purpose"
)
# Check if mode is off
if [ "$RALPH_MODE" = "off" ]; then
exit 0
fi
# Read the user prompt
USER_PROMPT="$1"
# Detect agent request (case-insensitive)
agent_detected=false
detected_agent=""
@@ -1198,51 +1239,114 @@ for agent in "${AGENTS[@]}"; do
fi
done
# Check if we should trigger
# Determine if we should start Ralph
should_trigger=false
if [ "$RALPH_MODE" = "always" ]; then
# Trigger on all prompts
should_trigger=true
elif [ "$RALPH_MODE" = "agents" ]; then
# Only trigger on agent requests
if [ "$agent_detected" = true ]; then
case "$RALPH_AUTO_MODE" in
"always")
# Trigger on all prompts
should_trigger=true
fi
fi
;;
"agents")
# Only trigger on agent requests OR development keywords
if [[ "$agent_detected" == true ]]; then
should_trigger=true
elif echo "$USER_PROMPT" | grep -qiE "build|create|implement|develop|fix|add|refactor|optimize|write|generate|delegate|autonomous"; then
should_trigger=true
detected_agent="general-development"
fi
;;
esac
if [ "$should_trigger" = true ]; then
# Create/update state file
cat > "$STATE_FILE" << EOF
# Ralph Loop State
# Generated: $(date)
if [[ "$should_trigger" == true ]]; then
# Create Ralph state file
mkdir -p "$CLAUDE_DIR"
cat > "$RALPH_STATE_FILE" << EOF
# Ralph Loop State - Auto-Triggered
# Generated: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
**User Request:**
$USER_PROMPT
**Detected Agent:** $detected_agent
**Mode:** $RALPH_MODE
**Mode:** $RALPH_AUTO_MODE
**Max Iterations:** $RALPH_MAX_ITERATIONS
**Timestamp:** $(date -Iseconds)
## Context
This state file was automatically generated by the Ralph auto-trigger hook.
Ralph CLI can read this file to continue autonomous looping based on the user's request.
Ralph CLI will read this file and autonomously execute the request.
## Auto-Trigger Details
- Triggered by: Claude Code UserPromptSubmit hook
- Trigger mode: $RALPH_AUTO_MODE
- Background execution: Yes (non-blocking)
- Log file: $RALPH_LOG_FILE
## Usage
To run Ralph autonomously:
\`\`\`bash
ralph build 50 # Run 50 iterations
\`\`\`
Ralph is running autonomously in the background. Monitor progress:
bash
# View Ralph output in real-time
tail -f ~/.claude/ralph-output.log
# Check if Ralph is still running
ps aux | grep ralph
# Stop Ralph manually
kill $(cat ~/.claude/ralph.pid)
rm ~/.claude/ralph.lock
Ralph will read this state file and continue working until the task is complete.
EOF
# Log the trigger (silent, no output)
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Ralph auto-triggered: mode=$RALPH_MODE, agent=$detected_agent" >> "$HOME/.claude/ralph-trigger.log" 2>/dev/null || true
# Spawn Ralph in background (NON-BLOCKING)
if command -v ralph &> /dev/null; then
# Create log file
touch "$RALPH_LOG_FILE"
# Start Ralph in background with nohup (survives terminal close)
echo "[$(date -u +"%Y-%m-%d %H:%M:%S UTC")] Starting Ralph in background..." >> "$RALPH_LOG_FILE"
echo "Mode: $RALPH_AUTO_MODE" >> "$RALPH_LOG_FILE"
echo "Agent: $detected_agent" >> "$RALPH_LOG_FILE"
echo "Max iterations: $RALPH_MAX_ITERATIONS" >> "$RALPH_LOG_FILE"
echo "---" >> "$RALPH_LOG_FILE"
# Start Ralph in background
nohup ralph build "$RALPH_MAX_ITERATIONS" >> "$RALPH_LOG_FILE" 2>&1 &
RALPH_PID=$!
# Save PID for tracking
echo "$RALPH_PID" > "$RALPH_PID_FILE"
echo "$RALPH_PID" > "$RALPH_LOCK_FILE"
# Log the trigger
{
echo "[$(date -u +"%Y-%m-%d %H:%M:%S UTC")] Ralph auto-triggered"
echo " Mode: $RALPH_AUTO_MODE"
echo " Agent: $detected_agent"
echo " PID: $RALPH_PID"
echo " Log: $RALPH_LOG_FILE"
} >> "$CLAUDE_DIR/ralph-trigger.log" 2>/dev/null || true
# Notify user via stderr (visible in Claude Code)
echo "🔄 Ralph CLI auto-started in background" >&2
echo " PID: $RALPH_PID" >&2
echo " Agent: $detected_agent" >&2
echo " Monitor: tail -f ~/.claude/ralph-output.log" >&2
echo " Stop: kill \$(cat ~/.claude/ralph.pid)" >&2
else
# Ralph not installed, just create state file
echo "⚠️ Ralph CLI not installed. State file created for manual use." >&2
echo " Install: npm install -g @iannuttall/ralph" >&2
fi
fi
# Exit immediately (NON-BLOCKING - Claude Code continues)
exit 0
RALPH_HOOK_EOF