External Ralph Loop - Autonomous test coverage improvement tool powered by Claude Code CLI.
| Category | Technology | Version |
|---|---|---|
| Shell | Bash | 4.0+ |
| AI Integration | Claude Code CLI | Latest |
| Config | YAML (simple) | - |
| CI | GitHub Actions | - |
# Run in target project directory
TARGET_COVERAGE=80 /path/to/ralph-loop.sh
# With custom language adapter
LANGUAGE=javascript TARGET_COVERAGE=70 ralph-loop.sh
# Using YAML config (create .ralph-loop.yaml first)
ralph-loop.sh
# Validate shell syntax
bash -n ralph-loop.sh adapters/*.shexternal-ralph-loop/
├── ralph-loop.sh # Main entry point (orchestrator)
├── adapters/ # Language-specific adapters
│ ├── python.sh # pytest + coverage
│ ├── javascript.sh # jest/vitest + c8/nyc
│ └── go.sh # go test -cover
├── prompts/ # Prompt templates
│ └── default.txt # Default improvement prompt
└── examples/ # Sample configurations
├── python/
├── javascript/
└── go/
Each adapter implements 3 functions:
| Function | Purpose | Return |
|---|---|---|
adapter_apply_defaults() |
Set default TEST_COMMAND, COVERAGE_COMMAND, COVERAGE_PATTERN | void |
adapter_run_tests(iter_dir) |
Execute tests, save output to iter_dir | exit code file |
adapter_measure_coverage(iter_dir) |
Parse coverage, return percentage | stdout |
1. Load config (env > yaml > adapter defaults)
2. Load adapter (source adapters/{language}.sh)
3. Loop until target coverage or max iterations:
a. adapter_run_tests()
b. adapter_measure_coverage()
c. Build prompt with test results
d. Call Claude CLI (--print mode)
e. Archive iteration artifacts
4. Create final archive
| Key | Type | Description |
|---|---|---|
language |
string | Language adapter: python, javascript, go |
target_coverage |
number | Target coverage percentage (0-100) |
max_iterations |
number | Maximum loop iterations |
prompt_file |
string | Path to custom prompt file |
coverage_pattern |
string | Regex to filter coverage paths (Python only) |
test_command |
string | Test execution command |
coverage_command |
string | Coverage report command |
- Create
adapters/yourlanguage.sh:
#!/usr/bin/env bash
# adapters/yourlanguage.sh - YourLang adapter
adapter_apply_defaults() {
: "${TEST_COMMAND:=your-test-cmd}"
: "${COVERAGE_COMMAND:=your-coverage-cmd}"
: "${COVERAGE_PATTERN:=^src/}"
}
adapter_run_tests() {
local iter_dir="$1"
eval "$TEST_COMMAND" >"$iter_dir/test.stdout.txt" 2>"$iter_dir/test.stderr.txt"
echo $? >"$iter_dir/test.exitcode"
}
adapter_measure_coverage() {
local iter_dir="$1"
# Parse and output coverage percentage (e.g., "85.5")
eval "$COVERAGE_COMMAND" | parse_coverage_somehow
}- Add example:
examples/yourlanguage/.ralph-loop.yaml - Update README.md
- Run syntax check:
bash -n adapters/yourlanguage.sh
# Syntax validation
bash -n ralph-loop.sh adapters/*.sh
# Dry run (create test project first)
cd /tmp/test-project
LANGUAGE=python MAX_ITERATIONS=1 TARGET_COVERAGE=50 ralph-loop.sh- Use
set -euo pipefailin all scripts - Quote all variables:
"$var"not$var - Use
localfor function variables - Prefix adapter functions with
adapter_ - Error messages via
die()helper
MIT - see LICENSE file.