Ralph Run
<!-- Synced from glaude. Do not edit in project repos. --
<!-- 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
## 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:
- 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)
- 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.
- Copy env files from CWD into the worktree. Discover which env files exist by:
- Reading
.claude/rules/git-workflow.mdfor env file patterns (look for .gitignore entries or env file lists) - Falling back to common defaults:
.env,.env.local,.env.development.local
- Reading
# 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
- 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.
- 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:
- 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.