@jaybeeuu/agent-cortex 2.0.0 → 2.2.0

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.
Files changed (183) hide show
  1. package/CHANGELOG.md +437 -0
  2. package/README.md +46 -15
  3. package/agents/README.md +22 -10
  4. package/agents/plan/agent.md +2 -2
  5. package/agents/ralph/agent.md +128 -91
  6. package/agents/ralph/claude/frontmatter.json +3 -3
  7. package/agents/ralph/claude/wake.md +46 -0
  8. package/agents/ralph/pi/{polling.md → wake.md} +35 -20
  9. package/agents/ralph-plan/agent.md +23 -11
  10. package/bin/agent-cortex.mjs +66 -4
  11. package/bin/installers/claude.mjs +262 -77
  12. package/bin/installers/pi.mjs +200 -24
  13. package/extensions/agent-guardrails/README.md +1 -1
  14. package/extensions/agent-guardrails/guardrails.ts +1 -1
  15. package/extensions/agent-guardrails/index.ts +1 -1
  16. package/extensions/agent-modes/discover.test.ts +2 -2
  17. package/extensions/output-style/README.md +58 -0
  18. package/extensions/output-style/index.ts +23 -0
  19. package/extensions/output-style/output-style.md +43 -0
  20. package/extensions/output-style/output-style.test.ts +50 -0
  21. package/extensions/output-style/output-style.ts +32 -0
  22. package/extensions/output-style/package.json +19 -0
  23. package/hooks/claude/scripts/notify.mjs +8 -1
  24. package/lib/cli.mjs +91 -2
  25. package/package.json +29 -4
  26. package/scripts/check-changeset.mjs +4 -0
  27. package/scripts/check-no-sync.mjs +5 -1
  28. package/scripts/check-skill-frontmatter.mjs +21 -0
  29. package/scripts/lib/compose-agent.mjs +69 -9
  30. package/scripts/lib/fs.mjs +10 -2
  31. package/scripts/lib/migrate.mjs +736 -0
  32. package/scripts/lib/release-gates.mjs +21 -1
  33. package/scripts/lib/skill-frontmatter.mjs +152 -0
  34. package/scripts/lib/skill-links.mjs +52 -0
  35. package/scripts/lib/verify-worker-tree.mjs +25 -0
  36. package/scripts/resolve-publish-command.mjs +4 -0
  37. package/skills/engineering/design-an-interface/SKILL.md +3 -3
  38. package/skills/engineering/grill-with-docs/SKILL.md +3 -5
  39. package/skills/engineering/improve-codebase-architecture/SKILL.md +5 -4
  40. package/skills/engineering/tdd/SKILL.md +5 -7
  41. package/skills/engineering/technical-direction/SKILL.md +5 -5
  42. package/skills/planning/classify-bead/REFERENCE.md +3 -3
  43. package/skills/planning/classify-bead/SKILL.md +14 -9
  44. package/skills/planning/classify-bead/scripts/classify-bead.mjs +5 -4
  45. package/skills/planning/create-task/REFERENCE.md +52 -3
  46. package/skills/planning/create-task/SKILL.md +70 -26
  47. package/skills/planning/create-task/scripts/{create-chores.ts → create-chores.mjs} +48 -23
  48. package/skills/planning/flesh-out-idea/REFERENCE.md +116 -0
  49. package/skills/planning/flesh-out-idea/SKILL.md +146 -0
  50. package/skills/planning/prd-to-tasks/REFERENCE.md +54 -5
  51. package/skills/planning/prd-to-tasks/SKILL.md +22 -16
  52. package/skills/planning/record-idea/FORMAT.md +66 -17
  53. package/skills/planning/record-idea/SKILL.md +48 -24
  54. package/skills/planning/request-refactor-plan/SKILL.md +4 -4
  55. package/skills/planning/spec-to-tickets/SKILL.md +5 -5
  56. package/skills/planning/write-a-prd/SKILL.md +8 -9
  57. package/skills/planning/write-a-ticket/SKILL.md +4 -6
  58. package/skills/productivity/bd-tool/SKILL.md +15 -10
  59. package/skills/productivity/grill-me/SKILL.md +5 -0
  60. package/skills/productivity/init-beads/SKILL.md +3 -3
  61. package/skills/productivity/migration/REFERENCE.md +227 -0
  62. package/skills/productivity/migration/SKILL.md +188 -0
  63. package/skills/productivity/validate-agent-dir/scripts/{validate-agent-dir.ts → validate-agent-dir.mjs} +49 -28
  64. package/skills/productivity/write-a-skill/SKILL.md +5 -5
  65. package/skills/review/maintain-agent-docs/SKILL.md +5 -7
  66. package/skills/review/refactor-skill/SKILL.md +4 -3
  67. package/skills/review/review-security/SKILL.md +3 -5
  68. package/skills/style/style-code/SKILL.md +5 -10
  69. package/skills/style/style-comms/SKILL.md +5 -7
  70. package/skills/style/style-documentation/SKILL.md +5 -6
  71. package/skills/style/style-tests/SKILL.md +5 -7
  72. package/skills/workflow/git-workflow/SKILL.md +28 -4
  73. package/skills/workflow/hitl-collab/SKILL.md +4 -6
  74. package/skills/workflow/plan/SKILL.md +41 -30
  75. package/skills/workflow/ralph/REFERENCE.md +209 -55
  76. package/skills/workflow/ralph/SKILL.md +89 -50
  77. package/skills/workflow/ralph/scripts/pending-gates.mjs +134 -0
  78. package/skills/workflow/run-pipeline-stage/SKILL.md +72 -71
  79. package/skills/workflow/run-pipeline-stage/playbooks/code.md +11 -0
  80. package/skills/workflow/run-pipeline-stage/playbooks/document.md +12 -0
  81. package/skills/workflow/run-pipeline-stage/playbooks/fix.md +12 -0
  82. package/skills/workflow/run-pipeline-stage/playbooks/review.md +11 -0
  83. package/skills/workflow/run-pipeline-stage/playbooks/verify.md +13 -0
  84. package/skills/workflow/run-pipeline-stage/prompts/stage-runner.md +73 -1
  85. package/token-map.README.md +9 -4
  86. package/token-map.json +13 -6
  87. package/.agents/skills/style-versioning/SKILL.md +0 -172
  88. package/.changeset/README.md +0 -8
  89. package/.changeset/config.json +0 -11
  90. package/.github/workflows/ci.yml +0 -302
  91. package/.junie/guidelines.md +0 -87
  92. package/.junie/mcp/mcp.json +0 -10
  93. package/AGENTS.md +0 -151
  94. package/agents/ralph/claude/polling.md +0 -31
  95. package/agents-native/ralph.md +0 -193
  96. package/docs/claude-hooks.md +0 -128
  97. package/docs/commit-signing.md +0 -231
  98. package/docs/ideas/auto-model-selection.md +0 -75
  99. package/docs/ideas/ban-content-assertion-tests.md +0 -75
  100. package/docs/ideas/bead-progress-notes-for-session-resumption.md +0 -75
  101. package/docs/ideas/classify-beads-via-deterministic-script-with-agent-fallback.md +0 -70
  102. package/docs/ideas/ctx-alias-version-and-update-commands.md +0 -65
  103. package/docs/ideas/ctx-feedback-command-for-capturing-ideas-from-any-machine.md +0 -67
  104. package/docs/ideas/dedicated-review-tests-skill.md +0 -71
  105. package/docs/ideas/deployment-beads-for-post-merge-pipelines.md +0 -36
  106. package/docs/ideas/design-and-delivery-as-separate-bead-trees/design-and-delivery-as-separate-bead-trees.md +0 -99
  107. package/docs/ideas/enable-signed-commit-enforcement-changesets-bot-commits-must-be-signed.md +0 -42
  108. package/docs/ideas/extension-manifests.md +0 -121
  109. package/docs/ideas/improve-pi-system-prompt.md +0 -37
  110. package/docs/ideas/map-every-cortex-tool-to-a-real-pi-equivalent.md +0 -95
  111. package/docs/ideas/model-selector.md +0 -40
  112. package/docs/ideas/pi-task-memory.md +0 -34
  113. package/docs/ideas/qa-extension.md +0 -43
  114. package/docs/ideas/record-idea-implementation-questions.md +0 -68
  115. package/docs/ideas/record-ideas-as-beads.md +0 -115
  116. package/docs/ideas/self-flushing-session.md +0 -72
  117. package/docs/ideas/state-in-beads-not-md.md +0 -69
  118. package/docs/ideas/subagent-visibility.md +0 -72
  119. package/docs/ideas/task-session-context.local.md +0 -95
  120. package/docs/ideas/task-session-context.md +0 -89
  121. package/docs/ideas/test-data-creation-helpers.md +0 -92
  122. package/docs/ideas/test-planning-stage-bead-in-feature-planning.md +0 -68
  123. package/docs/ideas/unified-ci-pipeline.md +0 -28
  124. package/docs/ideas/unify-the-ticket-and-task-decomposition-workflows.md +0 -71
  125. package/docs/ideas/worktree-housekeeping-for-closed-beads.md +0 -39
  126. package/docs/inspirations.md +0 -33
  127. package/docs/research/disable-model-invocation.md +0 -82
  128. package/docs/research/gas-city-research.md +0 -256
  129. package/docs/research/skill-design-research.md +0 -286
  130. package/docs/research/skill-improvements-analysis.md +0 -117
  131. package/docs/research/skill-patterns-research.md +0 -24
  132. package/docs/skills/skill-anatomy.md +0 -197
  133. package/docs/technical-direction/harness-config.md +0 -177
  134. package/docs/technical-direction/migration-execution-labels.md +0 -177
  135. package/docs/user-preferences.md +0 -17
  136. package/extensions/agent-guardrails/tsconfig.json +0 -12
  137. package/extensions/agent-modes/tsconfig.json +0 -12
  138. package/extensions/session-start/tsconfig.json +0 -12
  139. package/extensions/skill-stats/pnpm-lock.yaml +0 -329
  140. package/extensions/skill-stats/tsconfig.json +0 -12
  141. package/extensions/subagent/agents/planner.md +0 -37
  142. package/extensions/subagent/agents/reviewer.md +0 -35
  143. package/extensions/subagent/agents/scout.md +0 -50
  144. package/extensions/subagent/agents/worker.md +0 -24
  145. package/extensions/subagent/prompts/implement-and-review.md +0 -10
  146. package/extensions/subagent/prompts/implement.md +0 -10
  147. package/extensions/subagent/prompts/scout-and-plan.md +0 -9
  148. package/extensions/subagent/tsconfig.json +0 -12
  149. package/pi/keybindings.json +0 -3
  150. package/pi/settings.json +0 -34
  151. package/pnpm-workspace.yaml +0 -14
  152. package/skills/planning/create-task/scripts/package.json +0 -14
  153. package/skills/planning/create-task/scripts/pnpm-lock.yaml +0 -342
  154. package/skills/planning/create-task/scripts/tsconfig.json +0 -12
  155. package/skills/planning/record-idea/scripts/new-idea.sh +0 -89
  156. package/skills/productivity/validate-agent-dir/scripts/package.json +0 -15
  157. package/skills/productivity/validate-agent-dir/scripts/pnpm-lock.yaml +0 -329
  158. package/skills/productivity/validate-agent-dir/scripts/pnpm-workspace.yaml +0 -2
  159. package/skills/productivity/validate-agent-dir/scripts/tsconfig.json +0 -19
  160. package/skills/productivity/validate-agent-dir/scripts/validate-agent-dir.test.ts +0 -317
  161. package/skills/workflow/run-pipeline-stage/REFERENCE.md +0 -22
  162. package/skills/workflow/run-pipeline-stage/scripts/generate-progress.test.ts +0 -682
  163. package/skills/workflow/run-pipeline-stage/scripts/generate-progress.ts +0 -588
  164. package/skills/workflow/run-pipeline-stage/scripts/package.json +0 -15
  165. package/skills/workflow/run-pipeline-stage/scripts/pnpm-lock.yaml +0 -342
  166. package/skills/workflow/run-pipeline-stage/scripts/pnpm-workspace.yaml +0 -2
  167. package/skills/workflow/run-pipeline-stage/scripts/tsconfig.json +0 -12
  168. package/test/classify-bead.test.mjs +0 -277
  169. package/test/claude-installer.test.mjs +0 -308
  170. package/test/cli.test.mjs +0 -314
  171. package/test/create-chores.test.mjs +0 -85
  172. package/test/fake-bd.test.mjs +0 -72
  173. package/test/fs.test.mjs +0 -76
  174. package/test/helpers/fake-bd.mjs +0 -87
  175. package/test/helpers/fake-claude.mjs +0 -152
  176. package/test/helpers/fake-pi.mjs +0 -132
  177. package/test/installer.test.mjs +0 -664
  178. package/test/notify-hook.test.mjs +0 -63
  179. package/test/pi-installer.test.mjs +0 -785
  180. package/test/pi-register.test.mjs +0 -342
  181. package/test/pi-sweep.test.mjs +0 -619
  182. package/test/release-gates.test.mjs +0 -190
  183. package/test/verify-worker-tree.test.mjs +0 -120
@@ -1,18 +1,22 @@
1
1
  ---
2
2
  name: ralph
3
- description: "Run all pending beads end-to-end with up to 5 concurrent pipeline-stage chores in dedicated worktrees, opening review-gated PRs immediately and pausing for human merges. Use when you want to \"run the backlog\", \"run all beads\", or \"run ralph\" with human approval gates."
3
+ description: "Run every ready execution:afk bead end-to-end — decomposing features, expanding tasks into pipeline-stage chores, and driving up to 5 concurrent workers in dedicated worktrees while opening review-gated PRs immediately and pausing for human merges. Use when you want to \"run the backlog\", \"run all beads\", or \"run ralph\" with human approval gates."
4
4
  ---
5
5
 
6
6
  # Ralph
7
7
 
8
- Ralph is a parallel orchestration loop. It advances AFK task beads through pipeline-stage chores (`code` → `verify` → `review` → `document`), dispatching each stage as a background subagent in the feature's worktree, then opens review-gated feature and epic PRs and pauses for human merges. Ralph never writes code itself — it dispatches, tracks, and reports.
8
+ Ralph is a parallel orchestration loop. It advances `execution:afk` beads through pipeline-stage chores (`code` → `verify` → `review` → `document`), dispatching each unit as a background subagent in its parent's worktree, then opens review-gated feature and epic PRs and pauses for human merges. Ralph never writes code itself — it dispatches, tracks, and reports.
9
9
 
10
- State model: task state lives in beads (ready/in_progress via `bd`); the only local file is `.agent-cortex/ralph/state.json`, holding the agent-ID→bead mapping. Pipeline configuration comes from `skills/planning/create-task/pipeline.json`, and stage execution belongs to the `run-pipeline-stage` skill.
10
+ One query decides what ralph works on: **`bd ready -l execution:afk`**. Features, tasks and chores all arrive through it, and each bead's *shape* — not a second `bd` filter — decides which procedure carries it: a childless feature is decomposed, a bead with no stage chores is expanded, a stage chore is dispatched. An `execution:afk` bead is therefore never invisible to ralph for lacking a `stage:*` label, and ralph never invents a narrower "only stage chores" predicate that would hide one.
11
+
12
+ Each leaf execution bead belongs to the worker that ran it: the worker appends its milestone notes, closes the bead on both outcomes, and builds its own `stage:fix` + fresh-stage remediation chain when it fails. Ralph reads beads and routes — it never closes a leaf bead and never creates a fix bead. Its only retry control is a read-only cap backstop.
13
+
14
+ State model: task state lives in beads (ready/in_progress via `bd`); the only local file is `.agent-cortex/ralph/state.json`, holding the agent-ID→bead mapping. Pipeline configuration comes from `skills/planning/create-task/pipeline.json`, and stage execution belongs to the `run-pipeline-stage` skill. Stage chores are pre-created from that pipeline when a task is expanded — with `blocks` deps encoding the order — so ralph's dispatch is always "claim what `bd ready -l execution:afk` returns"; it never creates a stage chore.
11
15
 
12
16
  ## When to use
13
17
 
14
18
  - "Run the backlog", "run all beads", "run ralph", "run everything pending".
15
- - A planning session has produced classified, unblocked AFK task beads and you want autonomous execution with human review gates.
19
+ - A planning session has produced classified, unblocked `execution:afk` beads and you want autonomous execution with human review gates.
16
20
  - You want the full pipeline (implement → verify → review → document) orchestrated concurrently, with fix loops on failure.
17
21
 
18
22
  ## When NOT to use
@@ -29,61 +33,85 @@ State model: task state lives in beads (ready/in_progress via `bd`); the only lo
29
33
  2. Ensure `.agent-cortex/` and `.agent-cortex/worktrees/` are in the project's `.gitignore` (append any that are missing).
30
34
  3. Create the workspace: `mkdir -p .agent-cortex/ralph`.
31
35
  4. Initialize state: write `.agent-cortex/ralph/state.json` with `{ "inflight": [] }`.
32
- 5. Read `skills/planning/create-task/pipeline.json` and hold it in memory — you need its `maxFixRounds` for the fix loop.
33
- 6. Run `bd ready` and classify each available bead:
34
- - **Chore with a `stage:*` label**: pipeline stage bead — eligible for dispatch.
35
- - **Task or other type without an `implementation-type:*` label**: unexpected here — classification happens at planning time via `create-task`. Do not invoke `classify-bead`; treat as needs-refinement and note it for the shutdown summary.
36
- - **Task labelled `implementation-type:hitl`**: skip — record the ID for the Pending Human Action summary at shutdown.
37
- 7. For each ready chore bead (up to 5), dispatch it from its parent's feature worktree (see _Dispatching a chore bead_ in REFERENCE.md — create branches/worktrees first).
38
- 8. Hand over to your harness's completion-detection mechanism: PI keeps a {{TOOL:wait_for_agents}} call outstanding over every in-flight agent ID. If no chore was dispatched and HITL gate beads are pending (`bd list -l lifecycle:feature-pr -l implementation-type:hitl` or `bd list -l awaiting-epic-pr-merge`), go straight to HITL Pause (REFERENCE.md).
39
- 9. Regenerate `.agent-cortex/ralph/progress.md`:
40
- ```bash
41
- # workspace must be the absolute path you cd'd into — never . or $(pwd)
42
- workspace="/absolute/path/to/worktree"
43
- pnpm --prefix skills/workflow/run-pipeline-stage/scripts exec tsx generate-progress.ts --workspace "$workspace" > "$workspace/.agent-cortex/ralph/progress.md"
44
- ```
45
-
46
- ### 2. Event loop
36
+ 5. Read `skills/planning/create-task/pipeline.json` and hold it in memory — you need its `maxFixRounds` for the read-only cap backstop.
37
+ 6. Run **`bd ready -l execution:afk`**. That single query *is* the dispatch predicate — every ready `execution:afk` bead is ralph's work, whether it is a feature, a task or a chore. Classify each result by its shape to decide which procedure carries it:
38
+ - **`feature` bead with no children**: not dispatchable work yet — decompose it (_Feature decomposition_ below) and re-run the query.
39
+ - **Bead carrying a `stage:*` label**: a pipeline stage chore — dispatch it (_Event loop_, and _Dispatching a Chore Bead_ in REFERENCE.md).
40
+ - **`task` or other bead with no `stage:*` chore children**: expand it first (_Expansion guard_ below), then dispatch its ready `stage:code` chore.
41
+ - **Bead that already has its children** (a decomposed feature, an expanded task parent): skip it — it is not dispatchable itself, and its `stage:*` chore is dispatched on its own.
42
+ `execution:hitl` beads are not in this query and are not ralph's to touch: record them for the Pending Human Action summary. That includes every feature still at its default `execution:hitl` label.
43
+ 7. Dispatch each unit from its parent's worktree, up to 5 in flight: a stage chore via the event loop, a childless feature via a decomposition worker (_Feature decomposition_), a chore-less task via an expansion worker (_Expansion guard_). Create branches and worktrees first (REFERENCE.md, _Feature Branches and Worktrees_).
44
+ 8. Hand over to your harness's completion-detection mechanism: PI keeps a {{TOOL:wait_for_agents}} call outstanding over every in-flight agent ID, and Claude re-invokes you as each worker completes. If no **agent work** was dispatched — `state.json`'s `inflight` holds no entries, so no stage, decomposition or expansion worker is running — and `skills/workflow/ralph/scripts/pending-gates.mjs` reports a non-empty `pendingHumanAction` (an unblocked `lifecycle:feature-pr` gate, or an epic tagged `awaiting-epic-pr-merge`), go straight to HITL Pause (REFERENCE.md). A decomposition- or expansion-only init is in flight, not idle: keep the completion mechanism running and continue at the event loop.
45
+
46
+ ### 2. Expansion guard (stage chores are pre-created)
47
+
48
+ A ready `execution:afk` task bead with no `stage:*` chore children has nothing to dispatch, so it is not dispatched as work. Expand it first: dispatch a worker in the feature worktree that runs `create-chores.mjs --parent <id> --priority <parent-priority>` against the existing bead and reports the returned `code`/`verify`/`review`/`document`/`featurePrReview` mapping — the next `bd ready -l execution:afk` pass then picks up `stage:code` (see REFERENCE.md, _Expansion Guard_).
49
+
50
+ **Never expand an existing bead with `create-task`.** It creates a bead first and expands second, so the original would stay chore-less and gain a **second parent** beside it. `create-chores.mjs` expands; only `create-task` creates parents.
51
+
52
+ ### 3. Feature decomposition
53
+
54
+ A ready `execution:afk` bead of type `feature` with no children is not dispatchable work — there is nothing to stage and nothing to expand. Decompose it: dispatch a worker in `.agent-cortex/worktrees/<feature-id>` that turns the feature into one `execution:hitl` planning bead plus `execution:afk` implementation children that depend on it, then continue (REFERENCE.md, _Feature Decomposition_).
55
+
56
+ A feature carries `execution:hitl` by default, so this only runs when a human has deliberately relabelled a feature `execution:afk` to make its delivery agent-routable. Decomposition is then the last thing ralph does with it for a while: the children depend on the planning bead, so once the worker reports, `bd ready -l execution:afk` returns only the feature itself — no dispatchable child — and skipping that row is the *correct* behaviour, not re-expanding. **Never re-dispatch a decomposition**: the bead creation it runs is not idempotent, so a second run duplicates the whole hierarchy.
57
+
58
+ ### 4. Event loop
47
59
 
48
60
  On each completion notification (a background agent finished):
49
61
 
50
62
  1. Poll that parent's log for new lines — `tail -n +<nextLine> .agent-cortex/ralph/ralph-<parent-id>.log` (logs are keyed by parent bead ID, so every stage of a feature shares one file) — and post only new key events (stage transitions, test/lint results), never empty updates.
51
- 2. Read the completed agent's output with {{TOOL:read_agent}} and parse its `---REPORT---` block for `BEAD_ID`, `STAGE_COMPLETED`, and the outcome.
52
- 3. **Verify the delivery, then close the chore bead.** Run `node scripts/lib/verify-worker-tree.mjs --worktree .agent-cortex/worktrees/<parent-id> --base <base>` (REFERENCE.md, _Verified Completion_) and close only when it exits 0: `bd close <bead-id>`.
53
- 4. Advance the parent per the dispatch table:
63
+ 2. Read the completed agent's output with {{TOOL:read_agent}} and parse its `---REPORT---` block for `BEAD_ID`, `STAGE_COMPLETED`, and the outcome. A **decomposition** (`kind: "decompose"`) or **expansion** (`kind: "expand"`) worker has no REPORT and no leaf bead to confirm. An **expansion worker** owns no bead — confirm the parent now has `stage:*` chores (`bd children <parent-id> --json | grep -c '"stage:'`) and skip to step 5 to dispatch its ready `stage:code` chore. A **decomposition worker** — confirm the feature now has children (`bd children <feature-id> --json` returns a non-empty list), record that nothing is dispatchable for it until a human closes the planning bead, and skip to step 5; never re-decompose. If either confirmation comes back empty, the worker failed: surface its output, record the parent for the shutdown summary, and do not re-dispatch.
64
+ 3. Confirm the stage worker closed its chore bead: `bd show <bead-id>` should read `closed` with the outcome in its close reason. If it is still open the worker died mid-stage — read its notes and re-dispatch; never close it yourself.
65
+ 4. Route the parent per the dispatch table — nothing is created here: the pre-created chain already encodes the order, and the worker owns any remediation it needs.
54
66
 
55
67
  | Stage completed | Condition | Next action |
56
68
  |-----------------|-----------|-------------|
57
- | `code` | — | Closing the code chore unblocks the verify chore |
58
- | `fix` | — | Closing the fix chore unblocks the verify chore |
59
- | `verify` | `VERIFY_OUTCOME: PASS` | Closing the verify chore unblocks the review chore |
60
- | `verify` | `VERIFY_OUTCOME: FAIL` | Run the fix loop (REFERENCE.md) |
61
- | `review` | `REVIEW_OUTCOME: APPROVED` | Closing the review chore unblocks the document chore |
62
- | `review` | `REVIEW_OUTCOME: CHANGES_REQUESTED` | Run the fix loop (REFERENCE.md) |
63
- | `document` | — | Open/update the feature PR now (`feature/<parent-id>` → its base branch), report the URL, and update the child HITL gate bead (`lifecycle:feature-pr`). Wait for a human to close that bead after merge, then `bd close <parent-id>` |
69
+ | `code` | — | Closing the code chore unblocks the pre-created verify chore |
70
+ | `fix` | — | Closing the fix chore unblocks the fresh stage chore it was wired to |
71
+ | `verify` | `OUTCOME: SUCCESS` | Closing the verify chore unblocks the review chore |
72
+ | `verify` | `OUTCOME: BLOCKED` | Create nothing — the worker built `stage:fix` + a fresh `stage:verify`; dispatch the ready fix chore |
73
+ | `review` | `OUTCOME: SUCCESS` | Closing the review chore unblocks the document chore |
74
+ | `review` | `OUTCOME: BLOCKED` | Create nothing — the worker built `stage:fix` + a fresh `stage:review`; dispatch the ready fix chore |
75
+ | `document` | `OUTCOME: SUCCESS` | Open/update the feature PR now (`feature/<parent-id>` → its base branch), report the URL, and update the child HITL gate bead (`lifecycle:feature-pr`). Wait for a human to close that bead after merge, then `bd close <parent-id>` |
76
+ | any | parent status `blocked` | Nothing — the worker hit `maxFixRounds`; record the parent for the shutdown summary |
77
+
78
+ 5. Run `bd ready -l execution:afk` and dispatch new ready work while the in-flight count is under 5 — max 5 parent features, counted from `state.json`'s `inflight` (a parent counts while any of its workers — stage, `kind: "decompose"` or `kind: "expand"` — sits in `inflight`; REFERENCE.md, _State Files_). A ready childless feature is decomposed, not staged, and a ready bead with no chore tree is expanded (see _Feature decomposition_ and _Expansion guard_ above). Before each dispatch run the read-only cap backstop (REFERENCE.md, _Cap Backstop_): at `maxFixRounds` block the parent and create nothing. Do not schedule new parent features while `pending-gates.mjs` reports a non-empty `pendingHumanAction` — that is, while a `lifecycle:feature-pr` gate is **unblocked**. Gates still blocked behind their own pipeline (pre-created for a feature that has not reached its PR stage) are parked and never stop dispatch.
79
+ 6. If nothing is in flight (no stage, decomposition or expansion workers) and nothing is dispatchable (`bd ready -l execution:afk` returns no stage chore, no childless feature to decompose, and no ready, claimable chore-less task awaiting expansion — a queued `execution:afk` bead behind an open `lifecycle:feature-pr` HITL gate cannot be claimed, so it is paused work, not dispatchable work), proceed to HITL Pause (REFERENCE.md) when `pendingHumanAction` is non-empty, otherwise to Shutdown (REFERENCE.md).
80
+
81
+ ### 5. Reporting status (beads are the view)
64
82
 
65
- 5. Run `bd ready` and dispatch new ready `stage:*` chore beads while the in-flight count (`bd list --status=in_progress --type=chore`) is under 5. Do not schedule new parent features while any `lifecycle:feature-pr` HITL gate bead is open.
66
- 6. If no chores are in-flight and `bd ready` returns no `stage:*` chores, proceed to HITL Pause (REFERENCE.md) when HITL gate beads are pending, otherwise to Shutdown (REFERENCE.md).
67
- 7. Regenerate `.agent-cortex/ralph/progress.md`.
83
+ There is no status document to render. Report status in chat straight from `bd`, and give the human the same copy-paste command when they want the view themselves:
68
84
 
69
- ### 3. Branching and review model
85
+ ```bash
86
+ bd list --parent <parent-id> # every chore for a feature, with its state
87
+ bd ready -l execution:afk # the next dispatchable work
88
+ bd show <id> # full detail, including the worker's notes
89
+ ```
90
+
91
+ ### 6. Branching and review model
70
92
 
71
93
  - **Single-feature epics** (exactly one feature task child — count with `bd children <epic-id>`, excluding chores): no epic branch. `feature/<parent-id>` is based directly on `origin/main`, its feature PR targets `main`, and no epic PR is opened.
72
- - **Multi-feature epics** (two or more feature task children): the epic runs on `epic/<epic-id>`, based on `origin/main` — never local `main`. Each AFK parent task runs on `feature/<parent-id>`, based from its epic branch, in the dedicated worktree `.agent-cortex/worktrees/<parent-id>`.
94
+ - **Multi-feature epics** (two or more feature task children): the epic runs on `epic/<epic-id>`, based on `origin/main` — never local `main`. Each `execution:afk` parent task runs on `feature/<parent-id>`, based from its epic branch, in the dedicated worktree `.agent-cortex/worktrees/<parent-id>`.
73
95
  - Feature PR gate: `feature/<parent-id>` → `epic/<epic-id>` (or → `main` for single-feature epics). Epic PR gate: `epic/<epic-id>` → `main`.
96
+ - **Never stack branches.** `feature/<parent-id>` is based on `epic/<epic-id>` (or `origin/main`), never on another `feature/*`. A dependency between two tasks lives in the bead graph (`bd dep add <waiting> <blocked-on>`) so the dependent task stays out of `bd ready` until its dependency has merged — stacking the branch defeats that gate by hand and costs a rebase-on-squash later (see `git-workflow` rule 3).
74
97
  - Branch/worktree setup and the PR commands live in REFERENCE.md (_Feature branches and worktrees_, _Feature PR gate_).
75
98
 
76
- ### 4. HITL pause and shutdown
99
+ ### 7. HITL pause and shutdown
100
+
101
+ Both paths end in a **gated** `bd dolt push`: on a non-zero exit, retry once, then stop and report the command, exit code and stderr as a sync blocker instead of printing any completion or Pending Human Action summary. A sync that never reached the remote is a failed shutdown, not a finished one.
77
102
 
78
- - **HITL Pause** — when no chores are in-flight, none ready, and HITL gate beads are pending: regenerate `progress.md`, open/update epic PRs to `main` for multi-feature epics and tag each epic `awaiting-epic-pr-merge` (single-feature epics need none — their feature PRs already target `main`), run `bd dolt push`, output the Pending Human Action table, then stop completely until re-prompted.
79
- - **Shutdown** — when all work is complete: regenerate `progress.md`, open/update epic PRs to `main` for multi-feature epics and tag them (single-feature epics need none), run `bd dolt push`, then output the Pending Human Action / Needs Refinement / cap-blocked / Pending Epic Review summaries that apply, or "All beads complete."
103
+ - **HITL Pause** — when nothing is in flight (no stage, decomposition or expansion workers), nothing is dispatchable (nothing returned by `bd ready -l execution:afk`, including no ready, claimable chore-less task awaiting expansion), and `pending-gates.mjs` reports a non-empty `pendingHumanAction` (an unblocked `lifecycle:feature-pr` gate, or an epic tagged `awaiting-epic-pr-merge`; gates still parked behind their own pipeline do not count): open/update epic PRs to `main` for multi-feature epics and tag each epic `awaiting-epic-pr-merge` (single-feature epics need none — their feature PRs already target `main`), run the gated `bd dolt push`, output the Pending Human Action table, then stop completely until re-prompted.
104
+ - **Shutdown** — when all work is complete: open/update epic PRs to `main` for multi-feature epics and tag them (single-feature epics need none), run the gated `bd dolt push`, then output the Pending Human Action / Needs Refinement / cap-blocked / Pending Epic Review summaries that apply, or "All beads complete."
80
105
 
81
106
  ## Red Flags
82
107
 
83
108
  - Running as a background or delegated subagent instead of the interactive foreground agent.
84
109
  - Spawning a stage runner via {{TOOL:bash}} or running a stage inline instead of {{TOOL:task}}.
85
- - Substituting a backgrounded CLI run for a missing subagent tool — stop and report instead; that launch has no completion signal.
86
- - Advancing a parent on a worker's `OUTCOME: SUCCESS` without verifying the worktree — the report is a claim, not evidence.
110
+ - Closing a leaf execution bead, or creating a `stage:fix`/feedback bead — both belong to the worker.
111
+ - Creating a stage chore, or running `create-task` for an existing bead — the chain is pre-created and `create-task` would add a second parent.
112
+ - Re-dispatching a decomposition because "the feature still looks idle" — the children are blocked on the planning bead, which is Q5b working, not a failure. Never re-create the hierarchy.
113
+ - Reaching for a narrower dispatch query (`bd ready -t chore`, "chores with `stage:*`") — an `execution:afk` bead with no stage chores is work waiting for expansion, not work that does not exist.
114
+ - Loop counting from a stage runner's prose when the same fact is queryable from beads.
87
115
  - Editing bead files directly instead of using `bd` commands.
88
116
  - Auto-merging a PR, or continuing past a feature/epic gate before a human merge.
89
117
 
@@ -94,29 +122,40 @@ On each completion notification (a background agent finished):
94
122
  | "I'll just run this one stage inline" | An orchestrator that executes stages stops being an orchestrator — the review gates exist to catch exactly that shortcut. |
95
123
  | "One more task in flight won't hurt" | The 5-task cap bounds log polling, state bookkeeping, and PR sequencing; exceeding it loses track of in-flight work. |
96
124
  | "The review passed, so I can merge" | Feature and epic PR merges are human-controlled; the gate exists so a person sees every change. |
125
+ | "The worker left the chore open — I'll close it" | The worker owns that bead; an open one means it died mid-stage, so read its notes and re-dispatch instead of closing over the missing record. |
126
+ | "This bead has no chores — I'll create them as I go" | The whole chain is pre-created with `blocks` deps; hand-creating stages duplicates chores and loses the order. Expand with `create-chores.mjs` instead. |
127
+ | "That feature came back ready again, so I'll decompose it a second time" | The implementation children depend on the planning bead, so nothing is ready until a human closes it. Re-decomposing duplicates the hierarchy; idling *is* the correct outcome. |
97
128
 
98
129
  ## Philosophy / rationale
99
130
 
100
131
  - Orchestration state derives from beads so a crash loses nothing but an in-memory ID mapping: `state.json` holds only the agent-ID→bead mapping, never task state.
101
- - Classification happens up-front at planning time (`create-task`), so the loop can trust `bd ready` instead of re-interpreting each bead's intent.
132
+ - Every control-flow predicate — is anything in flight, is there work, is there room, may we pause or shut down — derives from `state.json`'s `inflight` (`kind: "stage"`, `kind: "decompose"` or `kind: "expand"`) plus `bd ready -l execution:afk`, never from a chore-type `bd` query: an expansion or decomposition worker owns no stage chore, so a chore-only predicate reports idle while an agent is running (REFERENCE.md, _The in-flight invariant_).
133
+ - One predicate answers both *who runs this* and *when*: `execution:afk` says it is agent work and the bead graph says it is ready, so ralph needs no label that encodes "not really work yet" — a childless feature is routed by its type, not excluded by a filter. Classification happens up-front at planning time (`create-task`), so the loop can trust the query instead of re-interpreting each bead's intent.
102
134
  - Human review gates are non-negotiable because agent-authored changes still need a person to merge them.
135
+ - One owner per lifecycle: the actor that did the work records the outcome, so beads never carry an outcome written by someone who was not there.
103
136
 
104
137
  ## Phase-gate checklists
105
138
 
106
- - [ ] Init complete: `bd prime` held, gitignore entries present, workspace and state.json created, pipeline.json read, first `bd ready` classified, first chores dispatched.
107
- - [ ] Event loop handed off: completion-detection mechanism running (or HITL Pause/Shutdown started) and `progress.md` regenerated.
139
+ - [ ] Init complete: `bd prime` held, gitignore entries present, workspace and state.json created, pipeline.json read, first `bd ready -l execution:afk` classified, first agent work dispatched (a stage chore, a decomposition worker or an expansion worker).
140
+ - [ ] Event loop handed off: completion-detection mechanism running (or HITL Pause/Shutdown started) — a decomposition- or expansion-only init is in flight, not idle.
141
+
142
+ ## See Also
108
143
 
109
- ## Cross-skill references
144
+ - [run-pipeline-stage](../run-pipeline-stage/SKILL.md) — owns the stage-runner prompt, per-stage playbooks, the `---REPORT---` format, and the worker's remediation chain. Read it before dispatching any stage.
145
+ - [create-task](../../planning/create-task/SKILL.md) — owns `pipeline.json` and the HITL gate beads; its `scripts/pending-gates.mjs` is the only home of the gate queries.
146
+ - [prd-to-tasks](../../planning/prd-to-tasks/SKILL.md) — load when the decomposition worker expands a feature into slices.
110
147
 
111
- - The `run-pipeline-stage` skill owns the stage-runner prompt, per-stage playbooks, the `---REPORT---` format, and fix-loop feedback beads — read it before dispatching any stage.
112
- - The `create-task` skill owns `pipeline.json` and creates the `lifecycle:feature-pr` HITL gate beads.
113
- - Do not invoke `classify-bead` from this loop — classification was already applied at planning time.
148
+ Do not invoke `classify-bead` from this loop — classification was applied at planning time.
114
149
 
115
150
  ## Verification checklist
116
151
 
117
- - [ ] Init ran once with observable results: `state.json` exists, `bd ready` was parsed, and the first chore beads are claimed.
152
+ - [ ] Init ran once with observable results: `state.json` exists, `bd ready -l execution:afk` was parsed, and agent work is in flight — a stage chore claimed, or a decomposition or expansion worker dispatched for a bead that needed one.
118
153
  - [ ] Every stage runner was spawned with {{TOOL:task}} from the parent's feature worktree, with the `---REPORT---` instruction in its prompt.
119
- - [ ] Every stage delivery was confirmed with `scripts/lib/verify-worker-tree.mjs` before the parent advanced, and no stage was dispatched from a session with no subagent tool.
120
- - [ ] In-flight count never exceeded 5, and fix loops respect `maxFixRounds` from `pipeline.json`.
154
+ - [ ] Every dispatch came from `bd ready -l execution:afk` — no narrower chore-only filter was used to decide that a bead was not work.
155
+ - [ ] A childless `execution:afk` feature was decomposed exactly once into a planning bead plus `execution:afk` children depending on it, and was not re-decomposed on later idle passes.
156
+ - [ ] In-flight count never exceeded 5, and the read-only cap backstop ran before every `stage:*` dispatch.
157
+ - [ ] Every in-flight, dispatchable-work, HITL-pause, and shutdown predicate was read from `state.json`'s `inflight` (stage, decomposition **and** expansion workers) plus `bd ready -l execution:afk`, with the ready, claimable scope of a chore-less `execution:afk` task bead — never from a chore-only `bd` query, and never counting a bead an open `lifecycle:feature-pr` gate blocks from being claimed.
158
+ - [ ] Ralph closed no leaf execution bead and created no fix bead; every closed chore carries its worker's close reason.
159
+ - [ ] Any chore-less `execution:afk` task bead was expanded with `create-chores.mjs` (one parent bead), never with `create-task`.
121
160
  - [ ] Feature and epic PRs were pushed and reported immediately at their gates, and nothing was auto-merged.
122
- - [ ] `bd dolt push` and a final `progress.md` regeneration ran before HITL Pause/Shutdown, and the chat received no empty poll updates.
161
+ - [ ] Every `bd dolt push` before HITL Pause/Shutdown exited 0 — a non-zero exit was retried once, then surfaced as a blocker (command, exit code, stderr) with no completion or Pending Human Action summary printed; status was reported from `bd` commands rather than a generated file, and the chat received no empty poll updates.
@@ -0,0 +1,134 @@
1
+ // Resolves which beads are waiting on a human, and which are merely parked
2
+ // behind their own pipeline.
3
+ //
4
+ // Ralph schedules new parent features only when nothing is pending human action.
5
+ // The distinction that matters is *unblocked*, not *open*: `create-chores`
6
+ // pre-creates a `lifecycle:feature-pr` gate for every planned feature, blocked
7
+ // behind that feature's own document chore. Such a gate is parked — the feature
8
+ // has not reached its PR stage — and must never stop dispatch. Only once the
9
+ // document chore closes does the gate unblock, and that is the state in which a
10
+ // feature genuinely awaits a human merge.
11
+ //
12
+ // Zero dependencies: run with `node pending-gates.mjs`.
13
+
14
+ import { execFile } from 'node:child_process';
15
+ import { promisify } from 'node:util';
16
+ import { pathToFileURL } from 'node:url';
17
+
18
+ /** The structural label every feature PR gate carries, whatever its axis. */
19
+ export const FEATURE_GATE_LABEL = 'lifecycle:feature-pr';
20
+
21
+ /** Epics whose PR into `main` awaits a human merge. */
22
+ export const EPIC_GATE_LABEL = 'awaiting-epic-pr-merge';
23
+
24
+ // Two-axis migration: gates created before the `execution:afk/hitl` migration
25
+ // carry `implementation-type:hitl`, gates created after carry `execution:hitl`.
26
+ // Both mean "a human must act", so the query matches either.
27
+ export const HITL_GATE_LABELS = ['execution:hitl', 'implementation-type:hitl'];
28
+
29
+ /** @typedef {{ id: string, title?: string }} Bead */
30
+ /** @typedef {{ id: string, title: string, kind: 'feature-pr' | 'epic-pr' }} PendingAction */
31
+
32
+ /**
33
+ * @typedef {object} GateState
34
+ * @property {PendingAction[]} pendingHumanAction Beads a human must act on now — non-empty means "do not schedule new parent features".
35
+ * @property {Array<{ id: string, title: string }>} parked Open gates still blocked behind their own pipeline; informational only.
36
+ */
37
+
38
+ /**
39
+ * Split open gates into those awaiting a human now and those still parked.
40
+ *
41
+ * @param {object} input
42
+ * @param {Bead[]} input.readyGates Open gates with no active blockers.
43
+ * @param {Bead[]} input.openGates Every open gate, blocked or not.
44
+ * @param {Bead[]} input.epicsAwaitingMerge Epics tagged `awaiting-epic-pr-merge`.
45
+ * @returns {GateState}
46
+ */
47
+ export function resolveGateState({ readyGates, openGates, epicsAwaitingMerge }) {
48
+ const actionable = new Set(readyGates.map((bead) => bead.id));
49
+
50
+ const pendingHumanAction = [
51
+ ...readyGates.map((bead) => pendingAction(bead, 'feature-pr')),
52
+ ...epicsAwaitingMerge.map((bead) => pendingAction(bead, 'epic-pr')),
53
+ ];
54
+
55
+ const parked = openGates
56
+ .filter((bead) => !actionable.has(bead.id))
57
+ .map((bead) => ({ id: bead.id, title: bead.title ?? '' }));
58
+
59
+ return { pendingHumanAction, parked };
60
+ }
61
+
62
+ /**
63
+ * @param {Bead} bead
64
+ * @param {'feature-pr' | 'epic-pr'} kind
65
+ * @returns {PendingAction}
66
+ */
67
+ function pendingAction(bead, kind) {
68
+ return { id: bead.id, title: bead.title ?? '', kind };
69
+ }
70
+
71
+ // BD_PATH env override lets machines where bd is not on PATH pin a location.
72
+ const BD_PATH = process.env.BD_PATH || 'bd';
73
+ const execFileAsync = promisify(execFile);
74
+
75
+ /** @type {(args: string[]) => Promise<string>} */
76
+ async function defaultExec(args) {
77
+ const { stdout } = await execFileAsync(BD_PATH, args, { encoding: 'utf-8' });
78
+ return stdout;
79
+ }
80
+
81
+ /**
82
+ * Query bd for the current gate state.
83
+ *
84
+ * @param {object} [options]
85
+ * @param {(args: string[]) => Promise<string>} [options.exec] bd runner; injectable for tests.
86
+ * @returns {Promise<GateState>}
87
+ */
88
+ export async function fetchGateState({ exec = defaultExec } = {}) {
89
+ const gateFilter = ['-l', FEATURE_GATE_LABEL, '--label-any', HITL_GATE_LABELS.join(',')];
90
+
91
+ // `bd ready` is blocker-aware: it returns only gates whose document chore has
92
+ // closed, i.e. the ones genuinely awaiting a human merge.
93
+ const readyGates = JSON.parse(await exec(['ready', '--json', ...gateFilter]));
94
+ const openGates = JSON.parse(await exec(['list', '--json', '--limit', '0', ...gateFilter]));
95
+ const epicsAwaitingMerge = JSON.parse(await exec(['list', '--json', '--limit', '0', '-l', EPIC_GATE_LABEL]));
96
+
97
+ return resolveGateState({ readyGates, openGates, epicsAwaitingMerge });
98
+ }
99
+
100
+ // ─── CLI ──────────────────────────────────────────────────────────────────────
101
+
102
+ const USAGE = 'Usage: node pending-gates.mjs\n\nPrints { pendingHumanAction, parked } as JSON.\n';
103
+
104
+ class UsageError extends Error {}
105
+
106
+ /**
107
+ * @param {object} options
108
+ * @param {string[]} options.argv CLI arguments (without node/script).
109
+ * @param {(args: string[]) => Promise<string>} [options.exec] bd runner; injectable for tests.
110
+ * @param {(chunk: string) => void} [options.write] stdout sink; injectable for tests.
111
+ * @returns {Promise<number>} process exit code.
112
+ */
113
+ export async function runCli({ argv, exec = defaultExec, write = (chunk) => process.stdout.write(chunk) }) {
114
+ if (argv.includes('--help') || argv.includes('-h')) {
115
+ write(USAGE);
116
+ return 0;
117
+ }
118
+ if (argv.length > 0) throw new UsageError(`unexpected argument: ${argv[0]}`);
119
+
120
+ write(`${JSON.stringify(await fetchGateState({ exec }), null, 2)}\n`);
121
+ return 0;
122
+ }
123
+
124
+ // Only run the CLI when invoked directly, so tests can import the pure resolver.
125
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
126
+ runCli({ argv: process.argv.slice(2) })
127
+ .then((code) => {
128
+ process.exitCode = code;
129
+ })
130
+ .catch((error) => {
131
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
132
+ process.exitCode = error instanceof UsageError ? 2 : 1;
133
+ });
134
+ }
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: run-pipeline-stage
3
- description: Execute a single pipeline stage for a bead (code, verify, review, document) via its playbook and dispatch rules, reporting the outcome in a fixed REPORT shape. Use when you want to "work through beads inline", "pick up a specific stage bead", or run one stage "without the full ralph orchestrator".
3
+ description: Execute a single pipeline stage for a bead (code, verify, review, document) via its playbook and read-only routing, reporting the outcome in a fixed REPORT shape. Use when you want to "work through beads inline", "pick up a specific stage bead", or run one stage "without the full ralph orchestrator".
4
4
  ---
5
5
 
6
6
  # Run Pipeline Stage
7
7
 
8
- Stage beads (`stage:code`, `stage:verify`, `stage:review`, `stage:document`, `stage:fix`) are created by the `create-task` skill from the pipeline definition in `skills/planning/create-task/pipeline.json`. This skill executes one stage at a time and reports the outcome.
8
+ Stage beads (`stage:code`, `stage:verify`, `stage:review`, `stage:document`, `stage:fix`) come from the pipeline definition in `skills/planning/create-task/pipeline.json`. This skill executes one stage and owns that bead's lifecycle: the runner that does the work appends its own notes, closes its own leaf execution bead on **both** outcomes, and builds its own remediation children when the stage fails. The orchestrator dispatches and routes — it never edits or closes a leaf bead.
9
9
 
10
10
  ## When to use
11
11
 
@@ -20,65 +20,66 @@ Stage beads (`stage:code`, `stage:verify`, `stage:review`, `stage:document`, `st
20
20
  - Creating or planning beads — use `create-task` or `plan`.
21
21
  - Exploratory bead bookkeeping without a stage — that is `bd-tool`.
22
22
 
23
+ ## Ownership split
24
+
25
+ | Actor | Owns |
26
+ |---|---|
27
+ | Stage runner (worker) | Milestone notes, progress-log lines, closing its leaf bead on both outcomes, remediation children, the REPORT |
28
+ | Orchestrator (ralph or you) | Claim, dispatch, forward routing, the read-only cap backstop, the PR gate |
29
+
30
+ A leaf bead is the worker's record of what happened. The orchestrator reads it; it does not write it.
31
+
23
32
  ## Workflow
24
33
 
25
34
  1. Run `bd prime` and hold the output; subagents can run it themselves if they need context.
26
35
  2. If no bead was specified, run `bd ready` and ask the user which to work on.
27
36
  3. Claim the bead with `bd update <id> --claim` — the bead, not the prompt, is the source of truth. Append a stage-start note immediately (see _Milestone Notes_).
28
37
  4. Read the bead's `stage:*` label — it names the stage to execute.
29
- 5. Load the universal stage-runner prompt (`skills/workflow/run-pipeline-stage/prompts/stage-runner.md`), populate `<stage>`, and read the matching playbook (`skills/workflow/run-pipeline-stage/playbooks/<stage>.md`) for stage-specific rules.
30
- 6. Tag the stage and regenerate the progress doc so pairing sessions stay current:
38
+ 5. Load the universal stage-runner prompt (`skills/workflow/run-pipeline-stage/prompts/stage-runner.md`) — it carries the lifecycle, remediation, and REPORT contract — populate `<stage>`, and read the matching playbook (`playbooks/<stage>.md`) for stage-specific rules.
39
+ 6. Tag the stage — beads are the only status view:
31
40
 
32
41
  ```bash
33
42
  bd tag <id> stage:<stage>
34
- # workspace must be the absolute path of the worktree — never . or $(pwd)
35
- workspace="/absolute/path/to/worktree"
36
- pnpm --prefix skills/workflow/run-pipeline-stage/scripts exec tsx generate-progress.ts --workspace "$workspace" > "$workspace/.agent-cortex/ralph/progress.md"
37
43
  ```
38
44
 
39
- 7. Dispatch one subagent per stage with the composed prompt — spawn it with {{TOOL:task}} and end the prompt with the REPORT contract below. A session with no subagent tool cannot dispatch: stop and say so rather than substituting a backgrounded CLI run, which has no completion signal.
45
+ 7. Dispatch one subagent per stage with the composed prompt — spawn it with {{TOOL:task}}. The prompt already ends with the REPORT contract; never compose one without it. A session with no subagent tool cannot dispatch: stop and say so rather than substituting a backgrounded CLI run, which has no completion signal.
40
46
  8. Verify the delivery against the worktree — `node scripts/lib/verify-worker-tree.mjs --worktree <abs-worktree> --base <base>` exits 0 only for a clean tree with a commit ahead of base. A worker whose REPORT claims `OUTCOME: SUCCESS` over a dirty tree has not delivered; re-dispatch it instead of advancing.
41
- 9. Route the REPORT through the Dispatch Rules: advance to the next stage, create a feedback bead, or close the parent.
47
+ 9. On the REPORT: route forward per _Routing_ below. Do **not** close the leaf bead — the worker closed it before reporting.
42
48
 
43
- Each step leaves observable state — a claimed bead, a `stage:` tag, a regenerated progress doc, a verified commit, and a REPORT that drives the next action.
49
+ Each step leaves observable state — a claimed bead, a `stage:` tag, worker notes and a closed bead, a verified commit, and a REPORT that drives the next action.
44
50
 
45
- ## Dispatch Rules
51
+ ## Routing (read-only)
46
52
 
47
- | Stage complete | Condition | Next action |
48
- |---|---|---|
49
- | `code` | — | Run **verify** |
50
- | `verify` | `OUTCOME: SUCCESS` | Run **review** |
51
- | `verify` | `OUTCOME: BLOCKED` | Create a `stage:fix` chore (see _Feedback Beads_) |
52
- | `review` | `OUTCOME: SUCCESS` | Run **document** |
53
- | `review` | `OUTCOME: BLOCKED` and fixRounds < maxFixRounds | Create a `stage:fix` chore; increment fixRounds |
54
- | `review` | `OUTCOME: BLOCKED` and fixRounds ≥ maxFixRounds | `bd update <parent-id> --status blocked --notes "max fix rounds reached"`; record for shutdown |
55
- | `document` | — | `bd close <id>` — done |
56
-
57
- `maxFixRounds` is read from `skills/planning/create-task/pipeline.json` (currently `4`). A fix chore re-runs the stage that failed — fix after verify → verify; fix after review → review.
53
+ The worker built anything this stage needed; routing picks up whatever `bd ready` returns.
58
54
 
59
- ## Feedback Beads
55
+ | Stage complete | Condition | Next action |
56
+ | `code` | `OUTCOME: SUCCESS` | Dispatch the ready `stage:verify` chore |
57
+ | `verify` | `OUTCOME: SUCCESS` | Dispatch the ready `stage:review` chore |
58
+ | `review` | `OUTCOME: SUCCESS` | Dispatch the ready `stage:document` chore |
59
+ | `fix` | `OUTCOME: SUCCESS` | Dispatch the ready re-run chore that was blocked on the fix |
60
+ | `document` | `OUTCOME: SUCCESS` | Open/update the feature PR and the HITL gate bead |
61
+ | `code` / `verify` / `review` / `fix` / `document` | `OUTCOME: BLOCKED` | Create nothing — the worker built `stage:fix` + a fresh instance of its own stage; dispatch the ready fix chore |
62
+ | any | parent status `blocked` | Nothing — the worker or the cap backstop blocked it; record it for shutdown |
60
63
 
61
- On stage failure, create a chore bead whose description carries the feedback so the orchestrator's dispatch path stays uniform — it just picks up whatever `bd ready` returns:
64
+ Cap backstop (read-only): before dispatching a `stage:*` chore, count the parent's fix rounds and, if already at `maxFixRounds` (`skills/planning/create-task/pipeline.json`, currently `4`), block the parent and create nothing:
62
65
 
63
66
  ```bash
64
- new_id=$(bd create "[<parent-id>] <title>" --type chore \
65
- --description "Requirements: see <parent-id> acceptance criteria (`bd show <parent-id>`).
66
-
67
- <feedback content from REPORT>" --priority <parent-priority> -q)
68
- bd tag $new_id stage:<next-stage>
69
- bd tag $new_id workflow:ralph
70
- bd dep add $new_id <parent-id> --type parent-child
67
+ fix_rounds=$(bd children <parent-id> --json | grep -c '"stage:fix"')
71
68
  ```
72
69
 
73
- Chore beads carry no required sections, so the feedback description must point at the
74
- parent/requirements bead (`<parent-id>`) rather than restating its acceptance criteria.
70
+ ## Remediation Children (worker-built)
71
+
72
+ On `OUTCOME: BLOCKED` the worker creates its own chain — a `stage:fix` chore carrying the feedback, plus a **fresh instance of the stage that failed**, blocked on the fix. A fresh instance is not optional: the failed chore is already closed, so the pre-created chain cannot re-verify a fix.
75
73
 
76
- | Triggering outcome | Suggested title | Next stage tag | Description content |
77
- |---|---|---|---|
78
- | `OUTCOME: BLOCKED` from verify | `Fix: verify failures` | `stage:code` | Full BLOCKING_ISSUES list |
79
- | `OUTCOME: BLOCKED` from review | `Fix: reviewer feedback` | `stage:fix` | Full BLOCKING_ISSUES list |
74
+ | Failed stage | Chain |
75
+ |---|---|
76
+ | `code` | `stage:fix` → fresh `stage:code` |
77
+ | `verify` | `stage:fix` → fresh `stage:verify` |
78
+ | `review` | `stage:fix` → fresh `stage:review` |
79
+ | `document` | `stage:fix` → fresh `stage:document` |
80
+ | `fix` | `stage:fix` → fresh `stage:fix` |
80
81
 
81
- Do not dispatch a new agent right after creating the feedback bead — it appears in `bd ready` on the next cycle and flows through the normal scheduling path.
82
+ Webbing, at cap, and the exact commands live in `prompts/stage-runner.md` and each playbook's _Remediation and close_ section. In short: both beads are children of the parent task (`--parent <parent-id>`), the fresh stage is `bd dep add <fresh> <fix> --type blocks`, and any not-yet-run later stage is re-blocked behind the fresh bead. Chores carry no required sections, so the feedback description points at the parent/requirements bead (`<parent-id>`) rather than restating its acceptance criteria.
82
83
 
83
84
  ## Progress Logging
84
85
 
@@ -106,23 +107,21 @@ bd update <id> --append-notes "[$(date -u +%Y-%m-%dT%H:%M:%SZ)] [<stage>] <what
106
107
 
107
108
  ## Report Format
108
109
 
109
- Every subagent prompt must end with the REPORT instruction:
110
-
111
- > End your response with a `---REPORT---` block in exactly this format:
112
- > ```
113
- > ---REPORT---
114
- > BEAD_ID: <id>
115
- > STAGE_COMPLETED: <code|verify|review|document>
116
- > SUMMARY: <2-3 sentence summary of what was done>
117
- > FILES_CHANGED: <comma-separated list, or "none">
118
- > COMMIT: <sha of the stage commit, or "none">
119
- > PUSHED: <yes|no>
120
- > PR: <feature PR url, or "none">
121
- > OUTCOME: <SUCCESS|BLOCKED>
122
- > BLOCKING_ISSUES: ← only if OUTCOME is BLOCKED
123
- > - <specific blocking issue>
124
- > ---
125
- > ```
110
+ Every stage-runner prompt ends with the literal REPORT instruction (see `prompts/stage-runner.md`):
111
+
112
+ ```
113
+ ---REPORT---
114
+ BEAD_ID: <id>
115
+ STAGE_COMPLETED: <code|verify|review|document|fix>
116
+ SUMMARY: <2-3 sentence summary of what was done>
117
+ FILES_CHANGED: <comma-separated list, or "none">
118
+ COMMIT: <sha of the stage commit, or "none">
119
+ PUSHED: <yes|no>
120
+ PR: <feature PR url, or "none">
121
+ OUTCOME: <SUCCESS|BLOCKED>
122
+ BLOCKING_ISSUES: ← only if OUTCOME is BLOCKED
123
+ - <specific blocking issue>
124
+ ```
126
125
 
127
126
  Subagents report facts — do not ask them to suggest or predict the next step. A REPORT claiming
128
127
  `OUTCOME: SUCCESS` with `PUSHED: no`, or a `COMMIT` that is not on the branch, records a failed
@@ -131,8 +130,9 @@ stage: the commit is the evidence, the report is the claim.
131
130
  ## Red Flags
132
131
 
133
132
  - Dispatching a subagent before tagging the stage — beads are the only source of truth for stage progress.
133
+ - Closing a leaf bead from the orchestrator — the worker closed it; a second close hides who owned the outcome.
134
+ - Creating a feedback or fix bead from the orchestrator — that is the worker's contract and bypasses its cap accounting.
134
135
  - Composing a subagent prompt without the REPORT contract — the output cannot be routed.
135
- - Creating a feedback bead and then dispatching anyway — bypasses the fix-round accounting and parent-child dependency graph.
136
136
  - Skipping the playbook "because the stage is simple" — playbooks carry the per-stage discipline the pipeline relies on.
137
137
  - Advancing on `OUTCOME: SUCCESS` without verifying the worktree — the commit is the evidence, the report is the claim.
138
138
  - Leaving bead notes to the end of the stage — a session that dies mid-stage then loses the whole trail.
@@ -140,34 +140,35 @@ stage: the commit is the evidence, the report is the claim.
140
140
  ## Common Rationalizations
141
141
 
142
142
  | "The stage is small — I'll just run it directly" | The stage skills and playbook keep output conformant; skipping them produces work that loops back as a fix chore. |
143
- | "I'll dispatch the fix right away — faster than a chore bead" | Feedback beads keep dispatch uniform and durable; direct re-dispatch breaks fix-round accounting and the dependency graph. |
144
- | "The stage is obvious from the prompt — no tag needed" | Beads are the source of truth; prompt drift desynchronises the progress doc, the log, and downstream dispatch. |
143
+ | "I'll close the chore — the worker forgot" | The worker closing it is the contract; an unclosed bead means the worker died, so read its notes and re-dispatch, do not paper over it. |
144
+ | "I'll wire the fix chain myself — faster" | Two owners of one lifecycle is what this skill exists to remove; worker-built chains keep cap accounting and the dependency graph truthful. |
145
+ | "The stage is obvious from the prompt — no tag needed" | Beads are the source of truth; prompt drift desynchronises the log and downstream dispatch. |
146
+
147
+ ## See Also
145
148
 
146
- ## Cross-skill references
149
+ - [create-task](../../planning/create-task/SKILL.md) — owns `pipeline.json`: stages, `maxFixRounds`, and the stage templates.
150
+ - [bd-tool](../../productivity/bd-tool/SKILL.md) — bead mechanics beyond the commands used here.
151
+ - [ralph](../ralph/SKILL.md) — runs many stage beads concurrently and consumes this skill's log and REPORT contracts.
147
152
 
148
- - `create-task` owns `pipeline.json` — stages, `maxFixRounds`, and the stage templates.
149
- - `bd-tool` covers bead mechanics beyond the commands in this skill.
150
- - `ralph` runs many stage beads concurrently and consumes this skill's log and REPORT contracts.
151
- - Playbooks delegate to stage skills: `tdd`/`style-code`/`style-tests` (code), `review-security` (review), `style-documentation` (document).
153
+ Each playbook delegates to a stage skill: `tdd`/`style-code`/`style-tests` (code, fix), `review-security` (review), `style-documentation` (document).
152
154
 
153
155
  ## Examples
154
156
 
155
- - Input: a `stage:verify` bead reporting `OUTCOME: BLOCKED` with two failing tests → Output: a `Fix: verify failures` chore tagged `stage:code` whose description lists both failures; verify closes and the chore is picked up on the next `bd ready` cycle.
156
- - Input: a `stage:document` bead reporting `OUTCOME: SUCCESS` → Output: the parent bead is closed with `bd close <id>` and that task's pipeline ends.
157
+ - Input: a `stage:verify` runner reporting `OUTCOME: BLOCKED` with two failing tests → Output: a `Fix (round 1)` chore plus a fresh `Verify (re-run 1)` chore blocked on it, `review` re-blocked behind the fresh verify, verify's own bead closed, and one `---REPORT---` block.
158
+ - Input: a `stage:document` runner reporting `OUTCOME: SUCCESS` → Output: document's bead already closed by the runner; the orchestrator opens the feature PR and updates the HITL gate bead.
157
159
 
158
160
  ## Philosophy / rationale
159
161
 
160
162
  - Beads hold all orchestration state — there is no separate state file to drift out of sync.
161
- - Subagents return facts in one fixed REPORT shape so routing stays mechanical across stages and harnesses.
162
- - Feedback as beads, not direct re-dispatches, puts every agent on a single scheduling path and keeps every decision visible in the dependency graph.
163
+ - Whoever does the work owns the record: a worker that closes its own bead leaves an auditable trail the orchestrator can only read.
164
+ - Self-contained remediation keeps the dependency graph truthful, so `bd ready` alone is enough to schedule the next step.
163
165
 
164
166
  ## Verification checklist
165
167
 
166
168
  - [ ] Bead claimed (`bd update <id> --claim`) before any executor works it.
167
- - [ ] `bd tag <id> stage:<stage>` run and progress doc regenerated before dispatch.
169
+ - [ ] `bd tag <id> stage:<stage>` run before dispatch.
168
170
  - [ ] Correct playbook read and followed for the stage; stage skills invoked where the playbook says.
169
- - [ ] Composed prompt ends with the complete REPORT contract block.
171
+ - [ ] Composed prompt carries the lifecycle, remediation, and REPORT contract from `prompts/stage-runner.md`.
170
172
  - [ ] Progress log lines written for every stage transition and key result.
171
173
  - [ ] Milestone notes appended at stage start and each milestone with `--append-notes` (not `--notes`).
172
- - [ ] REPORT routed per the Dispatch Rules — next stage, feedback bead, or `bd close <id>`.
173
- - [ ] Feedback beads carry the full BLOCKING_ISSUES content and the parent-child dependency.
174
+ - [ ] The orchestrator closed no leaf bead and created no fix bead; the cap backstop ran before any dispatch.