ralph-teams 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/team-lead.md +12 -8
- package/README.md +3 -5
- package/package.json +1 -1
- package/ralph.sh +14 -16
|
@@ -44,10 +44,11 @@ For Claude subagents, choose the model based on task difficulty unless the envir
|
|
|
44
44
|
- When spawning: use `subagent_type: "planner"`. If `RALPH_MODEL_PLANNER_EXPLICIT=1`, use `RALPH_MODEL_PLANNER`. Otherwise choose `haiku`/`sonnet`/`opus` based on task difficulty.
|
|
45
45
|
- When you delegate planning, explicitly tell the Planner the exact output path for the epic plan file, for example `plans/plan-EPIC-001.md`, and require it to write the plan there before replying.
|
|
46
46
|
- Wait for the Planner to finish, then read the plan file it wrote before moving on.
|
|
47
|
-
3. **
|
|
48
|
-
|
|
49
|
-
-
|
|
50
|
-
|
|
47
|
+
3. **Do NOT create a long-lived Builder mailbox.** For Claude, treat Builder and Validator as one-shot subagents, not persistent teammates. Do NOT ask them to wait for future direct messages. Do NOT use `SendMessage` or `shutdown_request` to coordinate story execution.
|
|
48
|
+
4. **Builder/Validator policy.**
|
|
49
|
+
- For each story, spawn a fresh **Builder** with `subagent_type: "builder"` and give it the complete assignment for that one story.
|
|
50
|
+
- If `RALPH_MODEL_BUILDER_EXPLICIT=1`, use `RALPH_MODEL_BUILDER`. Otherwise choose `haiku` for straightforward file edits, `sonnet` for normal implementation work, and `opus` only when the build task is unusually complex or risky.
|
|
51
|
+
- **Validator — only spawn if truly needed.** Ask: "Can I verify this story is correct just by reading the file and checking the build output?" If YES → **do NOT spawn the Validator** — self-verify instead. If NO → spawn a fresh Validator for that one story.
|
|
51
52
|
- DO NOT spawn for: "add X to file Y" (read the file, check X is there), build/typecheck checks (run the command yourself or trust Builder's output)
|
|
52
53
|
- SPAWN for: logic correctness, new behaviour, API contracts, anything requiring judgment to verify
|
|
53
54
|
- When self-verifying: read the changed file(s), check each criterion, decide PASS or FAIL.
|
|
@@ -64,16 +65,17 @@ Before starting a story, check the `passes` field in the PRD file (at the path p
|
|
|
64
65
|
|
|
65
66
|
### Build Phase
|
|
66
67
|
1. Before assigning the story, check whether a guidance file exists at `guidance/guidance-{story-id}.md` (substituting the actual story ID, e.g. `guidance/guidance-US-003.md`).
|
|
67
|
-
2.
|
|
68
|
+
2. Spawn a fresh Builder subagent for this story with:
|
|
68
69
|
- Story ID and title
|
|
69
70
|
- Full acceptance criteria
|
|
70
71
|
- The relevant section from the implementation plan
|
|
71
72
|
- Any context from previous stories or prior validator feedback
|
|
72
73
|
- **If the guidance file exists**, include this line explicitly: `Guidance file for this story: guidance/guidance-{story-id}.md — read it before implementing and follow the instructions in it.`
|
|
73
|
-
3. Wait for Builder to
|
|
74
|
+
3. Wait for that Builder to finish and inspect its final response.
|
|
75
|
+
4. Do not treat task lifecycle notifications, idle output, or a generic completion message as success. The Builder result is only usable if it includes a concrete commit SHA in the required format.
|
|
74
76
|
|
|
75
77
|
### Validate Phase
|
|
76
|
-
|
|
78
|
+
5. **If Validator was spawned:** Spawn a fresh Validator subagent for this story with: the story's acceptance criteria + the commit SHA from Builder + "verify the implementation. Use `git diff <sha>~1 <sha>` to see exactly what changed." Wait for Validator verdict.
|
|
77
79
|
**If no Validator:** Verify yourself — read the changed files, check each acceptance criterion is met, and determine PASS or FAIL.
|
|
78
80
|
|
|
79
81
|
### Pushback Loop (max 2 total build+validate cycles)
|
|
@@ -83,7 +85,7 @@ The first build+validate cycle is attempt 1. If it fails, you get one retry (att
|
|
|
83
85
|
8. If Validator reports **PASS** → mark story as passed in PRD, move to next story
|
|
84
86
|
9. If Validator reports **FAIL**:
|
|
85
87
|
- Increment attempt counter for this story
|
|
86
|
-
- If attempt count < 2:
|
|
88
|
+
- If attempt count < 2: spawn a new Builder for the retry and include the failure details from validation
|
|
87
89
|
- If attempt count = 2: **document the failure and move on** (see Failure Documentation below)
|
|
88
90
|
|
|
89
91
|
## Failure Documentation
|
|
@@ -137,6 +139,7 @@ After processing ALL stories in the epic (none left to attempt):
|
|
|
137
139
|
## Rules
|
|
138
140
|
|
|
139
141
|
- NEVER write code yourself
|
|
142
|
+
- For Claude, Builder and Validator must be one-shot story-scoped subagents. Do NOT keep them alive across stories.
|
|
140
143
|
- Only skip the Planner for genuinely simple epics — when in doubt, run it
|
|
141
144
|
- Only skip the Validator for genuinely simple stories — when in doubt, spawn it; for complex stories the Validator must always run
|
|
142
145
|
- NEVER exceed 2 total build+validate cycles per story (first attempt + 1 retry = 2 total)
|
|
@@ -145,3 +148,4 @@ After processing ALL stories in the epic (none left to attempt):
|
|
|
145
148
|
- ALWAYS document failures before moving on
|
|
146
149
|
- Keep Builder and Validator unaware of each other's reasoning — Validator should only see the code (via commit SHA), not Builder's explanation of what it did
|
|
147
150
|
- ALWAYS pass the commit SHA from Builder to Validator
|
|
151
|
+
- NEVER treat task notifications, idle teammate output, or summary prose as a substitute for a real Builder result and PRD update
|
package/README.md
CHANGED
|
@@ -37,7 +37,6 @@ The runtime is file-based. During a run, Ralph treats these files as the working
|
|
|
37
37
|
- `plans/`: implementation plans for epics that were explicitly planned
|
|
38
38
|
- `progress.txt`: narrative progress log
|
|
39
39
|
- `logs/`: raw backend logs
|
|
40
|
-
- `results/`: per-epic final result markers
|
|
41
40
|
- `ralph-state.json`: interrupt/resume state
|
|
42
41
|
|
|
43
42
|
## Flow
|
|
@@ -74,7 +73,7 @@ flowchart TB
|
|
|
74
73
|
SP[Mark story passed in PRD]
|
|
75
74
|
F[Record failure]
|
|
76
75
|
M{More stories}
|
|
77
|
-
RF[
|
|
76
|
+
RF[Print DONE summary]
|
|
78
77
|
|
|
79
78
|
TL --> PP
|
|
80
79
|
PP -->|Yes| Q
|
|
@@ -440,7 +439,7 @@ Example:
|
|
|
440
439
|
Notes:
|
|
441
440
|
|
|
442
441
|
- Ralph enables Codex multi-agent mode per run, so no global `~/.codex/config.toml` edits are required
|
|
443
|
-
- Codex runs from each epic worktree and is granted write access to the repo root so it can update the shared PRD
|
|
442
|
+
- Codex runs from each epic worktree and is granted write access to the repo root so it can update the shared PRD
|
|
444
443
|
- Codex does not use a separate repo-local Team Lead role file; the Team Lead policy comes from the runtime prompt assembled in `ralph.sh`, while `.codex/agents/*.toml` define the spawned planner, builder, validator, and merger roles
|
|
445
444
|
|
|
446
445
|
## PRD Format
|
|
@@ -501,7 +500,6 @@ During a run, Ralph writes:
|
|
|
501
500
|
- `progress.txt`: high-level run log
|
|
502
501
|
- `plans/plan-EPIC-xxx.md`: planner output for an epic
|
|
503
502
|
- planned epics are expected to use these files as their implementation contract
|
|
504
|
-
- `results/result-EPIC-xxx.txt`: final pass/partial/fail result per epic
|
|
505
503
|
- `logs/epic-EPIC-xxx-<timestamp>.log`: raw backend session log
|
|
506
504
|
- `ralph-state.json`: saved interrupt/resume state
|
|
507
505
|
- `guidance/guidance-US-xxx.md`: retry guidance captured from discuss flows
|
|
@@ -527,7 +525,7 @@ The current execution contract is:
|
|
|
527
525
|
- rerunning Ralph automatically resets `failed` and `partial` epics back to `pending` so only unfinished work is retried
|
|
528
526
|
- each story gets at most two build/validate cycles
|
|
529
527
|
- the validator checks output independently from the builder's reasoning
|
|
530
|
-
- after
|
|
528
|
+
- after updating `prd.json` for all attempted stories, the team lead must print `DONE: X/Y stories passed` and exit the session immediately
|
|
531
529
|
- pressing `Ctrl-C` writes `ralph-state.json` so the run can be resumed later with `ralph-teams resume`
|
|
532
530
|
|
|
533
531
|
## Troubleshooting
|
package/package.json
CHANGED
package/ralph.sh
CHANGED
|
@@ -871,10 +871,8 @@ spawn_epic_bg() {
|
|
|
871
871
|
PENDING_STORIES_JSON=$(rjq read "$PRD_FILE" ".epics[$EPIC_INDEX].userStories" | \
|
|
872
872
|
node -e 'const fs=require("fs"); const stories=JSON.parse(fs.readFileSync(0,"utf8")); process.stdout.write(JSON.stringify(stories.filter(s => s.passes !== true)));')
|
|
873
873
|
|
|
874
|
-
local RESULT_FILE="${ROOT_DIR}/results/result-${EPIC_ID}.txt"
|
|
875
874
|
local EPIC_LOG="${ROOT_DIR}/logs/epic-${EPIC_ID}-$(date +%s).log"
|
|
876
|
-
mkdir -p "${ROOT_DIR}/
|
|
877
|
-
rm -f "$RESULT_FILE"
|
|
875
|
+
mkdir -p "${ROOT_DIR}/logs"
|
|
878
876
|
|
|
879
877
|
# Create isolated worktree for this epic
|
|
880
878
|
local WORKTREE_PATH
|
|
@@ -950,7 +948,7 @@ $PENDING_STORIES_JSON
|
|
|
950
948
|
## Critical Rules
|
|
951
949
|
- Do NOT stop after the first story — process ALL stories before exiting
|
|
952
950
|
- Idle or waiting messages from teammates are NORMAL — they do not mean the session should end
|
|
953
|
-
- Once the final
|
|
951
|
+
- Once the final PRD updates are complete and you have printed the DONE summary, end the session immediately. Do not wait for more input.
|
|
954
952
|
- Process stories sequentially: build → validate → next. Do not stop early.
|
|
955
953
|
- After each story result (pass or fail), update $PRD_ABS_PATH to keep both passes and failureReason accurate for that story
|
|
956
954
|
|
|
@@ -1220,7 +1218,6 @@ while true; do
|
|
|
1220
1218
|
for slot in "${!active_pids[@]}"; do
|
|
1221
1219
|
local finished_epic_id
|
|
1222
1220
|
finished_epic_id=$(rjq read "$PRD_FILE" ".epics[${active_indices[$slot]}].id")
|
|
1223
|
-
local result_file="${ROOT_DIR}/results/result-${finished_epic_id}.txt"
|
|
1224
1221
|
local process_finished=false
|
|
1225
1222
|
|
|
1226
1223
|
emit_new_log_output "$finished_epic_id" "${active_logs[$slot]}" "${active_log_lines[$slot]:-0}"
|
|
@@ -1326,22 +1323,23 @@ while true; do
|
|
|
1326
1323
|
process_finished=true
|
|
1327
1324
|
fi
|
|
1328
1325
|
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1326
|
+
local total_s passed_s
|
|
1327
|
+
total_s=$(rjq length "$PRD_FILE" ".epics[${active_indices[$slot]}].userStories")
|
|
1328
|
+
passed_s=$(rjq count-where "$PRD_FILE" ".epics[${active_indices[$slot]}].userStories" "passes=true")
|
|
1329
|
+
local all_done=false
|
|
1330
|
+
[ "$passed_s" -eq "$total_s" ] && [ "$total_s" -gt 0 ] && all_done=true
|
|
1331
|
+
|
|
1332
|
+
if [ "$process_finished" = true ] || [ "$all_done" = true ]; then
|
|
1333
|
+
# Treat fully-passed stories in the PRD as the authoritative completion
|
|
1334
|
+
# signal, even if the backend session is still idling.
|
|
1332
1335
|
if [ "$process_finished" = false ]; then
|
|
1333
1336
|
terminate_process_tree "${active_pids[$slot]}"
|
|
1334
1337
|
fi
|
|
1335
1338
|
wait "${active_pids[$slot]}" 2>/dev/null || true
|
|
1336
1339
|
|
|
1337
|
-
#
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
passed_s=$(rjq count-where "$PRD_FILE" ".epics[${active_indices[$slot]}].userStories" "passes=true")
|
|
1341
|
-
local all_done=false
|
|
1342
|
-
[ "$passed_s" -eq "$total_s" ] && [ "$total_s" -gt 0 ] && all_done=true
|
|
1343
|
-
|
|
1344
|
-
if [ ! -f "$result_file" ] && [ "$all_done" = false ]; then
|
|
1340
|
+
# If the process exited before the epic reached all stories passed,
|
|
1341
|
+
# consider it a crash and retry when possible.
|
|
1342
|
+
if [ "$all_done" = false ]; then
|
|
1345
1343
|
local retry_count
|
|
1346
1344
|
retry_count="$(get_crash_retry_count "$finished_epic_id")"
|
|
1347
1345
|
if [ "$retry_count" -lt "$MAX_CRASH_RETRIES" ]; then
|