Skip to content

christopher-kapic/ralph-rs

Repository files navigation

ralph — Deterministic execution planner for coding agent harnesses

ralph-rs

A deterministic orchestrator for coding agent harnesses. Takes step-based plans and executes them through AI coding agents (Claude, Codex, OpenCode, Copilot, Goose, Pi) with retry loops, test validation, and git integration.

What it does

  • Plan management: Create, edit, and execute step-based plans for AI coding agents
  • Multi-harness support: Works with Claude Code, Codex, OpenCode, Copilot, Goose, Pi, and more
  • Deterministic execution: Subprocess orchestration with test validation, git commits, and rollback on failure
  • Retry with context: Failed attempts inject diffs and test output into retry prompts
  • Plan portability: Export/import plans as JSON for harness comparison and reuse

Install

Requirements: git >= 2.23 (uses git restore).

curl -fsSL https://raw.githubusercontent.com/christopher-kapic/ralph-rs/master/scripts/install.sh | bash

To install a specific version or to a custom directory:

# Specific version
curl -fsSL https://raw.githubusercontent.com/christopher-kapic/ralph-rs/master/scripts/install.sh | bash -s v0.2.0

# Custom directory
curl -fsSL https://raw.githubusercontent.com/christopher-kapic/ralph-rs/master/scripts/install.sh | INSTALL_DIR=~/.local/bin bash

Or build from source:

cargo install --path .

Quick Start

# Initialize config and database
ralph init

# Create a plan
ralph plan create auth --description "Add user authentication" --test "cargo build" --test "cargo test"

# Add steps (first positional is the step title, second is the plan slug)
ralph step add "Add user model" auth --description "Create User struct with id, email, password_hash fields" --criteria "User struct exists in src/models/user.rs" --criteria "Tests pass"
ralph step add "Add API endpoints" auth --description "Create login/register endpoints" --criteria "/api/login returns 200 with valid credentials"

# Approve and run
ralph plan approve auth
ralph run auth

Usage

Plan Management

ralph plan create <slug>               # Create a new plan
  [--description <d>]                     #   Plan description (also -d)
  [--test <cmd>]...                       #   Repeatable: deterministic test commands
  [--harness <h>]                         #   Plan-level harness override
  [--agent <name>]                        #   Plan-level agent definition
  [--branch <name>]                       #   Custom branch name
  [--depends-on <slug>]...                #   Plan-level dependencies

ralph plan list [--all] [--status <s>] [--archived]   # List plans
ralph plan show <slug>                 # Show plan details
ralph plan approve <slug>              # Approve plan (planning -> ready)
ralph plan delete <slug>               # Delete a plan
ralph plan archive <slug>              # Archive a completed/failed plan

Step Management

ralph step list [<slug>]               # List steps in a plan (defaults to active plan)
ralph step add <title> [<slug>]        # Add a step (title is positional)
  [--description <d>]                     #   Step description (also -d)
  [--criteria <c>]...                     #   Acceptance criteria
  [--agent <name>]                        #   Step-level agent override
  [--after <num>]                         #   Insert after step number
  [--import-json <FILE|->]                #   Bulk-insert from JSON (array or object)

ralph step remove <num> [<slug>]       # Remove step by position
ralph step edit <num> [<slug>]         # Edit step fields (--title/--description)
ralph step reset <num> [<slug>]        # Reset step to pending
ralph step move <num> [<slug>] --to <n># Reorder step

Execution

ralph run [<slug>]                     # Run all pending steps in a plan
ralph run [<slug>] --one               # Run only the next pending step
ralph run --all                        # Run every plan in dependency order
ralph run [<slug>] --from <n> --to <m> # Run a specific step range
ralph run [<slug>] --dry-run           # Print what would happen without executing
ralph run [<slug>] --current-branch    # Run on current branch (skip branch creation)
ralph run [<slug>] --auto-stash        # Auto-commit a dirty tree instead of bailing
ralph run [<slug>] --harness <h>       # Override harness for this run (beats the global --harness)
ralph resume [<slug>]                  # Resume from last failed step
ralph skip [<slug>]                    # Skip failed step, continue

Planning with a Harness

ralph plan harness generate <description>        # Delegate planning to an AI harness
ralph plan harness set <harness> [<slug>]        # Set the plan-generation harness
ralph plan harness show [<slug>]                 # Show the current harness for a plan

Portability

ralph export <slug> [-o <file>]        # Export plan to JSON
ralph import <file>                    # Import plan from JSON
  [--slug <name>]                         #   Override the plan slug on import
  [--branch <name>]                       #   Override the branch name on import

Utilities

ralph status [<slug>] [--verbose]      # Show execution status
ralph log [<slug>] [--step <n>] [--limit <n>] [--full|--lines <n>]   # Show execution logs
ralph agents <list|show|create|delete> # Manage agent file templates
ralph doctor                           # Check config, DB, harness availability

Harness Comparison

Export a plan and run it with different harnesses to compare results:

# Create and export a plan
ralph plan harness generate "Add user auth"
ralph export auth -o auth.json

# Import into each project copy (import writes to the DB scoped to the current cwd;
# use --slug to give each copy a distinct name if they share a database)
cd ~/myapp-claude && ralph import ~/auth.json --slug auth-claude
cd ~/myapp-codex  && ralph import ~/auth.json --slug auth-codex

# Run each copy with a different harness
cd ~/myapp-claude && ralph run auth-claude --harness claude &
cd ~/myapp-codex  && ralph run auth-codex  --harness codex  &

Configuration

Config lives at ~/.config/ralph-rs/config.json (Linux/macOS) with harness definitions, default harness, retry settings, and timeout configuration.

Relevant top-level keys:

  • default_harness — harness used when none is specified (must match a key under harnesses).
  • max_retries_per_step — retry budget per step (default: 3).
  • timeout_secs — harness invocation timeout in seconds. null, omitting the field, or the legacy value 0 all disable the timeout (default: disabled).
  • hook_timeout_secs — lifecycle hook timeout (0 disables; default: 120).
  • auto_stash — when true, ralph run auto-commits a dirty working tree before switching to the plan branch. When false (default) ralph run lists the dirty files and bails so you can stage or discard them intentionally; pass --auto-stash to override for a single run.

Agent definitions are markdown files in ~/.config/ralph-rs/agents/*.md.

Lifecycle Hooks

Ralph supports shell-based lifecycle hooks at four points during step execution: pre-step, post-step, pre-test, and post-test. Hooks are defined once in a reusable library at ~/.config/ralph-rs/hooks/*.md (nothing in your working directory) and then attached to plans or individual steps via CLI:

ralph hooks add my-review --lifecycle post-step --command "claude -p 'review this'"
ralph plan set-hook my-feature --lifecycle post-step --hook my-review       # every step
ralph step set-hook 3 --plan my-feature --lifecycle post-step --hook my-review  # one step
ralph hooks export -o bundle.json        # share with teammates
ralph hooks import bundle.json

Hooks can be global or path-scoped to specific project prefixes. When you run ralph plan harness generate, the plan agent is told which hooks are available and can attach them to steps it thinks deserve review.

Each hook runs with a wall-clock budget controlled by hook_timeout_secs in config.json (default: 120; set to 0 to disable). A hook that exceeds the budget is killed and its step attempt is marked failed.

For the full model (library layout, scope rules, sharing, worked examples for Claude Code / Codex / clippy), see docs/review-hooks.md.

Interactive TUI

Running ralph with no subcommand drops into a vim-flavored TUI modeled on lazygit. From here you can navigate plans, edit prompts, run plans, and answer questions raised by the harness without leaving the terminal.

ralph             # plan list (landing screen)
ralph run         # plan detail of the active plan, auto-starting the run
ralph run <slug>  # plan detail of <slug>, auto-starting the run

The TUI is opt-in — passing any non-default flag to ralph run (e.g., --one, --all, --harness, --json) keeps today's non-interactive behavior so scripts don't regress. The --non-interactive flag forces the same path from a TTY for cases like ralph run | tee log.txt.

Views

The TUI is multi-view, with ? opening a help overlay listing the bindings of the current view at any time:

View Entered by What it does
Plan list ralph Landing screen; tile per plan, sort by recency
Archived list enter on the "Archived (N)" tile Same layout as plan list; enter unarchives, d permanently deletes
Plan detail enter on a plan tile, or ralph run Step list + right-pane summary or live run tails
Step detail enter on a step in plan detail Stacked editable prompt panes (c opens $EDITOR)
Sub-views D (deps), palette /plan set-hook, etc. Plan dependencies, plan hooks, step hooks, step tags

Common keybindings

The full list lives behind ? in each view; this is the cheat sheet.

Action Plan list Archived Plan detail Step detail
Navigate j / k j / k j / k j / k (panes)
Open / drill in enter / l (unarchive) enter / l (focus pane)
Pop view q q / h q / h q / h
Multi-select space space space
Create i / a i (above) / a (below) — (palette: /step add)
Delete d (archive) d (delete) d
Approve plan A (palette /plan approve)
Toggle questions on plan Q (palette /plan questions on|off)
Run / resume (palette /run) R
Stop the live run S
Skip running step s
Edit pane in $EDITOR c
Answer open question A a on questions pane
Move step Shift-J/Shift-K
Reset step r
Plan dependencies D
Help overlay ? ? ? ?
Command palette / or : / or : / or : / or :

Command palette

Pressing / or : opens an inline palette like in lazygit. Tab cycles candidates; enter runs:

/run [<branch>]
/plan harness [<name>]
/plan show|archive|unarchive|delete|approve|questions on|off [<slug>]
/plan dependency add|remove|list
/plan set-hook|unset-hook|hooks
/step add <title>
/step skip [<num>]
/step move <num> --to <m>
/step set-hook|unset-hook|edit --tags
/cancel
/export <slug> [-o <path>]
/import <path>
/quit
/help

Live runs and questions

When the TUI spawns the runner subprocess, the right pane streams NDJSON events from the runner: harness stdout/stderr, test output, phase transitions, and the final summary. See docs/ndjson-events.md for the event schema — the same stream is what --json / --jsonl emit on stdout.

If questions_enabled is on for the plan, the harness can pause the run with ralph question ask "...". The TUI surfaces a indicator on the step, opens an answer modal on A or a, and offers to resume the implementation once the last open question is answered.

For the full UX spec, see TUI-plan.md.

License

MIT

About

A single-binary implementation of ralph loops that doesn't add unnecessary files to your repo

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors