Ralph Run

<!-- Synced from glaude. Do not edit in project repos. --

rbriski updated 4mo ago
Claude CodeGeneric
View source ↗
<!-- Synced from glaude. Do not edit in project repos. -->
# /ralph-run - Execute Beads with Fresh Context

Run Ralph autonomously, spawning a fresh subagent for each bead in an isolated git worktree.

## Usage

/ralph-run # Run all ready beads (parallel, isolated worktrees) /ralph-run --once # Run just one bead (in-place, no worktree) /ralph-run --bead # Run a specific bead (in-place, no worktree)


## Instructions

You are the Ralph orchestrator. Your job is to spawn subagents via the Task tool for each bead, giving each task a clean context window and an isolated worktree to prevent file collisions.

### Step 0: Discover Project Validation & Guard Against Concurrent Runs

**Discover validation commands** by checking the project root (in priority order):
1. `CLAUDE.md` — look for a `## Validation` or `## Quality Gates` section with explicit commands
2. `.claude/rules/` — check for testing/validation rules
3. `Makefile` — look for `lint`, `test`, `check` targets
4. `pyproject.toml` — if exists, assume `uv run ruff check . && uv run pytest`
5. `package.json` — check `scripts.lint`, `scripts.test`
6. `Cargo.toml` — assume `cargo clippy && cargo test`

Store the discovered command as `VALIDATE_CMD` for use throughout this run.

**Guard against concurrent runs.** Use a heartbeat-based lock file (not `pgrep`) because `/ralph-run` is a Claude Code slash command — each `Bash()` tool call spawns an ephemeral shell, so there's no persistent PID to track.

The lock file contains an epoch timestamp that acts as a heartbeat. The monitoring loop (Step 4) writes a fresh timestamp every iteration (~60s), so a recent value means an active orchestrator. A stale value (>3 min) means a crashed session.

```bash
REPO_NAME=$(basename "$(git rev-parse --show-toplevel)")
LOCKFILE="/tmp/ralph-run-${REPO_NAME}.lock"
STALE_SECONDS=180  # 3 minutes — monitoring loop runs every 60s

if [ -f "$LOCKFILE" ]; then
    lock_time=$(cat "$LOCKFILE")
    file_age=$(( $(date +%s) - lock_time ))
    if [ "$file_age" -lt "$STALE_SECONDS" ]; then
        echo "Error: Another /ralph-run instance is active (lock updated ${file_age}s ago). Wait for it to complete."
        exit 1
    fi
    echo "Removing stale lock (last updated ${file_age}s ago, likely crashed)"
fi

# Acquire lock
date +%s > "$LOCKFILE"

Important: The orchestrator must refresh the heartbeat during monitoring. In Step 4's polling loop, run date +%s > /tmp/ralph-run-${REPO_NAME}.lock alongside each status check. When all work is done (Step 6), remove the lock:

rm -f /tmp/ralph-run-${REPO_NAME}.lock

Then remove any stale Dolt lock files left by crashed workers from previous runs:

rm -f .beads/dolt-access.lock .beads/dolt/beads/.dolt/noms/LOCK

This is safe — the heartbeat lock above guarantees only one orchestrator is running, and only the orchestrator calls bd. If a Dolt lock file exists at startup, it's always stale from a previous crash.

Step 1: Find Ready Beads

Run bd ready to see available work. If --bead <id> was provided, use that specific bead.

If multiple beads are ready and independent (no dependency between them), spawn them in parallel (up to 3 at a time). If beads have dependencies, respect the ordering.

Step 2: Create Worktree (parallel mode only)

Skip this step for --once or --bead — run those in-place (no collision risk with a single worker).

For each bead that will run in parallel:

  1. Capture the current HEAD as this worker's base ref (for commit detection in Step 4). This must be done per-worker, not once at startup, because HEAD advances after each merge in Step 5:
BASE_REF_<bead-id>=$(git rev-parse HEAD)
  1. Create an isolated worktree using bd worktree create:
bd worktree create work-<bead-id> --branch work/<bead-id>

This creates ./work-<bead-id>/ with a .beads/redirect so the worktree shares the main beads database.

  1. Copy env files from CWD into the worktree. Discover which env files exist by:
    1. Reading .claude/rules/git-workflow.md for env file patterns (look for .gitignore entries or env file lists)
    2. Falling back to common defaults: .env, .env.local, .env.development.local
# Discover env files: check rules first, then fall back to defaults
ENV_FILES=""
if [ -f ".claude/rules/git-workflow.md" ]; then
    # Extract env file patterns from git workflow rules
    ENV_FILES=$(grep -oE '\.[eE]nv[a-zA-Z._-]*' .claude/rules/git-workflow.md | sort -u)
fi
if [ -z "$ENV_FILES" ]; then
    ENV_FILES=".env .env.local .env.development.local"
fi

for f in $ENV_FILES; do
    [ -f "$f" ] && cp "$f" "./work-<bead-id>/$f"
done
  1. Install dependencies in the worktree. Use whatever the project uses:
cd work-<bead-id> && <dependency-install-cmd> && cd ..

Common dependency install commands: uv sync, npm install, pnpm install, cargo build, bundle install.

  1. Record the worktree path for this bead — the worker will run from there.

If worktree creation fails (e.g., branch already exists from a previous run):

  • Try bd worktree remove work-<bead-id> && git branch -D work/<bead-id> first, then retry creation once
  • If still failing after one retry, skip this bead and report it as failed
  • Do NOT fall back to in-place execution during parallel mode — an in-place worker would commit directly to the current branch while worktree workers commit to work/<bead-id> branches, creating conflicting histories that the merge step cannot handle

Step 3: For Each Bead, Spawn a Worker Subagent

For each ready bead:

  1. Validate the bead ID and mark it in-progress (foreground — runs synchronously to avoid Dolt lock contention):
# Validate bead-id format BEFORE marking in-progress (avoids stuck beads on invalid IDs)
bead_id="<bead-id>"
if ! [[ "$bead_id" =~ ^[a-zA-Z0-9._-]+$ ]]; then
  echo "ERROR: Invalid bead-id format: $bead_id"
  exit 

Maintain Ralph Run?

Let people know it's listed here — add the badge (live metrics, light/dark aware) or a plain link to your README or docs.

[Ralph Run on getagentictools](https://getagentictools.com/loops/rbriski-ralph-run-execute-beads-with-fresh-context?ref=badge)
npx agentictools info loops/rbriski-ralph-run-execute-beads-with-fresh-context

The second line is the CLI lookup for this page — handy in READMEs and docs.