# Ralph — Code Generation Agent: Technical Specification
## Overview
Ralph is a Rust-based command-line code generation agent that operates via an agentic loop ("The Ralph Loop"). It supports multiple LLM backends, enforces safety guardrails, uses search-enabled model prompting, and provides session persistence, context compaction, and checkpointing for long-running work.
---
## 1. CLI Interface
### Invocation
```
ralph [OPTIONS] [PROMPT]
ralph <SUBCOMMAND>
```
### Backend Flags (mutually exclusive)
| `--deepseek` | DeepSeek | `DEEPSEEK_API_KEY` |
### Defaults per provider
| DeepSeek | `deepseek-chat` |
### General Options
| `--model <name>` | Override default model for the selected provider |
| `--workspace <path>` | Target workspace directory (default: `.`) |
| `--max-turns <n>` | Max Ralph Loop iterations (default: 20) |
| `--dry-run` | Show planned actions without executing |
| `--no-confirm` | Skip confirmation prompts (use with caution) |
| `--context <file>` | Inject additional context from a file |
| `--output <format>` | Output format: `terminal` (default), `json` |
| `--verbose` | Show full LLM interactions |
| `--resume [session-id]` | Resume last session for workspace (or specific session ID) |
| `--new-session` | Force a new session, ignoring any existing one |
| `--checkpoint <name>` | Create a named checkpoint at session start, before any changes |
| `--auto-checkpoint` | Auto-checkpoint before every destructive operation |
| `-v, --version` | Print version |
| `-h, --help` | Print help |
### Subcommands
```
ralph sessions list
ralph sessions show <session-id>
ralph sessions clean [--older-than <days>]
ralph checkpoint list [--session <id>]
ralph checkpoint create <name> [--session <id>]
ralph checkpoint revert <name-or-number> [--session <id>] [--files-only]
ralph checkpoint show <name-or-number> [--session <id>]
```
### Examples
```bash
# Basic invocation
ralph --deepseek "Add unit tests to src/parser.rs"
ralph --deepseek --workspace ./my-project "Fix the failing build"
ralph --deepseek --dry-run "Migrate database schema to support multi-tenancy"
# Session & checkpoint management
ralph --deepseek --resume "Add error handling to the parser"
ralph --deepseek --checkpoint "before-refactor" "Refactor the auth module"
ralph checkpoint list
ralph checkpoint revert before-refactor
ralph sessions list
```
---
## 2. Environment Variables
```
DEEPSEEK_API_KEY # Required when using --deepseek
BRAVE_API_KEY # Optional: enables web search (Brave Search API)
SERP_API_KEY # Optional: enables web search (SerpAPI)
RALPH_DEFAULT_PROVIDER # Optional: default provider
RALPH_MAX_TURNS # Optional: override default max turns
RALPH_WORKSPACE # Optional: override default workspace path
```
---
## 3. The Ralph Loop
The Ralph Loop is the core agentic cycle. Each iteration is called a **turn**.
```
┌─────────────────────────────────────────────────────────────┐
│ RALPH LOOP │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ OBSERVE │ → │ PLAN │ → │ EXECUTE │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ↑ │ │
│ │ ┌──────────┐ │ │
│ └──────────│ VERIFY │ ←───────┘ │
│ └──────────┘ │
│ │ │
│ [Done / Max turns reached] │
└─────────────────────────────────────────────────────────────┘
```
### Phase: OBSERVE
- Read workspace state: file tree, git status, relevant file contents
- Parse prior tool call results and their outcomes
- Inject search results if prior turn requested them
- Check if compaction is needed; compact before calling LLM if threshold exceeded
### Phase: PLAN
- LLM is given full context and asked to reason about the next action
- Produces a structured plan: a list of tool calls to execute
- No filesystem mutations happen in this phase
### Phase: EXECUTE
- Execute planned tool calls in sequence (or in parallel where safe)
- Guardrails checked before every tool call
- Dangerous tools require explicit user confirmation (unless `--no-confirm`)
- Session state saved after each successful tool call
### Phase: VERIFY
- LLM reviews the results of executed tool calls
- Decides: continue loop, declare success, or declare failure with reason
- If `run_command` (e.g. tests, build) was executed, output is fed back as context
### Loop Exit Conditions
- LLM declares task complete
- LLM declares task failed (with explanation)
- Max turns reached
- User interrupts (Ctrl+C)
- Guardrail violation detected
---
## 4. Tool Definitions
### File Tools
| `read_file(path)` | Read file contents | No |
| `list_dir(path)` | List directory contents | No |
| `write_file(path, content)` | Create or overwrite a file | Yes (when overwriting existing) |
| `edit_file(path, old, new)` | Exact string replacement in a file | No |
| `delete_file(path)` | Delete a file | Yes |
### Shell Tools
| `run_command(cmd, cwd)` | Execute a shell command | Yes (first use per session unless whitelisted) |
| `run_test(cmd)` | Run test suite | No (whitelisted) |
| `run_build(cmd)` | Run build command | No (whitelisted) |
### Search Tools
| `search_web(query)` | Web search (provider-native or Brave API) |
| `search_codebase(pattern, path)` | Regex search within workspace |
### Meta Tools
| `ask_user(question)` | Pause loop and prompt the user for clarification |
| `declare_done(summary)` | Signal successful task completion |
| `declare_failed(reason)` | Signal task cannot be completed |
---
## 5. Search-Enabled Prompting
A core design principle: **Ralph always instructs the LLM to search before making assumptions about APIs, library versions, or recent changes.**
### System Prompt Strategy
The system prompt explicitly instructs the LLM to:
1. Use `search_web` when unsure about an API, dependency version, or language feature
2. Search for security advisories before using third-party libraries
3. Verify that generated code matches the installed dependency versions in `Cargo.toml`, `package.json`, etc.
4. Search for error messages if a `run_command` result contains unknown errors
### Search Capabilities
Web search is provider-agnostic. Ralph uses the `search_web` tool when either `BRAVE_API_KEY` (Brave Search API) or `SERP_API_KEY` (SerpAPI) is set. Brave takes priority if both are present. If neither is set, the tool is excluded from the LLM's tool list entirely.
---
## 6. Guardrails
### Hard Blocks (never proceed, always abort)
- Writing files outside the designated workspace
- Executing `rm -rf`, `sudo`, or any command with destructive flags without explicit user approval
- Sending workspace contents to any endpoint other than the configured LLM provider
- Accessing environment variables not in an explicit allowlist (`RALPH_ENV_ALLOWLIST`)
- Generating code that contains hardcoded secrets, credentials, or private keys
### Soft Guards (prompt user before proceeding)
- Overwriting any existing file
- Deleting files
- Running commands not in the whitelist (build, test runners)
- Making network requests from generated code to external services
### Confirmation Protocol
When a soft guard is triggered:
```
[ralph] About to execute: write_file("src/auth.rs")
This will overwrite an existing file.
Proceed? [y/N/d(iff)/c(heckpoint+proceed)]
```
- `d` shows a diff before the user decides
- `c` creates a checkpoint, then proceeds
### Rate Limiting
- Configurable max turns per session (default 20)
- Token budget tracking per session (warn at 80%, halt at 100%)
---
## 7. Session Persistence
Ralph automatically persists conversation state so that work can be resumed in any new terminal instance without losing context.
### Session Storage Layout
```
~/.ralph/
├── config.toml
├── sessions/
│ └── <session-id>/ # e.g. 2026-03-22_7f3a1b/
│ ├── session.json # metadata
│ ├── messages.json # full conversation history
│ ├── compacted.json # pre-compaction archive (if any)
│ └── checkpoints/
│ └── <seq>_<name>/ # e.g. 003_before-auth-refactor/
│ ├── checkpoint.json # checkpoint metadata
│ ├── messages.json # message history at this point
│ └── files/ # snapshots of modified workspace files
└── logs/
└── YYYY-MM-DD_<session-id>.log
```
### `session.json` Schema
```json
{
"session_id": "2026-03-22_7f3a1b",
"workspace": "/Users/alice/projects/myapp",
"provider": "anthropic",
"model": "claude-sonnet-4-6",
"created_at": "2026-03-22T09:00:00Z",
"last_active": "2026-03-22T09:45:00Z",
"turn_count": 12,
"status": "interrupted"
}
```
### Auto-Resume Behavior
On startup, Ralph:
1. Looks up sessions matching the current workspace path
2. If a matching session with status `interrupted` or `in_progress` exists, prompts:
```
[ralph] Found previous session (2026-03-22_7f3a1b, 12 turns, last active 45 min ago).
Resume? [Y/n]
```
3. If resumed, the full message history is injected into the LLM context before the new prompt
4. If declined (or `--new-session` used), a fresh session is created
### State Saved Per Turn
After every completed turn, Ralph writes:
- Updated `messages.json` with new messages appended
- Updated `session.json` (`last_active`, `turn_count`, `status`)
A Ctrl+C between turns loses at most the current in-progress turn.
---
## 8. Context Compaction
When accumulated conversation history approaches the provider's context window limit, Ralph compacts it to free space while preserving continuity.
### Trigger
Compaction fires when the estimated token count of `messages.json` exceeds `compaction_threshold` (default: 80% of the provider's context window).
### Provider Context Windows
| DeepSeek (`deepseek-chat`) | 64,000 tokens |
### Compaction Process
1. Ralph sends full message history to the LLM with this compaction prompt:
> "Summarize this conversation and all work done so far into a concise but complete context summary. Include: the original task, all files modified (with brief description of changes), commands run and their outcomes, current workspace state, and any unresolved issues. This summary replaces the conversation history — omit nothing that affects future decisions."
2. The summary replaces all but the last `keep_recent_turns` turns (default: 3) in the active window
3. The original full history is archived to `compacted.json` (never deleted)
4. A `[compact]` event is emitted in the terminal and logged
---
## 9. Checkpoints
A checkpoint is a named snapshot of the full conversation state and workspace files at a specific point in a session.
### What a Checkpoint Captures
- Full `messages.json` at time of checkpoint
- Snapshots of all workspace files Ralph has modified since session start
- Turn number, timestamp, and user-supplied name
### Creating a Checkpoint
**Via CLI flag (before task starts):**
```bash
ralph --anthropic --checkpoint "before-auth-refactor" "Refactor the auth module"
```
**Via subcommand (in an active or resumed session):**
```bash
ralph checkpoint create "stable-state"
```
**Automatically (configurable):**
```toml
[checkpoints]
auto_checkpoint_before_destructive = true
```
**Via interactive confirmation prompt:**
When Ralph asks for confirmation on a destructive action, type `c`:
```
[ralph] About to execute: write_file("src/auth.rs")
Proceed? [y/N/d(iff)/c(heckpoint+proceed)]
```
### Listing Checkpoints
```bash
ralph checkpoint list
```
```
Session: 2026-03-22_7f3a1b (current)
# Name Turn Timestamp
1 session-start 0 2026-03-22 09:00:01
2 before-auth-refactor 5 2026-03-22 09:22:14
3 stable-state 9 2026-03-22 09:38:55
```
---
## 10. Checkpoint Revert
### Revert Command
```bash
ralph checkpoint revert <name-or-number> [--session <id>] [--files-only]
```
### Revert Process
1. Ralph displays what will change:
```
[ralph] Reverting to checkpoint 'before-auth-refactor' (turn 5, 2026-03-22 09:22:14)
Files to restore:
src/auth.rs (overwrite with checkpoint version)
src/auth_test.rs (delete — did not exist at checkpoint)
Cargo.toml (overwrite with checkpoint version)
Conversation: turns 6–12 will be discarded
Proceed? [y/N/d(iff)]
```
2. On confirmation:
- Workspace files are restored from checkpoint's `files/` snapshot
- `messages.json` is replaced with the checkpoint's `messages.json`
- `session.json` turn count is rolled back
- A `[revert]` event is appended to the session log
### `--files-only`
Restores workspace files without rolling back conversation history. Useful when you want the LLM to know what happened but undo the file changes.
### Safety
- Revert always requires explicit confirmation (not skippable with `--no-confirm`)
- A new auto-checkpoint named `before-revert-<timestamp>` is always created first, making the revert itself reversible
- Files outside the workspace are never touched
---
## 11. Output & Logging
### Terminal Output (default)
Color-coded phase prefixes:
- `[observe]` — workspace scanning
- `[plan]` — LLM reasoning summary
- `[tool]` — tool call + result
- `[verify]` — LLM verification step
- `[compact]` — context compaction event
- `[checkpoint]` — checkpoint created/reverted
- `[ralph]` — confirmation prompts and status messages
- `[done]` / `[failed]` — final outcome
### JSON Output (`--output json`)
Each turn emits a JSON object:
```json
{
"turn": 1,
"phase": "execute",
"tool": "write_file",
"args": { "path": "src/lib.rs" },
"result": "ok",
"timestamp": "2026-03-22T10:00:00Z",
"session_id": "2026-03-22_7f3a1b"
}
```
### Log File
Written to `~/.ralph/logs/YYYY-MM-DD_<session-id>.log`
---
## 12. Error Handling
| Missing API key | Print clear error with env var name, exit 1 |
| LLM API error (rate limit) | Exponential backoff, max 3 retries |
| LLM API error (auth) | Print error, exit 1 |
| Tool call parse failure | Log warning, ask LLM to retry once |
| Guardrail violation | Print violation details, halt loop, exit 2 |
| Max turns reached | Print summary of progress, exit 3 |
| User Ctrl+C | Graceful shutdown, save session state, print partial progress |
| Session file corrupt | Warn and offer to start new session |
| Checkpoint restore failure | Print details, abort revert, original files untouched |
---
## 13. Configuration File
Ralph reads `~/.ralph/config.toml` (global) and `.ralph.toml` in the workspace root (local, takes precedence).
```toml
[defaults]
provider = "deepseek"
max_turns = 20
workspace = "."
confirm_overwrites = true
[providers.deepseek]
model = "deepseek-chat"
[search]
brave_api_key_env = "BRAVE_API_KEY" # env var name, not the key itself
serp_api_key_env = "SERP_API_KEY" # env var name, not the key itself
[guardrails]
blocked_commands = ["rm -rf", "sudo", "curl | bash", "wget | sh"]
env_allowlist = ["HOME", "PATH", "CARGO_HOME", "RUSTUP_HOME"]
max_tokens_per_session = 200000
[whitelisted_commands]
build = ["cargo build", "npm run build", "make"]
test = ["cargo test", "npm test", "pytest", "go test"]
[session]
auto_resume = true # prompt to resume if previous session found
sessions_dir = "~/.ralph/sessions"
clean_after_days = 30
[compaction]
enabled = true
threshold_pct = 80 # % of context window at which to compact
keep_recent_turns = 3 # turns to keep verbatim after compaction
[checkpoints]
auto_checkpoint_before_destructive = false
```
---
## 14. Project Structure (Rust)
```
ralph/
├── Cargo.toml
├── Cargo.lock
├── .ralph.toml # workspace config (optional)
├── docs/
│ ├── specs.md
│ └── project-plan.md
└── src/
├── main.rs # CLI entrypoint, arg parsing (clap), subcommand dispatch
├── config.rs # Config loading (~/.ralph/config.toml + workspace)
├── loop_runner.rs # Ralph Loop orchestration
├── session.rs # Session create, load, save, list, clean
├── compaction.rs # Context compaction logic
├── checkpoint.rs # Checkpoint create, list, revert
├── providers/
│ ├── mod.rs # LlmProvider trait
│ ├── anthropic.rs # Anthropic API client
│ ├── openai.rs # OpenAI API client
│ └── deepseek.rs # DeepSeek API client (reuses OpenAI client)
├── tools/
│ ├── mod.rs # Tool registry, ToolCall / ToolResult types
│ ├── file_tools.rs # read_file, write_file, edit_file, list_dir, delete_file
│ ├── shell_tools.rs # run_command, run_test, run_build
│ ├── search_tools.rs # search_web, search_codebase
│ └── meta_tools.rs # ask_user, declare_done, declare_failed
├── guardrails.rs # Guardrail checks
├── context.rs # Workspace context builder
├── prompts.rs # System prompt templates
├── output.rs # Terminal + JSON rendering
└── errors.rs # RalphError enum
```
---
## 15. Dependencies (Rust Crates)
| `clap` | CLI argument parsing + subcommands |
| `tokio` | Async runtime |
| `reqwest` | HTTP client for LLM APIs |
| `serde` / `serde_json` | JSON serialization (sessions, checkpoints, API payloads) |
| `toml` | Config file parsing |
| `anyhow` | Error handling |
| `thiserror` | Custom error types |
| `colored` | Terminal color output |
| `ignore` | Workspace file traversal (respects .gitignore) |
| `similar` | Diff generation for confirmations and checkpoint reverts |
| `regex` | Codebase search |
| `uuid` | Session/checkpoint ID generation |
| `dirs` | Platform-agnostic home directory |
| `indicatif` | Progress indicators |
| `chrono` | Timestamps for sessions and checkpoints |
| `tiktoken-rs` | Token counting for compaction threshold |
---
## 16. Non-Goals (v1.0)
- No GUI or web interface
- No multi-agent orchestration (single Ralph instance per session)
- No plugin system
- No support for local/self-hosted models (planned for v1.1)
- No shared/team sessions (sessions are local to the user's machine)