A fault-tolerant multi-agent coding pipeline.
Plan → Code → Review → Cleanup — in a loop, until your task list is done.
relay runs a four-step loop for every task in your project's prd.json:
For each task (in dependency order):
1. Plan — Claude Sonnet reasons through the task (fresh context)
2. Code — Codex implements the plan (fresh context)
3. Review — Codex adversarially reviews its own diff (fresh context)
4. Cleanup — Claude addresses findings, tests, commits (fresh context, 10m cap)
→ commit + push → save context.json → next task
You define the tasks, write the acceptance criteria, and walk away. relay handles the rest — including waiting out token limits and recovering from context rot.
Ralphy runs a single agent against a flat task list. relay adds structure at every layer:
| Ralphy | relay | |
|---|---|---|
| Agent pipeline | Single agent | Plan → Code → Review → Cleanup |
| Adversarial review | ✗ | ✓ Codex reviews Codex |
| Context-rot guard | ✗ | ✓ 10m cap, git-state handoff, fresh restart |
| Inter-task memory | ✗ | ✓ context.json — compact cross-task notes |
| Token exhaustion | Basic | Codex: exact reset time. Claude: backoff. Max 16h wait. |
| Task dependencies | ✗ | ✓ Beads graph — nothing runs before its blockers |
| Acceptance criteria | ✗ | ✓ Per-task, verified before marking done |
| Commit discipline | ✗ | ✓ Incremental + feat: complete <task> on completion |
npm install -g @beads/bd # task queue with dependency graph
apt install jq coreutils # JSON + timeout (brew install jq on macOS)
# claude CLI: https://claude.ai/code
# codex CLI: https://github.com/openai/codex# 1. Copy templates into your project
cp path/to/relay/AGENTS.md.template ./AGENTS.md
cp path/to/relay/prd.template.json ./prd.json
mkdir -p .claude
cp path/to/relay/pipeline.sh ./.claude/pipeline.sh
chmod +x .claude/pipeline.sh
# 2. Edit AGENTS.md
# - Fill in ## Project: name, stack, rules, validation targets
# - Fill in ## Tasks: one entry per task with acceptance criteria
# 3. Generate prd.json from AGENTS.md
claude -p "Read AGENTS.md ## Tasks and generate prd.json.
Schema: id (kebab-case), title, status=pending, priority (int),
depends_on (array), acceptance_criteria (array), validation.command,
artifacts={plan:null,review:null}, completed_at=null, notes=null.
Add a VALIDATE: task as a blocker for every substantive task." > prd.json
# 4. Review prd.json — make sure acceptance_criteria are specific and measurable
# 5. Commit and run
git add AGENTS.md prd.json .claude/pipeline.sh
git commit -m "chore: add relay pipeline"
bash .claude/pipeline.shbash .claude/pipeline.sh # default: 10m session cap
MAX_SESSION_MINUTES=15 bash .claude/pipeline.sh # longer cap for complex tasksLong agent sessions accumulate context and degrade in quality. relay uses three mechanisms:
1. Fresh subprocesses per step
Every step (claude -p, codex exec, codex review) is a separate subprocess.
No session persists between steps or between tasks.
2. Session cap with git-state handoff
The cleanup step (Step 4) is capped at MAX_SESSION_MINUTES (default: 10 minutes).
When the cap hits, relay captures the live git state and injects it as structured
context into a fresh session — so the new session knows exactly what was done
without relying on in-context memory.
timeout → capture git log + git status + git diff stat
→ inject into next fresh session
→ Claude continues from git ground truth
Up to MAX_RESUME_ATTEMPTS=3 restarts per task.
3. Inter-task context.json
After every completed task, relay writes .claude/context.json — a compact record
of what was done, what was committed, and a 500-char rolling summary of key decisions.
Each new task's planning step reads this file for cross-task memory without
re-opening old conversation context.
Tuning the session cap:
| Task type | Recommended MAX_SESSION_MINUTES |
|---|---|
| Formatting / simple cleanup | 5–10 |
| Normal feature + tests (default) | 10 |
| Complex refactor touching many files | 15–20 |
If a task keeps hitting the restart limit, split it into smaller prd.json entries.
relay monitors both providers for rate limit / quota errors.
Codex — parses the exact reset time from the error message:
"try again at Apr 8th, 2026 12:20 PM" → sleep until exactly then (+60s buffer)
Claude — exponential backoff: 2m → 5m → 10m → 15m → 30m, max 16h. Probes both providers after each interval, resumes on whichever responds first.
Token exhaustion waits don't count against MAX_RESUME_ATTEMPTS.
During Step 4, Claude is instructed to:
- Commit after each logical unit of work (not just at the end)
- Use conventional commits:
feat:/fix:/refactor:/test: - Make a final summary commit
feat: complete <task title>when all criteria pass
After each task, relay commits context.json and pushes.
bd list # task states
bd show <id> # full audit trail
jq '.tasks[] | {id, status, completed_at}' prd.json # prd.json view
cat .claude/context.json | jq . # inter-task memory
ls .claude/plans/ # plan + review artifactsEdit prd.json directly — add tasks, adjust criteria, add dependencies.
The pipeline re-reads it on each iteration.
bd create "New task" --id new-id
bd dep add new-id existing-idIf Codex is not installed or fails a task (non-quota error), relay permanently switches to Claude Sonnet for Steps 2–4 for the rest of that run. No intervention needed.
| File | Purpose |
|---|---|
AGENTS.md |
Per-project agent instructions + task descriptions |
prd.json |
Task graph — source of truth (commit this) |
.claude/pipeline.sh |
The loop script |
.claude/context.json |
Inter-task memory (committed after each task) |
.claude/plans/<id>_plan.md |
Step 1 plan artifact |
.claude/plans/<id>_review.md |
Step 3 review artifact |
See ARCHITECTURE.md for a full technical deep-dive.
See PLAN.md for the original goals this tool was built to satisfy.
MIT