Fix create_files.sh syntax errors and complete Ralph implementation

- Fix nested EOF heredoc conflicts in update_status() and show_help() functions
- Use unique delimiters (STATUSEOF, HELPEOF) to avoid conflicts
- Complete Ralph for Claude Code implementation with all components:
  - ralph_loop.sh: Main autonomous development loop with rate limiting
  - ralph_monitor.sh: Live monitoring dashboard
  - setup.sh: Project initialization script
  - templates/: Template files for new projects
  - .gitignore: Comprehensive ignore rules

All scripts are now executable and syntax-validated.
This commit is contained in:
frankbria 2025-08-27 09:15:00 -07:00
parent 5e1d8734b1
commit 48bd008701
8 changed files with 571 additions and 5 deletions

36
.gitignore vendored Normal file
View file

@ -0,0 +1,36 @@
# Ralph generated files
.call_count
.last_reset
.exit_signals
status.json
# Logs
logs/
*.log
# Generated documentation
docs/generated/
# OS files
.DS_Store
Thumbs.db
# Temporary files
*.tmp
.temp/
# Node modules (if using Node.js projects)
node_modules/
# Python cache (if using Python projects)
__pycache__/
*.pyc
# Rust build (if using Rust projects)
target/
# IDE files
.vscode/
.idea/
*.swp
*.swo

View file

@ -94,7 +94,7 @@ update_status() {
local status=$4
local exit_reason=${5:-""}
cat > "$STATUS_FILE" << EOF
cat > "$STATUS_FILE" << STATUSEOF
{
"timestamp": "$(date -Iseconds)",
"loop_count": $loop_count,
@ -105,7 +105,7 @@ update_status() {
"exit_reason": "$exit_reason",
"next_reset": "$(date -d '+1 hour' -Iseconds | cut -d'T' -f2 | cut -d'+' -f1)"
}
EOF
STATUSEOF
}
# Check if we can make another call
@ -312,7 +312,7 @@ main() {
# Help function
show_help() {
cat << EOF
cat << HELPEOF
Ralph Loop for Claude Code
Usage: $0 [OPTIONS]
@ -331,7 +331,7 @@ Files created:
Example:
$0 --calls 50 --prompt my_prompt.md
EOF
HELPEOF
}
# Parse command line arguments

265
ralph_loop.sh Normal file → Executable file
View file

@ -82,7 +82,7 @@ update_status() {
local status=$4
local exit_reason=${5:-""}
cat > "$STATUS_FILE" << EOF
cat > "$STATUS_FILE" << STATUSEOF
{
"timestamp": "$(date -Iseconds)",
"loop_count": $loop_count,
@ -93,3 +93,266 @@ update_status() {
"exit_reason": "$exit_reason",
"next_reset": "$(date -d '+1 hour' -Iseconds | cut -d'T' -f2 | cut -d'+' -f1)"
}
STATUSEOF
}
# Check if we can make another call
can_make_call() {
local calls_made=0
if [[ -f "$CALL_COUNT_FILE" ]]; then
calls_made=$(cat "$CALL_COUNT_FILE")
fi
if [[ $calls_made -ge $MAX_CALLS_PER_HOUR ]]; then
return 1 # Cannot make call
else
return 0 # Can make call
fi
}
# Increment call counter
increment_call_counter() {
local calls_made=0
if [[ -f "$CALL_COUNT_FILE" ]]; then
calls_made=$(cat "$CALL_COUNT_FILE")
fi
((calls_made++))
echo "$calls_made" > "$CALL_COUNT_FILE"
echo "$calls_made"
}
# Wait for rate limit reset with countdown
wait_for_reset() {
local calls_made=$(cat "$CALL_COUNT_FILE" 2>/dev/null || echo "0")
log_status "WARN" "Rate limit reached ($calls_made/$MAX_CALLS_PER_HOUR). Waiting for reset..."
# Calculate time until next hour
local current_minute=$(date +%M)
local current_second=$(date +%S)
local wait_time=$(((60 - current_minute - 1) * 60 + (60 - current_second)))
log_status "INFO" "Sleeping for $wait_time seconds until next hour..."
# Countdown display
while [[ $wait_time -gt 0 ]]; do
local hours=$((wait_time / 3600))
local minutes=$(((wait_time % 3600) / 60))
local seconds=$((wait_time % 60))
printf "\r${YELLOW}Time until reset: %02d:%02d:%02d${NC}" $hours $minutes $seconds
sleep 1
((wait_time--))
done
printf "\n"
# Reset counter
echo "0" > "$CALL_COUNT_FILE"
echo "$(date +%Y%m%d%H)" > "$TIMESTAMP_FILE"
log_status "SUCCESS" "Rate limit reset! Ready for new calls."
}
# Check if we should gracefully exit
should_exit_gracefully() {
if [[ ! -f "$EXIT_SIGNALS_FILE" ]]; then
return 1 # Don't exit, file doesn't exist
fi
local signals=$(cat "$EXIT_SIGNALS_FILE")
# Count recent signals (last 5 loops)
local recent_test_loops=$(echo "$signals" | jq '.test_only_loops | length')
local recent_done_signals=$(echo "$signals" | jq '.done_signals | length')
local recent_completion_indicators=$(echo "$signals" | jq '.completion_indicators | length')
# Check for exit conditions
# 1. Too many consecutive test-only loops
if [[ $recent_test_loops -ge $MAX_CONSECUTIVE_TEST_LOOPS ]]; then
log_status "WARN" "Exit condition: Too many test-focused loops ($recent_test_loops >= $MAX_CONSECUTIVE_TEST_LOOPS)"
echo "test_saturation"
return 0
fi
# 2. Multiple "done" signals
if [[ $recent_done_signals -ge $MAX_CONSECUTIVE_DONE_SIGNALS ]]; then
log_status "WARN" "Exit condition: Multiple completion signals ($recent_done_signals >= $MAX_CONSECUTIVE_DONE_SIGNALS)"
echo "completion_signals"
return 0
fi
# 3. Strong completion indicators
if [[ $recent_completion_indicators -ge 2 ]]; then
log_status "WARN" "Exit condition: Strong completion indicators ($recent_completion_indicators)"
echo "project_complete"
return 0
fi
# 4. Check fix_plan.md for completion
if [[ -f "@fix_plan.md" ]]; then
local total_items=$(grep -c "^- \[" "@fix_plan.md" 2>/dev/null || echo "0")
local completed_items=$(grep -c "^- \[x\]" "@fix_plan.md" 2>/dev/null || echo "0")
if [[ $total_items -gt 0 ]] && [[ $completed_items -eq $total_items ]]; then
log_status "WARN" "Exit condition: All fix_plan.md items completed ($completed_items/$total_items)"
echo "plan_complete"
return 0
fi
fi
return 1 # Don't exit
}
# Main execution function
execute_claude_code() {
local calls_made=$(increment_call_counter)
local timestamp=$(date '+%Y-%m-%d_%H-%M-%S')
local output_file="$LOG_DIR/claude_output_${timestamp}.log"
local loop_count=$1
log_status "LOOP" "Executing Claude Code (Call $calls_made/$MAX_CALLS_PER_HOUR)"
# Execute Claude Code with the prompt
if $CLAUDE_CODE_CMD < "$PROMPT_FILE" > "$output_file" 2>&1; then
log_status "SUCCESS" "Claude Code execution completed successfully"
# Extract key information from output if possible
if grep -q "error\|Error\|ERROR" "$output_file"; then
log_status "WARN" "Errors detected in output, check: $output_file"
fi
return 0
else
log_status "ERROR" "Claude Code execution failed, check: $output_file"
return 1
fi
}
# Cleanup function
cleanup() {
log_status "INFO" "Ralph loop interrupted. Cleaning up..."
update_status "$loop_count" "$(cat "$CALL_COUNT_FILE" 2>/dev/null || echo "0")" "interrupted" "stopped"
exit 0
}
# Set up signal handlers
trap cleanup SIGINT SIGTERM
# Main loop
main() {
local loop_count=0
log_status "SUCCESS" "🚀 Ralph loop starting with Claude Code"
log_status "INFO" "Max calls per hour: $MAX_CALLS_PER_HOUR"
log_status "INFO" "Logs: $LOG_DIR/ | Docs: $DOCS_DIR/ | Status: $STATUS_FILE"
# Check if prompt file exists
if [[ ! -f "$PROMPT_FILE" ]]; then
log_status "ERROR" "Prompt file '$PROMPT_FILE' not found!"
exit 1
fi
while true; do
((loop_count++))
init_call_tracking
log_status "LOOP" "=== Starting Loop #$loop_count ==="
# Check rate limits
if ! can_make_call; then
wait_for_reset
continue
fi
# Check for graceful exit conditions
local exit_reason=$(should_exit_gracefully)
if [[ $? -eq 0 ]]; then
log_status "SUCCESS" "🏁 Graceful exit triggered: $exit_reason"
update_status "$loop_count" "$(cat "$CALL_COUNT_FILE")" "graceful_exit" "completed" "$exit_reason"
log_status "SUCCESS" "🎉 Ralph has completed the project! Final stats:"
log_status "INFO" " - Total loops: $loop_count"
log_status "INFO" " - API calls used: $(cat "$CALL_COUNT_FILE")"
log_status "INFO" " - Exit reason: $exit_reason"
break
fi
# Update status
local calls_made=$(cat "$CALL_COUNT_FILE" 2>/dev/null || echo "0")
update_status "$loop_count" "$calls_made" "executing" "running"
# Execute Claude Code
if execute_claude_code "$loop_count"; then
update_status "$loop_count" "$(cat "$CALL_COUNT_FILE")" "completed" "success"
# Brief pause between successful executions
sleep 5
else
update_status "$loop_count" "$(cat "$CALL_COUNT_FILE")" "failed" "error"
log_status "WARN" "Execution failed, waiting 30 seconds before retry..."
sleep 30
fi
log_status "LOOP" "=== Completed Loop #$loop_count ==="
done
}
# Help function
show_help() {
cat << HELPEOF
Ralph Loop for Claude Code
Usage: $0 [OPTIONS]
Options:
-h, --help Show this help message
-c, --calls NUM Set max calls per hour (default: $MAX_CALLS_PER_HOUR)
-p, --prompt FILE Set prompt file (default: $PROMPT_FILE)
-s, --status Show current status and exit
Files created:
- $LOG_DIR/: All execution logs
- $DOCS_DIR/: Generated documentation
- $STATUS_FILE: Current status (JSON)
Example:
$0 --calls 50 --prompt my_prompt.md
HELPEOF
}
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
exit 0
;;
-c|--calls)
MAX_CALLS_PER_HOUR="$2"
shift 2
;;
-p|--prompt)
PROMPT_FILE="$2"
shift 2
;;
-s|--status)
if [[ -f "$STATUS_FILE" ]]; then
echo "Current Status:"
cat "$STATUS_FILE" | jq . 2>/dev/null || cat "$STATUS_FILE"
else
echo "No status file found. Ralph may not be running."
fi
exit 0
;;
*)
echo "Unknown option: $1"
show_help
exit 1
;;
esac
done
# Start the main loop
main

103
ralph_monitor.sh Executable file
View file

@ -0,0 +1,103 @@
#!/bin/bash
# Ralph Status Monitor - Live terminal dashboard for the Ralph loop
set -e
STATUS_FILE="status.json"
LOG_FILE="logs/ralph.log"
REFRESH_INTERVAL=2
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
WHITE='\033[1;37m'
NC='\033[0m'
# Clear screen and hide cursor
clear_screen() {
clear
printf '\033[?25l' # Hide cursor
}
# Show cursor on exit
show_cursor() {
printf '\033[?25h' # Show cursor
}
# Cleanup function
cleanup() {
show_cursor
echo
echo "Monitor stopped."
exit 0
}
# Set up signal handlers
trap cleanup SIGINT SIGTERM EXIT
# Main display function
display_status() {
clear_screen
# Header
echo -e "${WHITE}╔════════════════════════════════════════════════════════════════════════╗${NC}"
echo -e "${WHITE}║ 🤖 RALPH MONITOR ║${NC}"
echo -e "${WHITE}║ Live Status Dashboard ║${NC}"
echo -e "${WHITE}╚════════════════════════════════════════════════════════════════════════╝${NC}"
echo
# Status section
if [[ -f "$STATUS_FILE" ]]; then
# Parse JSON status
local status_data=$(cat "$STATUS_FILE")
local loop_count=$(echo "$status_data" | jq -r '.loop_count // "0"' 2>/dev/null || echo "0")
local calls_made=$(echo "$status_data" | jq -r '.calls_made_this_hour // "0"' 2>/dev/null || echo "0")
local max_calls=$(echo "$status_data" | jq -r '.max_calls_per_hour // "100"' 2>/dev/null || echo "100")
local status=$(echo "$status_data" | jq -r '.status // "unknown"' 2>/dev/null || echo "unknown")
echo -e "${CYAN}┌─ Current Status ────────────────────────────────────────────────────────┐${NC}"
echo -e "${CYAN}${NC} Loop Count: ${WHITE}#$loop_count${NC}"
echo -e "${CYAN}${NC} Status: ${GREEN}$status${NC}"
echo -e "${CYAN}${NC} API Calls: $calls_made/$max_calls"
echo -e "${CYAN}└─────────────────────────────────────────────────────────────────────────┘${NC}"
echo
else
echo -e "${RED}┌─ Status ────────────────────────────────────────────────────────────────┐${NC}"
echo -e "${RED}${NC} Status file not found. Ralph may not be running."
echo -e "${RED}└─────────────────────────────────────────────────────────────────────────┘${NC}"
echo
fi
# Recent logs
echo -e "${BLUE}┌─ Recent Activity ───────────────────────────────────────────────────────┐${NC}"
if [[ -f "$LOG_FILE" ]]; then
tail -n 8 "$LOG_FILE" | while IFS= read -r line; do
echo -e "${BLUE}${NC} $line"
done
else
echo -e "${BLUE}${NC} No log file found"
fi
echo -e "${BLUE}└─────────────────────────────────────────────────────────────────────────┘${NC}"
# Footer
echo
echo -e "${YELLOW}Controls: Ctrl+C to exit | Refreshes every ${REFRESH_INTERVAL}s | $(date '+%H:%M:%S')${NC}"
}
# Main monitor loop
main() {
echo "Starting Ralph Monitor..."
sleep 2
while true; do
display_status
sleep "$REFRESH_INTERVAL"
done
}
main

34
setup.sh Executable file
View file

@ -0,0 +1,34 @@
#!/bin/bash
# Ralph Project Setup Script
set -e
PROJECT_NAME=${1:-"my-project"}
echo "🚀 Setting up Ralph project: $PROJECT_NAME"
# Create project directory
mkdir -p "$PROJECT_NAME"
cd "$PROJECT_NAME"
# Create structure
mkdir -p {specs/stdlib,src,examples,logs,docs/generated}
# Copy templates
cp ../templates/PROMPT.md .
cp ../templates/fix_plan.md @fix_plan.md
cp ../templates/AGENT.md @AGENT.md
cp -r ../templates/specs/* specs/ 2>/dev/null || true
# Initialize git
git init
echo "# $PROJECT_NAME" > README.md
git add .
git commit -m "Initial Ralph project setup"
echo "✅ Project $PROJECT_NAME created!"
echo "Next steps:"
echo " 1. Edit PROMPT.md with your project requirements"
echo " 2. Update specs/ with your project specifications"
echo " 3. Run: ../ralph_loop.sh"
echo " 4. Monitor: ../ralph_monitor.sh"

46
templates/AGENT.md Normal file
View file

@ -0,0 +1,46 @@
# Agent Build Instructions
## Project Setup
```bash
# Install dependencies (example for Node.js project)
npm install
# Or for Python project
pip install -r requirements.txt
# Or for Rust project
cargo build
```
## Running Tests
```bash
# Node.js
npm test
# Python
pytest
# Rust
cargo test
```
## Build Commands
```bash
# Production build
npm run build
# or
cargo build --release
```
## Development Server
```bash
# Start development server
npm run dev
# or
cargo run
```
## Key Learnings
- Update this section when you learn new build optimizations
- Document any gotchas or special setup requirements
- Keep track of the fastest test/build cycle

57
templates/PROMPT.md Normal file
View file

@ -0,0 +1,57 @@
# Ralph Development Instructions
## Context
You are Ralph, an autonomous AI development agent working on a [YOUR PROJECT NAME] project.
## Current Objectives
1. Study specs/* to learn about the project specifications
2. Review @fix_plan.md for current priorities
3. Implement the highest priority item using best practices
4. Use parallel subagents for complex tasks (max 100 concurrent)
5. Run tests after each implementation
6. Update documentation and fix_plan.md
## Key Principles
- ONE task per loop - focus on the most important thing
- Search the codebase before assuming something isn't implemented
- Use subagents for expensive operations (file searching, analysis)
- Write comprehensive tests with clear documentation
- Update @fix_plan.md with your learnings
- Commit working changes with descriptive messages
## 🧪 Testing Guidelines (CRITICAL)
- LIMIT testing to ~20% of your total effort per loop
- PRIORITIZE: Implementation > Documentation > Tests
- Only write tests for NEW functionality you implement
- Do NOT refactor existing tests unless broken
- Do NOT add "additional test coverage" as busy work
- Focus on CORE functionality first, comprehensive testing later
## Execution Guidelines
- Before making changes: search codebase using subagents
- After implementation: run ESSENTIAL tests for the modified code only
- If tests fail: fix them as part of your current work
- Keep @AGENT.md updated with build/run instructions
- Document the WHY behind tests and implementations
- No placeholder implementations - build it properly
## Completion Awareness
If you believe the project is complete or nearly complete:
- Update @fix_plan.md to reflect completion status
- Summarize what has been accomplished
- Note any remaining minor tasks
- Do NOT continue with busy work like extensive testing
- Do NOT implement features not in the specifications
## File Structure
- specs/: Project specifications and requirements
- src/: Source code implementation
- examples/: Example usage and test cases
- @fix_plan.md: Prioritized TODO list
- @AGENT.md: Project build and run instructions
## Current Task
Follow @fix_plan.md and choose the most important item to implement next.
Use your judgment to prioritize what will have the biggest impact on project progress.
Remember: Quality over speed. Build it right the first time. Know when you're done.

27
templates/fix_plan.md Normal file
View file

@ -0,0 +1,27 @@
# Ralph Fix Plan
## High Priority
- [ ] Set up basic project structure and build system
- [ ] Define core data structures and types
- [ ] Implement basic input/output handling
- [ ] Create test framework and initial tests
## Medium Priority
- [ ] Add error handling and validation
- [ ] Implement core business logic
- [ ] Add configuration management
- [ ] Create user documentation
## Low Priority
- [ ] Performance optimization
- [ ] Extended feature set
- [ ] Integration with external services
- [ ] Advanced error recovery
## Completed
- [x] Project initialization
## Notes
- Focus on MVP functionality first
- Ensure each feature is properly tested
- Update this file after each major milestone