Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
807e5e4
feat: add Docker containerization and parallel multi-agent execution
mtgibbs Feb 13, 2026
75e9a1d
fix: volume-based auth, --project flag, and smoke test fixes
mtgibbs Feb 13, 2026
0c4418b
feat: add --image flag for custom Docker images
mtgibbs Feb 13, 2026
cee3b3d
fix: claim_story stdout pollution and set -e crash on retry
mtgibbs Feb 13, 2026
f7f879d
fix: add jsr.io and deno.land to builder firewall whitelist
mtgibbs Feb 13, 2026
b36bef3
security: fix token exposure, hardcoded platform, and firewall generi…
mtgibbs Feb 13, 2026
538c478
fix: handle new branch push and pull in agent-loop
mtgibbs Feb 13, 2026
2c82c08
feat: auto-detect Dockerfile.ralph in project directory
mtgibbs Feb 13, 2026
991e2b9
fix: address PR review feedback
mtgibbs Feb 13, 2026
bd54904
Fix double-claiming: script claims story, injects ID into prompt
mtgibbs Feb 14, 2026
d651eff
fix: prevent story hoarding and release claims on auth failure
mtgibbs Feb 17, 2026
904afc1
feat: verifier agents and docker labels for container tracking
mtgibbs Feb 17, 2026
b3dcc25
fix: complete fetch-before-verify and clean dirty trees between itera…
mtgibbs Feb 20, 2026
be73a93
fix: exponential backoff and max retry limit for auth failures
mtgibbs Feb 20, 2026
21abddb
fix: force-push bare repo sync and clean stale branches on launch
mtgibbs Feb 20, 2026
82e8165
Merge pull request #1 from mtgibbs/fix/retro-agent-bugs
mtgibbs Feb 20, 2026
cd0fecd
feat: configurable git author identities via .ralph/friends.json
mtgibbs Feb 21, 2026
06c578a
feat: story dependencies via dependsOn field for parallel execution c…
mtgibbs Feb 21, 2026
fb037c6
feat: halt orchestrator on agent auth failure (exit code 2)
mtgibbs Feb 21, 2026
28566bc
fix: use extended regex for bare repo branch cleanup on macOS
mtgibbs Feb 21, 2026
54c8402
feat: evolve PRD format toward PRP standard with enriched context
mtgibbs Feb 25, 2026
cc4c98b
feat: add multi-PRP mode for parallel independent feature branches
mtgibbs Feb 26, 2026
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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ progress.txt

#Claude
.claude/

# Parallel mode state
.ralph/
agent_logs/
progress-agent-*.txt
29 changes: 29 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,32 @@ npm run dev
- Memory persists via git history, `progress.txt`, and `prd.json`
- Stories should be small enough to complete in one context window
- Always update AGENTS.md with discovered patterns for future iterations

## Parallel Mode

Ralph supports running multiple agents in parallel via Docker containers. See `parallel/README.md` for details.

- Parallel scripts live in `parallel/` — orchestrator, status, stop
- Docker image and container entrypoint live in `docker/`
- Agents claim stories via `claimed_by` field in prd.json using git atomic push
- Each agent writes to its own `progress-<agent-id>.txt` to avoid merge conflicts
- Builder agents have restricted network access (Claude API + npm only)
- Researcher agents have full internet access

### Multi-PRP Mode

`launch-multi-prp.sh` runs independent feature branches simultaneously (1 agent per PRP):

- Each PRP file specifies its own `branchName`; the orchestrator pre-creates branches
- `RALPH_BRANCH` env var tells each agent which branch to check out
- No story contention — each agent has its own story pool
- On completion, branches are fetched back and `gh pr create` commands are printed
- Use `--prp FILE` (repeatable) to specify which PRPs to run

### Lessons Learned

- **macOS bash 3.x**: Don't use `declare -A` (associative arrays). Use indexed parallel arrays.
- **Agent containers are independent**: The monitor loop crashing doesn't affect running agents.
- **Foundation stories take longer**: Types + API client stories are slower than incremental tool stories.
- **Token expiry planning**: All agents share one OAuth token. If it expires mid-run, agents that haven't finished enter a retry loop. Plan token validity for the full session.
- **PRP independence**: When two PRPs need the same helper, inline it in both as separate stories with "skip if already exists" guidance.
40 changes: 31 additions & 9 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,36 @@ You are an autonomous coding agent working on a software project.

## Your Task

1. Read the PRD at `prd.json` (in the same directory as this file)
1. Read the spec file: check for `prp.json` first, fall back to `prd.json` (in the same directory as this file)
2. Read the progress log at `progress.txt` (check Codebase Patterns section first)
3. Check you're on the correct branch from PRD `branchName`. If not, check it out or create from main.
4. Pick the **highest priority** user story where `passes: false`
5. Implement that single user story
6. Run quality checks (e.g., typecheck, lint, test - use whatever your project requires)
7. Update CLAUDE.md files if you discover reusable patterns (see below)
8. If checks pass, commit ALL changes with message: `feat: [Story ID] - [Story Title]`
9. Update the PRD to set `passes: true` for the completed story
10. Append your progress to `progress.txt`
3. Check you're on the correct branch from the spec's `branchName`. If not, check it out or create from main.
4. If the spec has a `previousVersion` field (non-null), read the prior version for context on what's already built
5. Pick the **highest priority** user story where `passes: false` and all `dependsOn` story IDs (if any) have `passes: true`
6. Before implementing, read the story's `context` block if present (see PRP Context below)
7. Implement that single user story
8. Run quality checks — if the story has `verificationCommands`, run those; otherwise use project defaults (typecheck, lint, test)
9. Update CLAUDE.md files if you discover reusable patterns (see below)
10. If checks pass, commit ALL changes with message: `feat: [Story ID] - [Story Title]`
11. Update the spec to set `passes: true` for the completed story
12. Append your progress to `progress.txt`

## PRP Context

The spec file may contain enriched fields that help you work more effectively. Check for and use these if present:

### Project-Level Fields
- **`constraints`**: Architectural decisions you MUST follow (e.g., "Use drizzle ORM", "Use server actions for mutations"). Treat these as hard requirements — do not deviate.
- **`nonGoals`**: Explicit scope boundaries. Before completing a story, verify your implementation doesn't accidentally build something listed as a non-goal.
- **`glossary`**: Domain term definitions. Use these when you encounter unfamiliar terms in the spec.

### Story-Level Fields
- **`context.relevantFiles`**: Read these files before starting implementation — they contain the code you'll be modifying or the patterns you should follow.
- **`context.hints`**: Implementation guidance — what to reuse, what approach to take.
- **`context.examples`**: Code snippets showing patterns your new code should match.
- **`verificationCommands`**: Specific shell commands to validate your work. Run these instead of (or in addition to) generic quality checks.

### Version Context
- **`previousVersion`**: If non-null, points to an archived prior version of this spec. Read it to understand what's already been built — stories with `passes: true` carried over from the previous version are already implemented.

## Progress Report Format

Expand Down Expand Up @@ -73,9 +93,11 @@ Only update CLAUDE.md if you have **genuinely reusable knowledge** that would he
## Quality Requirements

- ALL commits must pass your project's quality checks (typecheck, lint, test)
- If the story has `verificationCommands`, run those as part of your quality checks
- Do NOT commit broken code
- Keep changes focused and minimal
- Follow existing code patterns
- If `constraints` exist in the spec, verify your implementation follows them

## Browser Testing (If Available)

Expand Down
106 changes: 106 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ Ralph will:
| `skills/ralph/` | Skill for converting PRDs to JSON (works with Amp and Claude Code) |
| `.claude-plugin/` | Plugin manifest for Claude Code marketplace discovery |
| `flowchart/` | Interactive visualization of how Ralph works |
| `docker/` | Dockerfile and container scripts for parallel mode |
| `parallel/` | Parallel mode orchestrator, status, and stop scripts |

## Flowchart

Expand Down Expand Up @@ -232,6 +234,110 @@ After copying `prompt.md` (for Amp) or `CLAUDE.md` (for Claude Code) to your pro

Ralph automatically archives previous runs when you start a new feature (different `branchName`). Archives are saved to `archive/YYYY-MM-DD-feature-name/`.

## Parallel Mode (Docker)

Ralph includes a parallel mode that runs N containerized Claude Code agents simultaneously against the same PRD. Each agent runs in a Docker container with:

- **Network restrictions** — builder agents can only reach Claude API and npm registry
- **Resource limits** — configurable memory and CPU caps per container
- **Story claiming** — agents claim stories via git atomic push to avoid duplicate work
- **Automatic recovery** — stale claims are cleared, crashed containers are restarted

### Prerequisites (Parallel Mode)

- Docker installed and running
- A Claude Code auth token (env var, file, or 1Password)
- `jq` installed

### Quick Start (Parallel Mode)

```bash
# Set your Claude auth token
export RALPH_CLAUDE_TOKEN='<your-token>'

# Run 3 agents in parallel
./parallel/ralph-parallel.sh --agents 3

# Check status
./parallel/status.sh

# Graceful shutdown
./parallel/stop.sh
```

### Options

```bash
./parallel/ralph-parallel.sh \
--agents 3 \ # number of builder agents (default: 2)
--model claude-sonnet-4-5-20250929 \ # model (default: sonnet)
--memory 4g \ # per-container memory limit
--cpus 2 \ # per-container CPU limit
--researcher 1 \ # researcher agents with full internet access
[max_iterations] # per-agent iteration cap (default: 0 = until PRD complete)
```

### Auth Token

Priority order (first wins):
1. `RALPH_CLAUDE_TOKEN` environment variable
2. `.ralph/token` file in the project directory
3. 1Password via `op read` (interactive, startup only)

See [parallel/README.md](parallel/README.md) for full documentation.

## Multi-PRP Mode (Docker)

Multi-PRP mode extends parallel mode for running **independent feature branches simultaneously**. Instead of N agents competing for stories on one PRD, each PRP file gets its own feature branch and dedicated agent. This is ideal for batching multiple independent features in a single launch.

### How It Works

1. You provide multiple PRP JSON files, each with its own `branchName`
2. The orchestrator pre-creates a feature branch per PRP in the bare repo
3. One container launches per PRP, targeted to its branch via `RALPH_BRANCH`
4. Agents work independently — no competition, no cross-branch coordination
5. On completion, branches are fetched back and PR creation commands are printed

### Quick Start (Multi-PRP)

```bash
# Launch 6 agents, one per PRP file
./parallel/launch-multi-prp.sh \
--project /path/to/my-repo \
--prp prps/prp-03.json \
--prp prps/prp-04.json \
--prp prps/prp-05.json \
--prp prps/prp-06.json \
--prp prps/prp-07.json \
--model claude-sonnet-4-5-20250929
```

### Options (Multi-PRP)

```bash
./parallel/launch-multi-prp.sh \
--project DIR \ # project git repo (required)
--prp FILE \ # PRP JSON file, relative to project (repeatable, required)
--model MODEL \ # Claude model (default: claude-sonnet-4-5-20250929)
--memory SIZE \ # per-container memory (default: 4g)
--cpus N \ # per-container CPUs (default: 2)
--max-iterations N \ # per-agent iteration cap (default: 0 = until done)
--allow-domain DOMAIN # extra firewall whitelist (repeatable)
```

### Single-PRP vs Multi-PRP

| | `ralph-parallel.sh` | `launch-multi-prp.sh` |
|---|---|---|
| Branches | One shared branch | One branch per PRP |
| Agents | N agents compete for stories | 1 agent per PRP, no competition |
| Use case | Parallelize within a feature | Parallelize across features |
| Story claiming | Git atomic push (contention possible) | No contention (isolated branches) |
| Completion | All stories done → exit | All branches done → exit |
| Output | Stories marked `passes: true` | Branches synced + PR commands printed |

See [parallel/README.md](parallel/README.md) for full documentation.

## References

- [Geoffrey Huntley's Ralph article](https://ghuntley.com/ralph/)
Expand Down
41 changes: 41 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
FROM node:20-slim

# System deps for networking, git, and general tooling
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
iptables \
ipset \
iproute2 \
dnsutils \
jq \
curl \
sudo \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*

# Install claude-code globally
RUN npm install -g @anthropic-ai/claude-code

# Create non-root agent user (UID 1001 since node:20-slim uses 1000 for 'node')
RUN useradd -m -s /bin/bash -u 1001 agent

# Allow agent to run firewall init scripts via sudo (no password)
RUN echo "agent ALL=(root) NOPASSWD:SETENV: /opt/ralph/init-firewall-builder.sh, /opt/ralph/init-firewall-researcher.sh" \
> /etc/sudoers.d/agent-firewall && chmod 0440 /etc/sudoers.d/agent-firewall

# Copy scripts
COPY agent-loop.sh /opt/ralph/agent-loop.sh
COPY init-firewall-builder.sh /opt/ralph/init-firewall-builder.sh
COPY init-firewall-researcher.sh /opt/ralph/init-firewall-researcher.sh
RUN chmod +x /opt/ralph/agent-loop.sh /opt/ralph/init-firewall-builder.sh /opt/ralph/init-firewall-researcher.sh

# Workspace for cloned repo
RUN mkdir -p /workspace && chown agent:agent /workspace

# Claude config directory
RUN mkdir -p /home/agent/.claude && chown agent:agent /home/agent/.claude

USER agent
WORKDIR /workspace

ENTRYPOINT ["/opt/ralph/agent-loop.sh"]
Loading