Ralph

Ralph Integration

Prefer the old long-form? See V1 archive.

What ai-ralph is

Multi-engine autonomous AI dev loop. Given a fix_plan.md inside a code repo, drives Claude / Devin / Codex in a controlled loop, committing incrementally, until done. Workbench points at an ai-ralph fork under your org (e.g. <your-org>/ai-ralph); any ai-ralph-compatible CLI with a plan + int surface works.

What the workbench adds

ai-ralph runs one repo natively. Workbench adds three things:

  1. Context routing (scripts/sync-context.sh): reads .workbench-state/approved.json, honours each artifact’s target_repos:, copies into matching repos/{name}/ai/. Repo role filters too: service → PRDs+specs+TDDs+ERD+ADRs; automation → PRDs+BDDs+test cases+test spec; shared-lib → specs+TDDs+ADRs; infra → ADRs only.
  2. Workspace-mode planning (scripts/ralph-plan.sh): wraps ralph-plan --workspace at repos/, writes per-repo .ralph/fix_plan.md sections in one pass. Per-repo loop is fallback.
  3. Cross-repo parallel dispatch (scripts/ralph-dispatch.sh): wraps ralph --workspace --parallel N at repos/ (default N = min(len(REPOS), 4)). Ralph owns loop, worktrees, commits, pushes, PRs. --status shells gh pr list + tail of each worker log.

One plan, multiple repos, parallel dispatch. No re-implementation of ralph internals.

Workspace-mode planning

wb.ralph-plan defaults to workspace mode: single ralph-plan --workspace at $WB_ROOT/repos/ aggregates approved context, scans repos/*, writes per-repo ## <repo-name> sections into repos/.ralph/fix_plan.md.

Mode resolver: CLI flag > WB_RALPH_PLAN_MODE > project.conf RALPH_PLAN_MODE > auto. Auto picks workspace when the installed ralph-plan advertises --workspace, else loops project.conf REPOS per-repo. Override: wb.ralph-plan --mode per-repo, env, or project.conf.

target_repos: routing

Every PRD, eng-spec, TDD, ERD, BDD, test-cases, test-spec, test-erd carries target_repos: [...] naming repos from project.conf REPOS. wb.publish / wb.approve call scripts/validate-artifact.py, which rejects missing, empty, or unregistered values. Flows into sync-context.sh and ralph-plan section routing. ADRs + epic-context exempt.

When steering.local/ is non-empty, sync-context.sh writes a markdown footer (entries tagged ADD / SUPERSEDE / REMOVE) to $WB_ROOT/repos/.ralph/pr_footer.md. Ralph appends it to every PR body via upstream pr-footer-append. Footer is removed when overlays empty.

Adapter scripts

scripts/sync-context.sh
  # Push approved workbench artifacts into each repos/{x}/ai/ dir.
  # Honors target_repos: per artifact and the repo's role filter.
  # Writes/removes repos/.ralph/pr_footer.md based on steering.local/ state.

scripts/ralph-context.sh
  # Internal alias for sync-context.sh used by ralph-plan.sh.

scripts/ralph-plan.sh [--mode workspace|per-repo|auto] [--engine ...] [--thinking ...] [--dry-run]
  # Resolver: CLI flag > env WB_RALPH_PLAN_MODE > project.conf RALPH_PLAN_MODE > auto.
  # Workspace: (cd repos && ralph-plan --workspace --engine $E --thinking $T)
  # Per-repo fallback: loops project.conf REPOS, runs ralph-plan inside each.

scripts/ralph-dispatch.sh [--parallel N [M]] [--max-tasks M] [--max-task-attempts K] [--respawn-delay SEC] [--no-tabs] [--engine ...] [--repos a,b] [--exclude c] [--status] [--dry-run]
  # (cd repos && ralph --workspace --parallel N [M] [--max-task-attempts K] [--respawn-delay SEC] [--no-tabs])
  # Default N = min(len(REPOS), 4). With M set, engages ralph's continuous mode.
  # Engine + continuous knobs passed through when ralph supports them; missing
  # continuous support fails fast (no silent fallback to batch).
  # --status: gh pr list per repo + tail of repos/.ralph/logs/.

scripts/ralph-enable-check.sh
  # Preflights that `ralph enable --workspace` ran at $WB_ROOT/repos/.
  # Called by wb.ralph-plan and wb.ralph-dispatch.

scripts/validate-artifact.py
  # Validates target_repos: against project.conf REPOS. Hooked into lifecycle.py
  # at both publish and approve. Pass-through for adr and epic-context types.

Single-repo debugging (workbench does not wrap this):

(cd "$WB_ROOT/repos/<name>" && ralph --live --monitor)

Continuous dispatch

wb.ralph-dispatch defaults to batch mode: spawn N agents, each runs the workspace loop, wrapper exits when all N stop. One-shot fan-out.

Continuous mode keeps N workers saturated until M total task attempts (success + failure both count) or queue drains. Right shape for long unattended runs over a deep workspace fix_plan.

Opt-in. Setting M flips the mode:

# Named form (preferred; pairs cleanly with project.conf)
wb.ralph-dispatch --parallel 3 --max-tasks 30

# Positional form (mirrors ralph's `--parallel N M` shape byte-identically)
wb.ralph-dispatch --parallel 3 30

# Drive from project.conf so the team runs the same shape
echo 'WB_RALPH_MAX_TASKS="50"' >> project.conf
wb.ralph-dispatch --parallel 4

Tuning knobs (inert without M; ralph accepts them in batch mode but they only matter in continuous):

Flag Env var project.conf key Default Meaning
--max-tasks M WB_RALPH_MAX_TASKS WB_RALPH_MAX_TASKS unset Engages continuous; total attempts cap.
--max-task-attempts K WB_RALPH_MAX_TASK_ATTEMPTS WB_RALPH_MAX_TASK_ATTEMPTS 1 (ralph) Per-task retry cap; task is skip-listed after K failures.
--respawn-delay SEC WB_RALPH_RESPAWN_DELAY WB_RALPH_RESPAWN_DELAY 0 (ralph) Cooldown between worker respawns.
--no-tabs WB_RALPH_DISABLE_TABS=true WB_RALPH_DISABLE_TABS (off) Force single-pane orchestrator.

Wrapper capability-gates the forwarding: continuous-mode flags pass through only when ralph --help advertises the --parallel N M surface. Older ralph causes wb.ralph-dispatch --max-tasks to fail fast with a clear error, not silent fallback to batch.

Hard rules