- Add all 21 commands (clawd, ralph, prometheus*, dexto*) - Add all hooks (intelligent-router, clawd-*, prometheus-wrapper, unified-integration-v2) - Add skills (ralph, prometheus master) - Add MCP servers (registry.json, manager.sh) - Add plugins directory with marketplaces - Add health-check.sh and aliases.sh scripts - Complete repository synchronization with local ~/.claude/ Total changes: 100+ new files added All integrations now fully backed up in repository 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
394 lines
12 KiB
Bash
Executable File
394 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
|
# Claude Code Unified Integration Hook
|
|
# Auto-triggers Ralph Orchestrator, ARC Protocol, and manages claude-mem
|
|
# ALWAYS-ON MODE - Ralph runs continuously and orchestrates all tasks
|
|
#
|
|
# Architecture:
|
|
# Claude Code (User) -> Hook -> Ralph Orchestrator (ALWAYS-ON)
|
|
# |
|
|
# +-> ARC Protocol Workers (parallel execution)
|
|
# +-> claude-mem (persistent memory)
|
|
# +-> Multiple AI Backends (Claude, Gemini, etc.)
|
|
#
|
|
# Environment Variables:
|
|
# RALPH_MODE - "always" (default), "agents", "off"
|
|
# RALPH_BACKEND - "claude" (default), "kiro", "gemini", "opencode"
|
|
# RALPH_PRESET - "claude-code" (default), "feature", "tdd-red-green", etc.
|
|
# ARC_ENABLED - "true" (default) to enable ARC Protocol workers
|
|
# CLAUDE_MEM_ENABLED - "true" (default) to enable claude-mem memory
|
|
|
|
set -euo pipefail
|
|
|
|
# ============================================================================
|
|
# CONFIGURATION
|
|
# ============================================================================
|
|
|
|
CLAUDE_DIR="${HOME}/.claude"
|
|
RALPH_DIR="${CLAUDE_DIR}/ralph-integration"
|
|
ARC_DIR="${RALPH_DIR}/arc"
|
|
LOG_DIR="${RALPH_DIR}/logs"
|
|
|
|
# Ralph State Files
|
|
RALPH_LOCK_FILE="${RALPH_DIR}/ralph.lock"
|
|
RALPH_PID_FILE="${RALPH_DIR}/ralph.pid"
|
|
RALPH_LOG_FILE="${LOG_DIR}/ralph.log"
|
|
RALPH_CONFIG="${RALPH_DIR}/ralph.yml"
|
|
|
|
# ARC State Files
|
|
ARC_LOCK_FILE="${RALPH_DIR}/arc.lock"
|
|
ARC_PID_FILE="${RALPH_DIR}/arc.pid"
|
|
ARC_LOG_FILE="${LOG_DIR}/arc.log"
|
|
ARC_CONFIG="${ARC_DIR}/.arc/STATE.md"
|
|
|
|
# Integration Log
|
|
INTEGRATION_LOG="${LOG_DIR}/integration.log"
|
|
|
|
# Default Settings (override via environment variables)
|
|
RALPH_MODE="${RALPH_MODE:-always}"
|
|
RALPH_BACKEND="${RALPH_BACKEND:-claude}"
|
|
RALPH_PRESET="${RALPH_PRESET:-claude-code}"
|
|
ARC_ENABLED="${ARC_ENABLED:-true}"
|
|
CLAUDE_MEM_ENABLED="${CLAUDE_MEM_ENABLED:-true}"
|
|
|
|
# Maximum Ralph iterations
|
|
RALPH_MAX_ITERATIONS="${RALPH_MAX_ITERATIONS:-100}"
|
|
|
|
# Create directories
|
|
mkdir -p "${RALPH_DIR}" "${LOG_DIR}" "${ARC_DIR}"
|
|
|
|
# Logging function
|
|
log() {
|
|
local level="$1"
|
|
shift
|
|
echo "[$(date -u +"%Y-%m-%d %H:%M:%S UTC")] [${level}] $*" | tee -a "${INTEGRATION_LOG}"
|
|
}
|
|
|
|
# ============================================================================
|
|
# INPUT PROCESSING
|
|
# ============================================================================
|
|
|
|
# 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
|
|
|
|
log INFO "Unified integration triggered"
|
|
log INFO "Mode: ${RALPH_MODE}"
|
|
log INFO "Prompt: ${USER_PROMPT:0:100}..."
|
|
|
|
# ============================================================================
|
|
# RALPH ORCHESTRATOR INTEGRATION
|
|
# ============================================================================
|
|
|
|
start_ralph() {
|
|
local prompt="$1"
|
|
|
|
# Check if Ralph is already running
|
|
if [[ -f "$RALPH_LOCK_FILE" ]]; then
|
|
local lock_pid
|
|
lock_pid=$(cat "$RALPH_LOCK_FILE" 2>/dev/null || echo "")
|
|
if [[ -n "$lock_pid" ]] && kill -0 "$lock_pid" 2>/dev/null; then
|
|
log INFO "Ralph already running (PID: ${lock_pid})"
|
|
return 0
|
|
else
|
|
log WARN "Ralph lock file exists but process dead, cleaning up"
|
|
rm -f "$RALPH_LOCK_FILE" "$RALPH_PID_FILE"
|
|
fi
|
|
fi
|
|
|
|
# Create Ralph configuration
|
|
create_ralph_config
|
|
|
|
# Start Ralph in background
|
|
log INFO "Starting Ralph Orchestrator..."
|
|
nohup ralph run \
|
|
-c "$RALPH_CONFIG" \
|
|
-p "$prompt" \
|
|
--max-iterations "$RALPH_MAX_ITERATIONS" \
|
|
--no-tui \
|
|
>> "$RALPH_LOG_FILE" 2>&1 &
|
|
|
|
local ralph_pid=$!
|
|
echo "$ralph_pid" > "$RALPH_PID_FILE"
|
|
echo "$ralph_pid" > "$RALPH_LOCK_FILE"
|
|
|
|
log INFO "Ralph started (PID: ${ralph_pid})"
|
|
log INFO "Config: ${RALPH_CONFIG}"
|
|
log INFO "Log: ${RALPH_LOG_FILE}"
|
|
|
|
# Notify user
|
|
echo "🤖 Ralph Orchestrator: ACTIVE" >&2
|
|
echo " PID: ${ralph_pid}" >&2
|
|
echo " Mode: ${RALPH_MODE}" >&2
|
|
echo " Monitor: tail -f ${RALPH_LOG_FILE}" >&2
|
|
}
|
|
|
|
create_ralph_config() {
|
|
# Determine preset to use
|
|
local preset_config
|
|
preset_config=$(get_ralph_preset "$RALPH_PRESET")
|
|
|
|
cat > "$RALPH_CONFIG" << EOF
|
|
# Ralph Orchestrator Configuration for Claude Code
|
|
# Auto-generated: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
|
|
# Mode: ${RALPH_MODE}
|
|
# Backend: ${RALPH_BACKEND}
|
|
|
|
${preset_config}
|
|
|
|
# Claude Code Integration Settings
|
|
cli:
|
|
backend: "${RALPH_BACKEND}"
|
|
prompt_mode: "arg"
|
|
|
|
# Integration with claude-mem
|
|
memories:
|
|
enabled: ${CLAUDE_MEM_ENABLED}
|
|
inject: auto
|
|
|
|
# Integration with ARC Protocol
|
|
arc_integration:
|
|
enabled: ${ARC_ENABLED}
|
|
bridge_path: "${ARC_DIR}/.agent/mcp/arc_mcp_server.py"
|
|
dashboard_enabled: true
|
|
|
|
# Core Behaviors
|
|
core:
|
|
scratchpad: "${RALPH_DIR}/scratchpad.md"
|
|
specs_dir: "./specs/"
|
|
guardrails:
|
|
- "Fresh context each iteration - scratchpad and memories are state"
|
|
- "Don't assume 'not implemented' - search first"
|
|
- "Backpressure is law - tests/typecheck/lint must pass"
|
|
- "Use ARC workers for parallel execution when possible"
|
|
- "Leverage claude-mem for context from previous sessions"
|
|
EOF
|
|
|
|
log INFO "Ralph config created: ${RALPH_CONFIG}"
|
|
}
|
|
|
|
get_ralph_preset() {
|
|
local preset="$1"
|
|
|
|
case "$preset" in
|
|
"claude-code")
|
|
# Optimized preset for Claude Code integration
|
|
cat << 'PRESET_EOF'
|
|
# Claude Code Preset - Planner-Builder-Verifier Workflow
|
|
event_loop:
|
|
completion_promise: "TASK_COMPLETE"
|
|
max_iterations: 100
|
|
starting_event: "task.start"
|
|
|
|
hats:
|
|
planner:
|
|
name: "📋 Planner"
|
|
description: "Break down tasks into actionable steps, identify dependencies"
|
|
triggers: ["task.start", "plan.failed"]
|
|
publishes: ["plan.ready", "task.complete"]
|
|
instructions: |
|
|
You are the Planner. Analyze the user's request and:
|
|
1. Break down the task into clear, actionable steps
|
|
2. Identify dependencies and parallelizable work
|
|
3. Consider using ARC workers for parallel execution
|
|
4. Search claude-mem for relevant context from past sessions
|
|
5. Create a detailed plan before proceeding
|
|
|
|
builder:
|
|
name: "🔨 Builder"
|
|
description: "Implement code following the plan and best practices"
|
|
triggers: ["plan.ready", "build.failed"]
|
|
publishes: ["build.done", "build.blocked"]
|
|
instructions: |
|
|
You are the Builder. Implement the plan:
|
|
1. Follow the plan created by the Planner
|
|
2. Write clean, well-documented code
|
|
3. Use ARC workers for parallel tasks when beneficial
|
|
4. Run tests, linting, and type checking
|
|
5. Only publish build.done when all quality gates pass
|
|
|
|
verifier:
|
|
name: "✅ Verifier"
|
|
description: "Verify implementation meets requirements and quality standards"
|
|
triggers: ["build.done"]
|
|
publishes: ["verification.passed", "verification.failed", "task.complete"]
|
|
instructions: |
|
|
You are the Verifier. Ensure quality:
|
|
1. Review the implementation against the plan
|
|
2. Verify all tests pass
|
|
3. Check for edge cases and error handling
|
|
4. Ensure code follows best practices
|
|
5. Store lessons learned in memories for future sessions
|
|
PRESET_EOF
|
|
;;
|
|
"autonomous")
|
|
# Fully autonomous mode
|
|
cat << 'PRESET_EOF'
|
|
# Autonomous Mode - Single Hat with Full Autonomy
|
|
event_loop:
|
|
completion_promise: "TASK_COMPLETE"
|
|
max_iterations: 150
|
|
|
|
core:
|
|
guardrails:
|
|
- "You are fully autonomous - plan, execute, and verify independently"
|
|
- "Use ARC workers for all parallelizable tasks"
|
|
- "Leverage memories extensively for context"
|
|
- "Iterate until the task is completely done"
|
|
PRESET_EOF
|
|
;;
|
|
*)
|
|
# Default/feature preset
|
|
cat << 'PRESET_EOF'
|
|
# Default Feature Development Preset
|
|
event_loop:
|
|
completion_promise: "TASK_COMPLETE"
|
|
max_iterations: 100
|
|
PRESET_EOF
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# ============================================================================
|
|
# ARC PROTOCOL INTEGRATION
|
|
# ============================================================================
|
|
|
|
start_arc() {
|
|
if [[ "$ARC_ENABLED" != "true" ]]; then
|
|
log INFO "ARC Protocol disabled"
|
|
return 0
|
|
fi
|
|
|
|
# Check if ARC is already running
|
|
if [[ -f "$ARC_LOCK_FILE" ]]; then
|
|
local lock_pid
|
|
lock_pid=$(cat "$ARC_LOCK_FILE" 2>/dev/null || echo "")
|
|
if [[ -n "$lock_pid" ]] && kill -0 "$lock_pid" 2>/dev/null; then
|
|
log INFO "ARC already running (PID: ${lock_pid})"
|
|
return 0
|
|
else
|
|
log WARN "ARC lock file exists but process dead, cleaning up"
|
|
rm -f "$ARC_LOCK_FILE" "$ARC_PID_FILE"
|
|
fi
|
|
fi
|
|
|
|
# Setup ARC directory
|
|
setup_arc_directory
|
|
|
|
# Start ARC dashboard
|
|
log INFO "Starting ARC Protocol..."
|
|
cd "$ARC_DIR"
|
|
|
|
# Start the ARC dashboard in background
|
|
nohup python3 ./dash >> "$ARC_LOG_FILE" 2>&1 &
|
|
local arc_pid=$!
|
|
echo "$arc_pid" > "$ARC_PID_FILE"
|
|
echo "$arc_pid" > "$ARC_LOCK_FILE"
|
|
|
|
log INFO "ARC started (PID: ${arc_pid})"
|
|
log INFO "Dashboard: http://localhost:37373"
|
|
|
|
echo "🚀 ARC Protocol: ACTIVE" >&2
|
|
echo " PID: ${arc_pid}" >&2
|
|
echo " Dashboard: http://localhost:37373" >&2
|
|
}
|
|
|
|
setup_arc_directory() {
|
|
# Create .arc structure if it doesn't exist
|
|
mkdir -p "${ARC_DIR}/.arc/"{planning,archive,templates}
|
|
|
|
# Initialize ARC state
|
|
cat > "$ARC_CONFIG" << EOF
|
|
# ARC Protocol State
|
|
# Initialized: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
|
|
|
|
**Status:** Active
|
|
**Mode:** Integrated with Ralph Orchestrator
|
|
**Workspace:** ${ARC_DIR}
|
|
|
|
## Integration
|
|
|
|
This ARC instance is managed by Ralph Orchestrator.
|
|
All worker dispatch and coordination happens through Ralph.
|
|
|
|
## Available Commands
|
|
|
|
- Check status: cat ${ARC_CONFIG}
|
|
- View logs: tail -f ${ARC_LOG_FILE}
|
|
- Stop integration: kill \$(cat ${ARC_LOCK_FILE})
|
|
EOF
|
|
|
|
log INFO "ARC directory initialized: ${ARC_DIR}"
|
|
}
|
|
|
|
# ============================================================================
|
|
# CLAUDE-MEM INTEGRATION
|
|
# ============================================================================
|
|
|
|
check_claude_mem() {
|
|
if [[ "$CLAUDE_MEM_ENABLED" != "true" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
# Check if claude-mem plugin is installed
|
|
local mem_plugin="${CLAUDE_DIR}/plugins/cache/thedotmack/claude-mem"
|
|
|
|
if [[ -d "$mem_plugin" ]]; then
|
|
log INFO "claude-mem plugin found"
|
|
return 0
|
|
else
|
|
log WARN "claude-mem not installed"
|
|
echo "📦 claude-mem: NOT INSTALLED" >&2
|
|
echo " Install: /plugin marketplace add thedotmack/claude-mem" >&2
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# ============================================================================
|
|
# MAIN EXECUTION
|
|
# ============================================================================
|
|
|
|
main() {
|
|
# Exit if disabled
|
|
if [[ "$RALPH_MODE" == "off" ]]; then
|
|
log INFO "Integration disabled (RALPH_MODE=off)"
|
|
exit 0
|
|
fi
|
|
|
|
# Determine if we should trigger
|
|
local should_trigger=false
|
|
|
|
case "$RALPH_MODE" in
|
|
"always")
|
|
should_trigger=true
|
|
;;
|
|
"agents")
|
|
# Detect agent or development keywords
|
|
if echo "$USER_PROMPT" | grep -qiE "build|create|implement|develop|fix|add|refactor|optimize|write|generate|delegate|autonomous|agent|task|feature|pr"; then
|
|
should_trigger=true
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
if [[ "$should_trigger" == true ]]; then
|
|
# Start components
|
|
check_claude_mem
|
|
start_arc
|
|
start_ralph "$USER_PROMPT"
|
|
|
|
log INFO "Integration complete"
|
|
else
|
|
log INFO "Skipped (no trigger keywords)"
|
|
fi
|
|
|
|
# Always exit immediately (non-blocking)
|
|
exit 0
|
|
}
|
|
|
|
# Run main function
|
|
main "$@"
|