Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ _bmad-output/

# Node modules (if any future dependencies)
node_modules/

# Codex generated files
.codex/
96 changes: 84 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

> **Automate your BMAD development workflow with Claude Code CLI or OpenAI Codex CLI**

BMAD Ralph Loop is a CLI automation tool that orchestrates development cycles using Claude Code CLI or OpenAI Codex CLI and the BMAD Method agents. It manages the complete story lifecycle: from story creation by the Scrum Master agent, through implementation by the Developer agent, to code review — all running autonomously.
BMAD Ralph Loop is a CLI automation tool that orchestrates development cycles using Claude Code CLI or OpenAI Codex CLI and the BMAD Method agents. It manages the complete story lifecycle: from story creation by the Scrum Master agent, through implementation by the Developer agent, to code review and follow-up rework until the story is clean — all running autonomously.

![Demo](docs/assets/demo.gif)
*Demo placeholder - Record your own workflow!*
Expand All @@ -16,15 +16,17 @@ BMAD Ralph Loop is a CLI automation tool that orchestrates development cycles us

## Features

- **Autonomous Development Loop** — Runs the full cycle: create-story → dev-story → code-review
- **Autonomous Development Loop** — Runs the full cycle: create-story → dev-story → code-review, looping review feedback back into dev-story until clean
- **BMAD Method Integration** — Built for the BMAD (BMad Agile Development) methodology
- **Multi-Agent Orchestration** — Coordinates SM (Scrum Master) and DEV (Developer) agents
- **Sprint Status Tracking** — YAML-based status management with automatic updates
- **Intelligent Story Processing** — Handles backlog, ready-for-dev, review, and done states
- **Epic Management** — Automatic epic completion detection and retrospectives
- **Intelligent Story Processing** — Handles backlog, ready-for-dev, review, and done states, including review-to-dev retries
- **Epic Management** — Automatic epic completion detection, retrospectives, and end-of-epic branch sync
- **Parallel Story Workers** — Optional worktree-based parallel execution with dependency-aware scheduling
- **Dry-Run Mode** — Preview all actions before execution
- **Selective Processing** — Target specific epics or individual stories
- **Auto-Commit** — Commits changes with proper conventional commit messages
- **Auto-Commit** — Commits each story and finalizes each completed epic with a dedicated commit
- **Log-Safe Commits** — Excludes Ralph runtime logs from Ralph-generated commits
- **Verbose Logging** — Detailed logs for debugging and audit trails

---
Expand Down Expand Up @@ -55,7 +57,7 @@ codex-ralph-loop
- **Claude Code CLI** — [Install from claude.ai](https://claude.ai)
- **OpenAI Codex CLI** — [Install from OpenAI docs](https://developers.openai.com/codex/cli)
- **yq** — YAML processor
- **Bash 4+** — Modern bash shell
- **Bash 4+** — Modern bash shell (`Bash 4.3+` required for parallel mode)

Install at least one provider CLI (Claude or Codex).

Expand All @@ -80,10 +82,16 @@ chmod +x claude-ralph-loop/claude-ralph-loop.sh claude-ralph-loop/codex-ralph-lo
sudo cp claude-ralph-loop/ralph-loop-core.sh /usr/local/bin/ralph-loop-core.sh
sudo cp claude-ralph-loop/claude-ralph-loop.sh /usr/local/bin/claude-ralph-loop
sudo cp claude-ralph-loop/codex-ralph-loop.sh /usr/local/bin/codex-ralph-loop
sudo rm -rf /usr/local/bin/ralph-loop-lib
sudo mkdir -p /usr/local/bin/ralph-loop-lib
sudo cp claude-ralph-loop/lib/*.sh /usr/local/bin/ralph-loop-lib/
# OR (user-only)
cp claude-ralph-loop/ralph-loop-core.sh ~/bin/ralph-loop-core.sh
cp claude-ralph-loop/claude-ralph-loop.sh ~/bin/claude-ralph-loop
cp claude-ralph-loop/codex-ralph-loop.sh ~/bin/codex-ralph-loop
rm -rf ~/bin/ralph-loop-lib
mkdir -p ~/bin/ralph-loop-lib
cp claude-ralph-loop/lib/*.sh ~/bin/ralph-loop-lib/
```

### Install Dependencies
Expand Down Expand Up @@ -114,6 +122,8 @@ codex-ralph-loop [OPTIONS]
| Flag | Description |
|------|-------------|
| `--dry-run` | Preview actions without executing |
| `--yes`, `-y` | Skip the `Proceed with implementation?` confirmation prompt |
| `--bell` | Ring the terminal bell when the controller exits |
| `--epic N` | Process only stories from epic N |
| `--story X-Y` | Process a specific story (e.g., `1-2`) |
| `--skip-review` | Skip the code-review step |
Expand All @@ -130,6 +140,12 @@ claude-ralph-loop
# Preview what would happen
claude-ralph-loop --dry-run

# Run without the confirmation prompt
claude-ralph-loop --yes

# Ring the terminal bell when Ralph finishes
claude-ralph-loop --bell

# Process only Epic 2 stories
claude-ralph-loop --epic 2

Expand All @@ -144,6 +160,9 @@ claude-ralph-loop --verbose

# Use Codex instead of Claude
codex-ralph-loop

# Run multiple ready stories in parallel
RALPH_CONCURRENCY=3 codex-ralph-loop
```

### Choose Your CLI
Expand Down Expand Up @@ -171,8 +190,23 @@ your-project/
|----------|---------|-------------|
| `RALPH_PROJECT_ROOT` | Auto-detected | Project root directory |
| `RALPH_SPRINT_STATUS` | `_bmad-output/implementation-artifacts/sprint-status.yaml` | Path to sprint status |
| `RALPH_LOG_DIR` | `scripts/logs` | Directory for log files |
| `RALPH_LOG_DIR` | `logs/` | Directory for log files |
| `RALPH_SKIP_RETRO` | `false` | Skip retrospective prompt when epics complete |
| `RALPH_AUTO_RETROSPECTIVE` | `true` | Run retrospectives automatically when an epic completes |
| `RALPH_MAX_REVIEW_PASSES` | `5` | Maximum review/dev loops before Ralph aborts a story |
| `RALPH_PROMPT_ON_FAILURE` | `false` | Ask before continuing after failures |
| `RALPH_AUTO_PUSH_EPIC` | `true` | Push the current branch when an epic completes |
| `RALPH_EPIC_PUSH_REMOTE` | Current upstream | Override the remote used for automatic epic pushes |
| `RALPH_CONCURRENCY` | `1` | Number of stories to process in parallel |
| `RALPH_RUNTIME_ROOT` | `../.ralph-runtime/<repo>` | Shared runtime root for parallel worker state |
| `RALPH_WORKTREE_ROOT` | `$RALPH_RUNTIME_ROOT/worktrees` | Parallel worker git worktrees |
| `RALPH_RESULT_ROOT` | `$RALPH_RUNTIME_ROOT/results` | Parallel worker result and console logs |
| `RALPH_KEEP_WORKTREES_ON_SUCCESS` | `false` | Keep successful worker worktrees for inspection |
| `RALPH_KEEP_WORKTREES_ON_FAILURE` | `true` | Keep failed worker worktrees for debugging |
| `RALPH_WORKFLOW_IDLE_TIMEOUT` | `7200` | Fail a provider workflow after this many idle seconds with no new output |
| `RALPH_WORKER_IDLE_TIMEOUT` | `10800` | Fail a parallel worker after this many idle seconds with no new output |
| `RALPH_CONTROL_FILE` | `$RALPH_RUNTIME_ROOT/control` | Runtime control file for `pause`, `resume`, `drain`, or `stop` |
| `RALPH_NOTIFY_BELL` | `false` | Ring the terminal bell when the controller exits |

### Sprint Status Format

Expand All @@ -194,6 +228,39 @@ development_status:

See [examples/sprint-status.example.yaml](examples/sprint-status.example.yaml) for a complete example.

### Parallel Mode

Set `RALPH_CONCURRENCY` above `1` to enable worktree-based parallel execution. Ralph keeps the main repo as the controller, launches one worker branch/worktree per runnable story, merges completed worker commits back serially, and only finalizes epics on the controller branch.

Parallel mode has a few safety rules:
- The authoritative project worktree must be clean except for Ralph log files.
- `RALPH_WORKTREE_ROOT` and `RALPH_RESULT_ROOT` must stay outside the project repository.
- Absolute `story_location` values must point inside the project repo; Ralph remaps them into each worker worktree automatically.
- Story dependencies in `sprint-status.yaml` must be `done` before a dependent story will launch.
- Failed worker integrations keep the worker worktree for inspection and leave the authoritative story status unchanged.
- Stale provider workflows and parallel workers are failed automatically once their idle timeout expires, so a wedged CLI does not block the entire run forever.
- When a story is retried, Ralph attaches the latest kept worktree for that story under `.ralph/previous-attempt/` inside the new worker so the agent can salvage useful prior work.
- The wrapper scripts run from a per-run snapshot of `ralph-loop-core.sh`, so editing the repo copy while Ralph is active will not corrupt the live run.
- Ralph prints both the controller PID and control-file path at startup. You can send `TERM` to the controller PID for a graceful drain, or write commands to the control file while the run is active.

### Runtime Control File

Ralph polls `RALPH_CONTROL_FILE` while it is running. Update the file with one of these commands:

```bash
echo pause > /path/to/control
echo resume > /path/to/control
echo drain > /path/to/control
echo stop > /path/to/control
```

- `pause`: stop launching new stories, but let already-running work continue
- `resume`: start launching eligible stories again
- `drain`: stop launching new stories and exit after active work finishes
- `stop`: terminate active work and exit without integrating unfinished stories

Ralph ignores stale control-file contents from before the current run. You must rewrite the file during the active run for a command to take effect.

---

## How It Works
Expand Down Expand Up @@ -232,13 +299,18 @@ See [examples/sprint-status.example.yaml](examples/sprint-status.example.yaml) f

3. **Code Review (DEV Agent)**
- Reviews implementation against story requirements
- Auto-fixes issues found
- Updates status: `review` → `done`
- Can make fixes or request another dev pass
- Updates status: `review` → `ready-for-dev` when follow-up work is needed, otherwise `review` → `done`

4. **Auto-Commit**
- Commits all changes with conventional commit format
- Message: `feat(epic-N): implement X-Y`

5. **Epic Finalization**
- Marks the epic complete when all stories are done
- Runs the retrospective automatically by default
- Creates a final epic completion commit and pushes the branch

---

## BMAD Method Integration
Expand All @@ -258,7 +330,7 @@ BMAD Method Workflow:
└── Build Cycle (repeated for each story):
├── create-story (SM Agent)
├── dev-story (DEV Agent)
└── code-review (DEV Agent)
└── code-review (DEV Agent, loops back to dev-story until clean)
```

### The Build Cycle
Expand All @@ -269,9 +341,9 @@ In the BMAD Method, each story goes through this cycle:
|------|-------|----------|---------|
| 1 | SM | `create-story` | Create story file from epic |
| 2 | DEV | `dev-story` | Implement the story |
| 3 | DEV | `code-review` | Quality validation |
| 3 | DEV | `code-review` | Quality validation and dev-loop feedback |

**BMAD Ralph Loop automates this entire cycle**, running each workflow autonomously in sequence for every pending story.
**BMAD Ralph Loop automates this entire cycle**, running each workflow autonomously for every pending story until review is clean.

### Prerequisites

Expand Down
29 changes: 28 additions & 1 deletion claude-ralph-loop.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,42 @@ fi

SCRIPT_DIR="$(cd "$(dirname "$SOURCE_PATH")" && pwd)"
CORE_PATH="$SCRIPT_DIR/ralph-loop-core.sh"
if [[ -z "${RALPH_LIB_DIR:-}" ]]; then
if [[ -d "$SCRIPT_DIR/ralph-loop-lib" ]]; then
export RALPH_LIB_DIR="$SCRIPT_DIR/ralph-loop-lib"
else
export RALPH_LIB_DIR="$SCRIPT_DIR/lib"
fi
else
export RALPH_LIB_DIR
fi
SNAPSHOT_PARENT="${RALPH_SCRIPT_SNAPSHOT_ROOT:-${TMPDIR:-/tmp}}"
SNAPSHOT_DIR=""
SNAPSHOT_CORE=""

export PROVIDER="claude"

cleanup_script_snapshot() {
if [[ -n "$SNAPSHOT_DIR" && -d "$SNAPSHOT_DIR" ]]; then
rm -rf "$SNAPSHOT_DIR"
fi
}

if [[ ! -f "$CORE_PATH" ]]; then
echo "Error: ralph-loop-core.sh not found in $SCRIPT_DIR" >&2
exit 1
fi

mkdir -p "$SNAPSHOT_PARENT"
SNAPSHOT_DIR="$(mktemp -d "$SNAPSHOT_PARENT/ralph-script-snapshot.XXXXXX")"
chmod 700 "$SNAPSHOT_DIR"
trap cleanup_script_snapshot EXIT

SNAPSHOT_CORE="$SNAPSHOT_DIR/ralph-loop-core.sh"
cp "$CORE_PATH" "$SNAPSHOT_CORE"
chmod +x "$SNAPSHOT_CORE"

# shellcheck source=ralph-loop-core.sh
source "$CORE_PATH"
source "$SNAPSHOT_CORE"

main "$@"
29 changes: 28 additions & 1 deletion codex-ralph-loop.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,42 @@ fi

SCRIPT_DIR="$(cd "$(dirname "$SOURCE_PATH")" && pwd)"
CORE_PATH="$SCRIPT_DIR/ralph-loop-core.sh"
if [[ -z "${RALPH_LIB_DIR:-}" ]]; then
if [[ -d "$SCRIPT_DIR/ralph-loop-lib" ]]; then
export RALPH_LIB_DIR="$SCRIPT_DIR/ralph-loop-lib"
else
export RALPH_LIB_DIR="$SCRIPT_DIR/lib"
fi
else
export RALPH_LIB_DIR
fi
SNAPSHOT_PARENT="${RALPH_SCRIPT_SNAPSHOT_ROOT:-${TMPDIR:-/tmp}}"
SNAPSHOT_DIR=""
SNAPSHOT_CORE=""

export PROVIDER="codex"

cleanup_script_snapshot() {
if [[ -n "$SNAPSHOT_DIR" && -d "$SNAPSHOT_DIR" ]]; then
rm -rf "$SNAPSHOT_DIR"
fi
}

if [[ ! -f "$CORE_PATH" ]]; then
echo "Error: ralph-loop-core.sh not found in $SCRIPT_DIR" >&2
exit 1
fi

mkdir -p "$SNAPSHOT_PARENT"
SNAPSHOT_DIR="$(mktemp -d "$SNAPSHOT_PARENT/ralph-script-snapshot.XXXXXX")"
chmod 700 "$SNAPSHOT_DIR"
trap cleanup_script_snapshot EXIT

SNAPSHOT_CORE="$SNAPSHOT_DIR/ralph-loop-core.sh"
cp "$CORE_PATH" "$SNAPSHOT_CORE"
chmod +x "$SNAPSHOT_CORE"

# shellcheck source=ralph-loop-core.sh
source "$CORE_PATH"
source "$SNAPSHOT_CORE"

main "$@"
68 changes: 62 additions & 6 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ development_status:
|--------|-------------|--------------|
| `backlog` | Story not started | Runs `create-story` workflow |
| `ready-for-dev` | Story file exists | Runs `dev-story` workflow |
| `review` | Implementation done | Runs `code-review` workflow |
| `review` | Implementation done | Runs `code-review`; loops to `ready-for-dev` if follow-up work is needed |
| `done` | Story completed | Skipped |
| `blocked` | Story blocked | Skipped |
| `in-progress` | For epics only | Shows epic is active |
Expand Down Expand Up @@ -99,6 +99,21 @@ retrospectives:
| `RALPH_SPRINT_STATUS` | `_bmad-output/implementation-artifacts/sprint-status.yaml` | Sprint status file path |
| `RALPH_LOG_DIR` | `logs/` | Directory for log files |
| `RALPH_SKIP_RETRO` | `false` | Skip retrospective prompt when epics complete |
| `RALPH_AUTO_RETROSPECTIVE` | `true` | Automatically run retrospective when an epic completes |
| `RALPH_MAX_REVIEW_PASSES` | `5` | Maximum `dev-story`/`code-review` loops before aborting |
| `RALPH_PROMPT_ON_FAILURE` | `false` | Prompt before continuing after a story or epic failure |
| `RALPH_AUTO_PUSH_EPIC` | `true` | Push the current branch when an epic completes |
| `RALPH_EPIC_PUSH_REMOTE` | *(empty)* | Remote override for automatic epic pushes; defaults to current upstream |
| `RALPH_CONCURRENCY` | `1` | Number of stories Ralph can process at once |
| `RALPH_RUNTIME_ROOT` | `../.ralph-runtime/<repo>` | Shared runtime root for parallel worker state |
| `RALPH_WORKTREE_ROOT` | `$RALPH_RUNTIME_ROOT/worktrees` | Git worktree location for parallel story workers |
| `RALPH_RESULT_ROOT` | `$RALPH_RUNTIME_ROOT/results` | Worker result files, logs, and console captures |
| `RALPH_KEEP_WORKTREES_ON_SUCCESS` | `false` | Keep successful worker worktrees instead of deleting them |
| `RALPH_KEEP_WORKTREES_ON_FAILURE` | `true` | Keep failed worker worktrees for debugging |
| `RALPH_WORKFLOW_IDLE_TIMEOUT` | `7200` | Fail a provider workflow after this many idle seconds without new output |
| `RALPH_WORKER_IDLE_TIMEOUT` | `10800` | Fail a parallel worker after this many idle seconds without new output |
| `RALPH_CONTROL_FILE` | `$RALPH_RUNTIME_ROOT/control` | Runtime control file for `pause`, `resume`, `drain`, or `stop` |
| `RALPH_NOTIFY_BELL` | `false` | Ring the terminal bell when the controller exits |
| `RALPH_CODEX_FULL_AUTO` | `true` | Use `--full-auto` with Codex exec |
| `RALPH_CODEX_SANDBOX` | *(empty)* | Codex sandbox mode (e.g., `danger-full-access`) |
| `RALPH_CODEX_MODEL` | *(empty)* | Codex model override |
Expand Down Expand Up @@ -199,7 +214,8 @@ claude-ralph-loop --skip-review
The default workflow order is:
1. `create-story` (backlog → ready-for-dev)
2. `dev-story` (ready-for-dev → review)
3. `code-review` (review → done)
3. `code-review` (review → ready-for-dev for another dev pass, or review → done when clean)
4. Epic finalization (done stories → retrospective → epic completion commit → push)

To change this, modify the `process_story()` function in the script.

Expand All @@ -217,10 +233,50 @@ To use custom agents:

### Parallel Processing

Currently, stories are processed sequentially. For parallel processing, you would need to:
1. Fork the script
2. Modify the main loop to use background processes
3. Handle concurrent YAML updates carefully
Set `RALPH_CONCURRENCY` to a value greater than `1` to enable Ralph's worktree-based parallel mode.

How it works:
1. The main Ralph process stays in the authoritative repo and owns the real `sprint-status.yaml`.
2. Each runnable story gets its own git branch and git worktree under `RALPH_WORKTREE_ROOT`.
3. Each worker runs Ralph in single-story mode against a copied sprint status file.
4. The controller waits for workers to finish, then cherry-picks successful worker commits back one at a time.
5. Only after integration succeeds does the controller update the authoritative story status and check for epic completion.

Parallel mode rules:
- The main project worktree must be clean except for Ralph `ralph-*.log` files.
- `RALPH_WORKTREE_ROOT` and `RALPH_RESULT_ROOT` must live outside the project repository.
- Absolute `story_location` values are supported only when they point inside the project repository; Ralph remaps them into each worker worktree.
- Stories listed in `dependencies:` will not launch until every dependency is `done`.
- Parallel mode requires `Bash 4.3+`.
- If a worker commit fails to integrate, Ralph leaves the authoritative story status unchanged and keeps the worker worktree for manual inspection.
- If a provider workflow or parallel worker stops producing output long enough to exceed its idle timeout, Ralph terminates it and records the story as failed instead of waiting forever.
- When a story is retried, Ralph copies reference material from the latest kept worktree for that story into `.ralph/previous-attempt/` inside the new worker worktree.
- The wrapper scripts source an immutable per-run snapshot of `ralph-loop-core.sh`, so editing the repo copy during an active run does not change the live controller or workers.
- Ralph prints both the controller PID and the runtime control-file path at startup.

### Runtime Control File

Ralph polls `RALPH_CONTROL_FILE` during an active run. Write one of these commands into the file:

```bash
echo pause > /path/to/control
echo resume > /path/to/control
echo drain > /path/to/control
echo stop > /path/to/control
```

- `pause`: stop launching new stories but let active workers keep running
- `resume`: allow new eligible stories to launch again
- `drain`: graceful stop; Ralph waits for active workers to finish, then exits with remaining stories deferred
- `stop`: immediate stop; Ralph terminates active workers, keeps their worktrees for salvage, and exits with those stories deferred

Ralph ignores control-file contents that predate the current run. Rewrite the file during the run for a command to take effect.

Example:

```bash
RALPH_CONCURRENCY=3 codex-ralph-loop
```

### Custom Commit Messages

Expand Down
Loading