Files
Keep/.ralph/RALPH-REFERENCE.md

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)