Ralph for Claude Code

repository·main·Indexed 27 days ago

https://github.com/frankbria/ralph-claude-code

An autonomous AI development loop for Claude Code that enables continuous, iterative project improvement. It features built-in safeguards including rate limiting, circuit breakers, and intelligent exit detection to prevent infinite loops and API overuse. Ralph provides tools for importing requirements from PRDs and GitHub Issues, managing task queues via ralph-queue, and running executions in isolated Docker or E2B sandboxes.

Tokens
29.3K
Snippets
78
Records
143
Agent score
94%

What's inside ralph-claude-code

  1. Understand Ralph test organization

    main

    Tests are organized into three main categories based on scope and execution speed:

    • Unit (tests/unit/): Fast, isolated function tests using mocks. Typically <1s per file.
    • Integration (tests/integration/): Medium speed (1-5s per file). Tests component interactions using real filesystem and git.
    • E2E (tests/e2e/): Slow (>5s per file). Tests complete workflows using a full environment and a mock Claude CLI harness.

    Shared utilities like assertions, mocks, and fixtures are located in tests/helpers/.

  2. Understand Sandbox File Synchronization strategies

    main

    Ralph uses different synchronization models depending on the selected sandbox provider. Note that .git directories and Ralph's internal state (.ralph/ files, status.json, logs) are never synced in either direction to prevent loop control corruption.

    ProviderStrategyBehavior
    --sandbox dockerReal-time (bind mount)The project directory is bind-mounted read-write at /workspace. Changes are visible instantly in both directions. Sync flags are not supported for this provider.
    --sandbox e2bSnapshot + per-iteration downloadThe project uploads once at session start. After every loop iteration, changed files download back to the host. Deletions and renames propagate via a manifest.
  3. Current Project Status and Roadmap

    main

    As of version v0.9.8 (updated 2026-01-10), Ralph for Claude Code is in Phase 1 (CLI Modernization), which is approximately 80% complete. The core functionality is stable with 100% test pass rates across 276 tests.

    Development Roadmap:

    • Phase 1: CLI Modernization (In Progress): Focuses on modern CLI options, JSON output, session management, and ralph-import enhancements.
    • Phase 2: Agent SDK Integration (Planned): Will introduce an Agent SDK, custom tools, and a hybrid CLI/SDK architecture.
    • Phase 3: Configuration & Infrastructure (Planned): Will add .ralphrc support, JSON configuration files, log rotation, and dry-run mode.
    • Phase 4: Validation Testing (Planned): Includes tmux integration, monitor dashboards, and E2E full loop tests.
    • Phase 5: GitHub Issue Integration (Planned): Enables importing plans from GitHub issues and managing issue lifecycles.
    • Phase 6: Sandbox Execution Environments (Planned): Introduces sandboxing via Docker, E2B Cloud, Daytona, and Cloudflare.
  4. Register an Agent Provider

    main

    To register a new provider, ensure the following:

    1. File Placement: Place the script in lib/agents/<provider>.sh.
    2. Naming Convention: Use the AGENT_PROVIDER environment variable to select the provider. The loader will source lib/agents/${AGENT_PROVIDER}.sh.
    3. Function Export: The script must export three functions: <provider>_build_command, <provider>_normalize_output, and <provider>_capabilities.
    4. Selection Order: The active provider is resolved in the following order: Environment Variable (AGENT_PROVIDER) > CLI Argument > .ralphrc config (defaulting to claude).
  5. Add new BATS test files

    main

    To add a new test file to the suite:

    1. Create a new .bats file in the appropriate directory (e.g., tests/unit/).
    2. Make the file executable: chmod +x <filename>.bats.
    3. Include the standard header and load the test helper:
      #!/usr/bin/env bats
      load '../helpers/test_helper'
    4. Run the test file directly using bats <path_to_file> to verify it passes.
    touch tests/unit/test_my_feature.bats
    chmod +x tests/unit/test_my_feature.bats
    
    # Content of test_my_feature.bats:
    #!/usr/bin/env bats
    # Unit tests for my feature
    
    load '../helpers/test_helper'
    
    bats tests/unit/test_my_feature.bats
  6. Configure Ralph Development Instructions and Tasks

    main

    Ralph's behavior is driven by two primary configuration files in the .ralph/ directory:

    1. .ralph/PROMPT.md (Context & Objectives)

    Define the persona, project context, current objectives, and key principles. This tells Ralph what it is building and how it should approach the code (e.g., 'Use async/await', 'Follow Node.js best practices').

    2. .ralph/fix_plan.md (Task List)

    Define a prioritized list of specific, actionable tasks using Markdown checkboxes. Ralph will iterate through these tasks in order.

    Example Task Format:

    ## Priority 1: Core Structure
    - [ ] Set up package.json with dependencies
    - [ ] Create src/index.js entry point
  7. Import development plans from GitHub Issues

    main

    Use ralph-import to convert GitHub issues and their discussion comments into Ralph-formatted PRDs. The issue title becomes the project name (slugified) and the body becomes the PRD content.

    Prerequisites

    • GitHub CLI (gh) installed and authenticated (gh auth login).
    • jq installed for JSON parsing.

    Usage

    • Specific issue: ralph-import --github-issue <number>
    • Search/Filter: Use --github-search, --github-label, --github-assignee, or --github-milestone to find issues.
    • Include comments: Use --include-comments to include discussion text (use with caution on public repos).
    • Custom project name: Provide a name after the flags: ralph-import --github-issue 42 my-project.
    • Dry run: Use --dry-run to preview matches without importing.
    # Import a specific issue by number
    ralph-import --github-issue 42
    
    # Import the oldest open issue with a label
    ralph-import --github-label "sprint-1"
    
    # Import issue comments
    ralph-import --github-issue 42 --include-comments
    
    # Preview matches
    ralph-import --github-label bug --dry-run
  8. Manage Claude session expiration

    main

    To prevent context pollution and API errors from stale sessions, implement a maximum age for Claude sessions. A recommended approach is to check the file modification time of the session file and start a fresh session if it exceeds a threshold (e.g., 24 hours).

    # Add session expiration (24 hours)
    CLAUDE_SESSION_MAX_AGE=$((24 * 3600))  # 24 hours in seconds
    
    init_claude_session() {
        if [[ -f "$CLAUDE_SESSION_FILE" ]]; then
            local session_age=$(($(date +%s) - $(stat -c %Y "$CLAUDE_SESSION_FILE" 2>/dev/null || echo 0)))
    
            if [[ $session_age -gt $CLAUDE_SESSION_MAX_AGE ]]; then
                log_status "INFO" "Session expired (${session_age}s old), starting fresh"
                rm -f "$CLAUDE_SESSION_FILE"
            else
                local session_id=$(cat "$CLAUDE_SESSION_FILE" 2>/dev/null)
                if [[ -n "$session_id" ]]; then
                    log_status "INFO" "Resuming Claude session: ${session_id:0:20}... (${session_age}s old)"
                    echo "$session_id"
                    return 0
                fi
            fi
        fi
    
        log_status "INFO" "Starting new Claude session"
        echo ""
    }
  9. Debug failing BATS tests

    main

    If a test fails, use these strategies to investigate:

    1. Filter for a specific test: Run only the test that is failing using the --filter flag.
    2. Add debug output: Use echo "..." >&3 inside your @test block to print messages to stdout during the test execution.
    3. Enable bash tracing: Use set -x inside a test block to trace command execution.
    4. Inspect temporary files: Comment out cleanup logic in your teardown() function to inspect files in $TEST_TEMP_DIR after a failure.
    # 1. Run single test
    bats tests/unit/test_rate_limiting.bats --filter "can_make_call"
    
    # 2. Add debug output
    @test "debugging example" {
        echo "Before command" >&3
    
        run my_function
    
        echo "Status: $status" >&3
        echo "Output: $output" >&3
    
        assert_success
    }
    
    # 3. Use set -x for tracing
    @test "trace example" {
        set -x
        run my_function
        set +x
    }
    
    # 4. Preserve temp directory
    teardown() {
        echo "Temp dir: $TEST_TEMP_DIR" >&3
        # Comment out cleanup to inspect:
        # rm -rf "$TEST_TEMP_DIR"
    }
  10. Build a queue with ralph-queue add

    main

    Use ralph-queue add to populate the .ralph/queue.json file with work items. You can add items using metadata filters (reusing ralph-import flags), explicit GitHub issue numbers, or local PRD/spec files. Adding is idempotent; existing items are skipped.

    # 1) Metadata filters
    ralph-queue add --github-label "bug,P0"            # ALL labels (comma = AND)
    ralph-queue add --github-milestone "v1.0"
    ralph-queue add --github-search "login timeout"
    ralph-queue add --github-title "[P0]*"             # * is the only wildcard
    ralph-queue add --github-assignee @me              # or a username, or none
    ralph-queue add --github-label bug --exclude-label wontfix
    ralph-queue add --github-state all                 # open (default), closed, all
    ralph-queue add --github-label bug --repo owner/repo
    
    # 2) Explicit issue numbers
    ralph-queue add --github-issues 69,70,71
    
    # 3) A local PRD/spec file
    ralph-queue add --prd ./docs/feature.md
  11. Implement security audit logging for sensitive events

    main

    To improve observability and security, log sensitive events (such as session changes, tool permission changes, or version mismatches) to a structured audit log. This allows for easier auditing and analysis compared to standard operational logs.

    # Add security audit logging
    SECURITY_AUDIT_LOG="logs/security_audit.log"
    
    log_security_event() {
        local event_type=$1
        local event_data=$2
    
        local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
        local audit_entry=$(jq -n \
            --arg ts "$timestamp" \
            --arg type "$event_type" \
            --arg data "$event_data" \
            '{timestamp: $ts, event_type: $type, data: $data}'
        )
    
        echo "$audit_entry" >> "$SECURITY_AUDIT_LOG"
    }
  12. Run Claude Code in a Docker sandbox

    main

    To isolate Claude's execution (file edits and command running), you can use a Docker sandbox. Ralph's monitoring and rate limiting remain on the host, while the project directory is bind-mounted to /workspace in the container.

    Setup

    1. Pull the image: docker pull ghcr.io/frankbria/ralph-sandbox:latest
    2. Tag it: docker tag ghcr.io/frankbria/ralph-sandbox:latest ralph-sandbox:latest

    Usage

    • --sandbox docker: Enables Docker execution using the default image.
    • --sandbox-image <image>: Use a specific image (must have claude on PATH).
    • --sandbox-memory <size>: Set memory limit (e.g., 8g).
    • --sandbox-cpus <count>: Set CPU limit.
    • --sandbox-network <type>: Set network mode (e.g., none for isolation).

    Credentials

    Ralph securely passes ANTHROPIC_API_KEY via an env-file or copies ~/.claude/.credentials.json into the container. Both are cleaned up automatically on exit.