461 lines
16 KiB
Markdown
461 lines
16 KiB
Markdown
# Ralph Reference Guide
|
|
|
|
This reference guide provides essential information for troubleshooting and understanding Ralph's autonomous development loop.
|
|
|
|
In bmalph-managed projects, start Ralph with `bmalph run`. When you need direct loop flags such as `--reset-circuit` or `--live`, invoke `bash .ralph/ralph_loop.sh ...` from the project root.
|
|
|
|
## Table of Contents
|
|
|
|
1. [Configuration Files](#configuration-files)
|
|
2. [Project Configuration (.ralph/.ralphrc)](#project-configuration-ralphralphrc)
|
|
3. [Session Management](#session-management)
|
|
4. [Circuit Breaker](#circuit-breaker)
|
|
5. [Exit Detection](#exit-detection)
|
|
6. [Live Streaming](#live-streaming)
|
|
7. [Troubleshooting](#troubleshooting)
|
|
|
|
---
|
|
|
|
## Configuration Files
|
|
|
|
Ralph uses several files within the `.ralph/` directory, plus an optional legacy fallback config at the project root:
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `.ralph/PROMPT.md` | Main prompt that drives each loop iteration |
|
|
| `.ralph/@fix_plan.md` | Prioritized task list that Ralph follows |
|
|
| `.ralph/@AGENT.md` | Build and run instructions maintained by Ralph |
|
|
| `.ralph/status.json` | Real-time status tracking (JSON format) |
|
|
| `.ralph/logs/` | Execution logs for each loop iteration |
|
|
| `.ralph/.ralph_session` | Current session state |
|
|
| `.ralph/.circuit_breaker_state` | Circuit breaker state |
|
|
| `.ralph/live.log` | Live streaming output file for monitoring |
|
|
| `.ralph/.loop_start_sha` | Git HEAD SHA captured at loop start for progress detection |
|
|
| `.ralph/.ralphrc` | Project-specific configuration installed by bmalph |
|
|
| `.ralphrc` (project root, legacy fallback) | Optional legacy configuration for older standalone Ralph layouts |
|
|
|
|
### Rate Limiting
|
|
|
|
- Default: 100 API calls per hour (configurable via `--calls` flag or `.ralph/.ralphrc`)
|
|
- Automatic hourly reset with countdown display
|
|
- Call tracking persists across script restarts
|
|
|
|
---
|
|
|
|
## Project Configuration (.ralph/.ralphrc)
|
|
|
|
In bmalph-managed projects, Ralph reads `.ralph/.ralphrc` for per-project settings.
|
|
For backward compatibility with older standalone Ralph layouts, it also falls back to a project-root `.ralphrc` when the bundled config file is missing.
|
|
|
|
### Precedence
|
|
|
|
Environment variables > Ralph config file > script defaults
|
|
|
|
### Available Settings
|
|
|
|
| Variable | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `PROJECT_NAME` | `my-project` | Project name for prompts and logging |
|
|
| `PROJECT_TYPE` | `unknown` | Project type (javascript, typescript, python, rust, go) |
|
|
| `MAX_CALLS_PER_HOUR` | `100` | Rate limit for API calls |
|
|
| `CLAUDE_TIMEOUT_MINUTES` | `15` | Timeout per loop driver invocation |
|
|
| `CLAUDE_OUTPUT_FORMAT` | `json` | Output format (json or text) |
|
|
| `ALLOWED_TOOLS` | `Write,Read,Edit,MultiEdit,Glob,Grep,Task,TodoWrite,WebFetch,WebSearch,EnterPlanMode,ExitPlanMode,NotebookEdit,Bash` | Claude Code only. Ignored by codex, cursor, and copilot |
|
|
| `CLAUDE_PERMISSION_MODE` | `bypassPermissions` | Claude Code only. Prevents interactive approval workflows from blocking unattended loops without relying on beta headers |
|
|
| `PERMISSION_DENIAL_MODE` | `continue` | How Ralph responds to permission denials: continue, halt, or threshold |
|
|
| `SESSION_CONTINUITY` | `true` | Maintain context across loops |
|
|
| `SESSION_EXPIRY_HOURS` | `24` | Session expiration time |
|
|
| `RALPH_VERBOSE` | `false` | Enable verbose logging |
|
|
| `CB_NO_PROGRESS_THRESHOLD` | `3` | Loops with no progress before circuit opens |
|
|
| `CB_SAME_ERROR_THRESHOLD` | `5` | Loops with same error before circuit opens |
|
|
| `CB_OUTPUT_DECLINE_THRESHOLD` | `70` | Output decline percentage threshold |
|
|
| `CB_COOLDOWN_MINUTES` | `30` | Minutes before OPEN auto-recovers to HALF_OPEN |
|
|
| `CB_AUTO_RESET` | `false` | Reset circuit to CLOSED on startup |
|
|
| `TASK_SOURCES` | `local` | Where to import tasks from (local, beads, github) |
|
|
|
|
### Generation
|
|
|
|
bmalph copies `ralphrc.template` to `.ralph/.ralphrc` during `bmalph init`. Untouched managed configs are updated on upgrade, while customized `.ralph/.ralphrc` files are preserved.
|
|
|
|
---
|
|
|
|
## Session Management
|
|
|
|
Ralph maintains session continuity across loop iterations using `--resume` with explicit session IDs.
|
|
|
|
### Session Continuity
|
|
|
|
Ralph uses `--resume <session_id>` instead of `--continue` to resume sessions. This ensures Ralph only resumes its own saved sessions and avoids hijacking unrelated active sessions.
|
|
|
|
This applies to every driver that exposes resumable IDs today:
|
|
|
|
- Claude Code
|
|
- OpenAI Codex
|
|
- Cursor
|
|
|
|
### Session Files
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `.ralph/.ralph_session` | Current Ralph session state (active or reset/inactive) |
|
|
| `.ralph/.ralph_session_history` | History of last 50 session transitions |
|
|
| `.ralph/.claude_session_id` | Persisted driver session ID (shared filename for historical reasons; used by Claude Code, Codex, and Cursor) |
|
|
|
|
### Session Lifecycle
|
|
|
|
Sessions are automatically reset when:
|
|
- Circuit breaker opens (stagnation detected)
|
|
- Manual interrupt (Ctrl+C / SIGINT)
|
|
- Project completion (graceful exit)
|
|
- Manual circuit breaker reset (`bash .ralph/ralph_loop.sh --reset-circuit`)
|
|
- Manual session reset (`bash .ralph/ralph_loop.sh --reset-session`)
|
|
|
|
### Session Expiration
|
|
|
|
Sessions expire after 24 hours (configurable via `SESSION_EXPIRY_HOURS` in `.ralph/.ralphrc`). When expired:
|
|
- A new session is created automatically
|
|
- Previous context is not preserved
|
|
- Session history records the transition
|
|
|
|
### Session State Structure
|
|
|
|
Active session payload:
|
|
|
|
```json
|
|
{
|
|
"session_id": "uuid-string",
|
|
"created_at": "ISO-timestamp",
|
|
"last_used": "ISO-timestamp"
|
|
}
|
|
```
|
|
|
|
Reset/inactive payload:
|
|
|
|
```json
|
|
{
|
|
"session_id": "",
|
|
"reset_at": "ISO-timestamp",
|
|
"reset_reason": "reason string"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Circuit Breaker
|
|
|
|
The circuit breaker prevents runaway loops by detecting stagnation.
|
|
|
|
### States
|
|
|
|
| State | Description | Action |
|
|
|-------|-------------|--------|
|
|
| **CLOSED** | Normal operation | Loop continues |
|
|
| **HALF_OPEN** | Monitoring after recovery | Testing if issue resolved |
|
|
| **OPEN** | Halted due to stagnation | Loop stops |
|
|
|
|
### Thresholds
|
|
|
|
| Threshold | Default | Description |
|
|
|-----------|---------|-------------|
|
|
| `CB_NO_PROGRESS_THRESHOLD` | 3 | Open circuit after N loops with no file changes |
|
|
| `CB_SAME_ERROR_THRESHOLD` | 5 | Open circuit after N loops with repeated errors |
|
|
| `CB_OUTPUT_DECLINE_THRESHOLD` | 70% | Open circuit if output declines by >N% |
|
|
| `CB_PERMISSION_DENIAL_THRESHOLD` | 2 | Open circuit after N loops with permission denials |
|
|
| `CB_COOLDOWN_MINUTES` | 30 | Minutes before OPEN auto-recovers to HALF_OPEN |
|
|
| `CB_AUTO_RESET` | false | Reset to CLOSED on startup (bypasses cooldown) |
|
|
|
|
### Permission Denial Detection
|
|
|
|
When the active driver is denied permission to execute commands, Ralph:
|
|
1. Detects permission denials from the JSON output
|
|
2. Applies `PERMISSION_DENIAL_MODE` from `.ralph/.ralphrc`
|
|
3. Keeps `last_action: permission_denied` visible in the status file and dashboard
|
|
|
|
`PERMISSION_DENIAL_MODE` behavior:
|
|
- `continue` keeps looping and logs the denial
|
|
- `halt` stops immediately with reason `permission_denied`
|
|
- `threshold` keeps looping until `CB_PERMISSION_DENIAL_THRESHOLD` opens the circuit breaker
|
|
|
|
### Auto-Recovery Cooldown
|
|
|
|
After `CB_COOLDOWN_MINUTES` (default: 30) in OPEN state, the circuit auto-transitions to HALF_OPEN. From HALF_OPEN, if progress is detected, circuit goes to CLOSED; otherwise back to OPEN.
|
|
|
|
Set `CB_AUTO_RESET=true` in `.ralph/.ralphrc` to bypass cooldown entirely and reset to CLOSED on startup.
|
|
|
|
### Circuit Breaker State Structure
|
|
|
|
```json
|
|
{
|
|
"state": "CLOSED|HALF_OPEN|OPEN",
|
|
"consecutive_no_progress": 0,
|
|
"consecutive_same_error": 0,
|
|
"consecutive_permission_denials": 0,
|
|
"last_progress_loop": 5,
|
|
"total_opens": 0,
|
|
"reason": "string (when OPEN)",
|
|
"opened_at": "ISO-timestamp (when OPEN)",
|
|
"current_loop": 10
|
|
}
|
|
```
|
|
|
|
### Recovery
|
|
|
|
To reset the circuit breaker:
|
|
```bash
|
|
bash .ralph/ralph_loop.sh --reset-circuit
|
|
```
|
|
|
|
---
|
|
|
|
## Exit Detection
|
|
|
|
Ralph uses multiple mechanisms to detect when to exit the loop.
|
|
|
|
### Exit Conditions
|
|
|
|
| Condition | Threshold | Description |
|
|
|-----------|-----------|-------------|
|
|
| Consecutive done signals | 2 | Exit on repeated completion signals |
|
|
| Test-only loops | 3 | Exit if too many test-only iterations |
|
|
| Fix plan complete | All [x] | Exit when all tasks are marked complete |
|
|
| EXIT_SIGNAL + completion_indicators | Both | Dual verification for project completion |
|
|
|
|
### EXIT_SIGNAL Gate
|
|
|
|
The `completion_indicators` exit condition requires dual verification:
|
|
|
|
| completion_indicators | EXIT_SIGNAL | Result |
|
|
|-----------------------|-------------|--------|
|
|
| >= 2 | `true` | **Exit** ("project_complete") |
|
|
| >= 2 | `false` | **Continue** (agent still working) |
|
|
| >= 2 | missing | **Continue** (defaults to false) |
|
|
| < 2 | `true` | **Continue** (threshold not met) |
|
|
|
|
**Rationale:** Natural language patterns like "done" or "complete" can trigger false positives during productive work. By requiring an explicit `EXIT_SIGNAL` confirmation, Ralph avoids exiting mid-iteration.
|
|
|
|
When the agent outputs `STATUS: COMPLETE` with `EXIT_SIGNAL: false`, the explicit `false` takes precedence. This allows marking a phase complete while indicating more phases remain.
|
|
|
|
### RALPH_STATUS Block
|
|
|
|
The coding agent should include this status block at the end of each response:
|
|
|
|
```
|
|
---RALPH_STATUS---
|
|
STATUS: IN_PROGRESS | COMPLETE | BLOCKED
|
|
TASKS_COMPLETED_THIS_LOOP: 0 | 1
|
|
FILES_MODIFIED: <number>
|
|
TESTS_STATUS: PASSING | FAILING | NOT_RUN
|
|
WORK_TYPE: IMPLEMENTATION | TESTING | DOCUMENTATION | REFACTORING
|
|
EXIT_SIGNAL: false | true
|
|
RECOMMENDATION: <one line summary of what to do next>
|
|
---END_RALPH_STATUS---
|
|
```
|
|
|
|
### When to Set EXIT_SIGNAL: true
|
|
|
|
Set EXIT_SIGNAL to **true** when ALL conditions are met:
|
|
1. All items in `@fix_plan.md` are marked `[x]`
|
|
2. All tests are passing (or no tests exist for valid reasons)
|
|
3. No errors or warnings in the last execution
|
|
4. All requirements from specs/ are implemented
|
|
5. Nothing meaningful left to implement
|
|
|
|
### Progress Detection
|
|
|
|
Ralph detects progress through both uncommitted file changes AND git commits made within a loop. Before each loop, Ralph captures `git rev-parse HEAD`; if HEAD changes during the loop, committed files count as progress alongside working tree changes.
|
|
|
|
---
|
|
|
|
## Live Streaming
|
|
|
|
Ralph supports real-time streaming output with the `--live` flag.
|
|
|
|
### Usage
|
|
|
|
```bash
|
|
bash .ralph/ralph_loop.sh --live # Live streaming output
|
|
bash .ralph/ralph_loop.sh --monitor --live # Live streaming with tmux monitoring
|
|
```
|
|
|
|
### How It Works
|
|
|
|
- Live mode switches the active driver to its structured streaming format and pipes the stream through `jq`
|
|
- Cursor background loop execution stays on `json` output and switches to `stream-json` for live display
|
|
- Claude Code also uses `stream-json` for live display, while Codex streams its native JSONL events directly
|
|
- Shows text deltas and tool invocations in real-time
|
|
- Requires `jq` and `stdbuf` (from coreutils); falls back to background mode if unavailable
|
|
|
|
### Monitoring Layout
|
|
|
|
When using `--monitor` with `--live`, tmux creates a 3-pane layout:
|
|
- **Left pane:** Ralph loop with live streaming
|
|
- **Right-top pane:** `tail -f .ralph/live.log` (live driver output)
|
|
- **Right-bottom pane:** status dashboard (`bmalph watch` when available)
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Common Issues
|
|
|
|
#### Ralph exits too early
|
|
|
|
**Symptoms:** Loop stops before work is complete
|
|
|
|
**Causes:**
|
|
- EXIT_SIGNAL set to true prematurely
|
|
- completion_indicators triggered by natural language
|
|
- All `@fix_plan.md` items marked complete
|
|
|
|
**Solutions:**
|
|
1. Ensure EXIT_SIGNAL is only true when genuinely complete
|
|
2. Add remaining tasks to `@fix_plan.md`
|
|
3. Check `.ralph/.response_analysis` for exit reasons
|
|
|
|
#### Ralph doesn't exit when complete
|
|
|
|
**Symptoms:** Loop continues with busywork
|
|
|
|
**Causes:**
|
|
- EXIT_SIGNAL not being set to true
|
|
- `@fix_plan.md` has unmarked items
|
|
- completion_indicators threshold not met
|
|
|
|
**Solutions:**
|
|
1. Ensure RALPH_STATUS block is included in responses
|
|
2. Set EXIT_SIGNAL: true when all work is done
|
|
3. Mark all completed items in `@fix_plan.md`
|
|
|
|
#### Circuit breaker opens unexpectedly
|
|
|
|
**Symptoms:** "OPEN - stagnation detected" message
|
|
|
|
**Causes:**
|
|
- Same error recurring across loops
|
|
- No file changes for multiple loops
|
|
- Output volume declining significantly
|
|
|
|
**Solutions:**
|
|
1. Check `.ralph/logs/` for the recurring error
|
|
2. Fix the underlying issue causing the error
|
|
3. Reset circuit breaker: `bash .ralph/ralph_loop.sh --reset-circuit`
|
|
|
|
#### Permission denied blocks progress
|
|
|
|
**Symptoms:** "OPEN - permission_denied" message
|
|
|
|
**Causes:**
|
|
- The active driver denied permission to run commands
|
|
- `ALLOWED_TOOLS` in `.ralph/.ralphrc` too restrictive for Claude Code
|
|
- The active non-Claude driver rejected a tool under its native permission model
|
|
|
|
**Solutions:**
|
|
1. For Claude Code, update `ALLOWED_TOOLS` in `.ralph/.ralphrc` to include needed tools
|
|
2. For Claude Code unattended loops, keep `CLAUDE_PERMISSION_MODE="bypassPermissions"` in `.ralph/.ralphrc`
|
|
3. For codex, cursor, and copilot, review the driver's native permission settings; `ALLOWED_TOOLS` is ignored
|
|
4. If you want unattended behavior, keep `PERMISSION_DENIAL_MODE="continue"` in `.ralph/.ralphrc`
|
|
5. Reset circuit breaker if needed: `bash .ralph/ralph_loop.sh --reset-circuit`
|
|
|
|
#### Session expires mid-project
|
|
|
|
**Symptoms:** Context lost, session age > 24h
|
|
|
|
**Causes:**
|
|
- Long gaps between loop iterations
|
|
- Session not being refreshed
|
|
|
|
**Solutions:**
|
|
1. Sessions are designed to expire after 24h (configurable via `SESSION_EXPIRY_HOURS`)
|
|
2. Start a new session with `bash .ralph/ralph_loop.sh --reset-session`
|
|
3. Context will be rebuilt from `@fix_plan.md` and `specs/`
|
|
|
|
#### Cursor preflight fails
|
|
|
|
**Symptoms:** `bmalph doctor` or `bmalph run --driver cursor` fails before the loop starts
|
|
|
|
**Causes:**
|
|
- `command -v jq` fails in the bash environment Ralph uses
|
|
- `command -v cursor-agent` fails in that same bash environment
|
|
- `cursor-agent status` reports an authentication problem
|
|
|
|
**Solutions:**
|
|
1. Run `command -v jq` in the same bash shell Ralph uses and install `jq` if missing
|
|
2. Run `command -v cursor-agent` and ensure the official Cursor CLI is on the bash `PATH`
|
|
3. Run `cursor-agent status` and sign in to Cursor before starting Ralph
|
|
|
|
### Diagnostic Commands
|
|
|
|
```bash
|
|
# Check Ralph status
|
|
bash .ralph/ralph_loop.sh --status
|
|
|
|
# Check circuit breaker state
|
|
bash .ralph/ralph_loop.sh --circuit-status
|
|
|
|
# Reset circuit breaker
|
|
bash .ralph/ralph_loop.sh --reset-circuit
|
|
|
|
# Auto-reset circuit breaker (bypasses cooldown)
|
|
bash .ralph/ralph_loop.sh --auto-reset-circuit
|
|
|
|
# Reset session
|
|
bash .ralph/ralph_loop.sh --reset-session
|
|
|
|
# Enable live streaming
|
|
bash .ralph/ralph_loop.sh --live
|
|
|
|
# Live streaming with monitoring
|
|
bash .ralph/ralph_loop.sh --monitor --live
|
|
```
|
|
|
|
### Log Files
|
|
|
|
Loop execution logs are stored in `.ralph/logs/`:
|
|
- Each loop iteration creates a timestamped log file
|
|
- Logs contain Claude's output and status information
|
|
- Use logs to diagnose issues with specific iterations
|
|
|
|
### Status File Structure
|
|
|
|
`.ralph/status.json`:
|
|
```json
|
|
{
|
|
"timestamp": "ISO-timestamp",
|
|
"loop_count": 10,
|
|
"calls_made_this_hour": 25,
|
|
"max_calls_per_hour": 100,
|
|
"last_action": "description",
|
|
"status": "running|completed|halted|paused|stopped|success|graceful_exit|error",
|
|
"exit_reason": "reason (if exited)",
|
|
"next_reset": "timestamp for rate limit reset"
|
|
}
|
|
```
|
|
|
|
`bmalph status` normalizes these raw bash values to `running`, `blocked`, `completed`, `not_started`, or `unknown`.
|
|
|
|
---
|
|
|
|
## Error Detection
|
|
|
|
Ralph uses two-stage error filtering to eliminate false positives.
|
|
|
|
### Stage 1: JSON Field Filtering
|
|
Filters out JSON field patterns like `"is_error": false` that contain the word "error" but aren't actual errors.
|
|
|
|
### Stage 2: Actual Error Detection
|
|
Detects real error messages:
|
|
- Error prefixes: `Error:`, `ERROR:`, `error:`
|
|
- Context-specific: `]: error`, `Link: error`
|
|
- Occurrences: `Error occurred`, `failed with error`
|
|
- Exceptions: `Exception`, `Fatal`, `FATAL`
|
|
|
|
### Multi-line Error Matching
|
|
Ralph verifies ALL error lines appear in ALL recent history files before declaring a stuck loop, preventing false negatives when multiple distinct errors occur.
|
|
|
|
---
|
|
|
|
## Further Reading
|
|
|
|
- [BMAD-METHOD Documentation](https://github.com/bmad-code-org/BMAD-METHOD)
|
|
- [Ralph Repository](https://github.com/snarktank/ralph)
|