@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
@@ -4,8 +4,141 @@ Detailed procedures for the ralph orchestration workflow. See [SKILL.md](./SKILL
4
4
 
5
5
  ---
6
6
 
7
+ ## The in-flight invariant
8
+
9
+ Every ralph control-flow predicate — *is any agent work in flight?*, *is there work?*, *is there
10
+ room to dispatch?*, *may we pause?*, *may we shut down?* — is answered from `state.json`'s
11
+ `inflight` list (entries carry `kind: "stage"`, `kind: "decompose"` or `kind: "expand"`) plus
12
+ `bd ready -l execution:afk`. **Never** from a chore-type `bd` query, and never from "was a chore
13
+ dispatched?".
14
+
15
+ | Question | Derive it from | Never from |
16
+ |----------|----------------|------------|
17
+ | Is any agent work in flight? | `inflight` in `.agent-cortex/ralph/state.json` — stage, decomposition **and** expansion entries | `bd list -t chore`, `bd ready -t chore`, or any "were chores dispatched?" test |
18
+ | Is anything dispatchable? | `bd ready -l execution:afk`: a `stage:*` chore, a childless `execution:afk` `feature` bead to decompose, **or** a ready, claimable chore-less `execution:afk` task bead awaiting expansion | A chore listing alone — a ready, claimable childless feature or chore-less task is work waiting, not idle |
19
+ | Is there room under the 5-feature cap? | Parent count in `inflight` | A count of chore beads |
20
+ | May ralph pause or shut down? | `inflight` empty **and** nothing dispatchable (per the row above) | "No stage worker is running" |
21
+
22
+ **`execution:afk` is the one dispatch predicate.** It answers *whose work is this* for features,
23
+ tasks and chores alike, and the bead graph answers *when*. Ralph therefore never narrows the query
24
+ — "chores with `stage:*`" would report a ready childless feature or an unexpanded task as idle
25
+ while both are work waiting for a worker.
26
+
27
+ **Dispatchable means ready *and* claimable.** `bd ready -l execution:afk` decides ready; pending human action
28
+ decides claimable: while `pending-gates.mjs` reports an unblocked `lifecycle:feature-pr` gate, ralph
29
+ schedules no new parent features (_Feature PR gate_, step 6), so a queued unexpanded `execution:afk` bead in
30
+ that state is paused work, not dispatchable work. Scoping the predicate both ways is what makes HITL Pause
31
+ reachable in the canonical post-PR state — gate open, unexpanded `execution:afk` beads queued, `inflight`
32
+ empty, no ready `stage:*` chore — instead of re-arming a PI
33
+ wait over an empty agent set forever on an idle poll.
34
+
35
+ **Why:** an expansion or decomposition worker claims no chore. A chore-only predicate therefore
36
+ reports "nothing in flight" while an agent is running, which makes ralph pause or shut down
37
+ mid-expansion and leaves the parent's freshly created `stage:*` chain undispatched. The only
38
+ legitimate chore-type control-flow predicate in ralph is the retry counter in _Cap Backstop_
39
+ (`stage:fix` children): it counts remediation history rather than in-flight work, so it may gate a
40
+ dispatch decision but it must never answer *is anything in flight?*. Every other chore-type `bd`
41
+ query used as a control-flow predicate is a bug. Structural checks that ask nothing more than
42
+ *what does this bead already have?* — the _Expansion Guard_'s `grep -c '"stage:'`, the _Cap
43
+ Backstop_'s `stage:fix` count, the _Feature Decomposition_'s child count — are not predicates and
44
+ are fine.
45
+
46
+ ---
47
+
48
+ ## Expansion Guard
49
+
50
+ Stage chores are pre-created, never created on demand. `create-chores.mjs` (in `skills/planning/create-task/`) reads `pipeline.json` and creates the whole chain in one shot — `code` → `verify` → `review` → `document`, plus the `featurePrReview` HITL gate — with `blocks` deps that encode the order, and with the parent's priority and inherited labels. Ralph's dispatch is therefore always "claim what `bd ready -l execution:afk` returns".
51
+
52
+ A ready `execution:afk` task bead with **no** `stage:*` chore children has nothing to dispatch. Expand it, then dispatch the resulting `stage:code` chore:
53
+
54
+ 1. **Confirm it is chore-less** — a bead that already has stage chores is never expanded again:
55
+ ```bash
56
+ bd children <parent-id> --json | grep -c '"stage:'
57
+ ```
58
+ Expect `0` printed. `grep -c` exits `1` when it counts zero matches, so add `|| true` when the
59
+ check runs under `set -e` or inside an `&&` chain — the printed count is the answer, not the exit
60
+ status.
61
+ 2. **Dispatch an expansion worker** in the feature worktree (`.agent-cortex/worktrees/<parent-id>`) whose whole job is to run the pre-creator against the existing bead and report the JSON it printed:
62
+ ```bash
63
+ node <create-task-scripts>/create-chores.mjs \
64
+ --parent <parent-id> --priority <parent-priority>
65
+ ```
66
+ `<create-task-scripts>` is the absolute path to `skills/planning/create-task/scripts/`, resolved from wherever the skill was loaded — never hardcode one harness's install path. `<parent-priority>` is the parent's own priority from `bd show <parent-id>`, so chores match the task they belong to.
67
+ 3. **Record it in `inflight`** so its completion is attributable to the parent and it stays in the wait set — it has no chore, so `choreId` is `null`:
68
+ ```json
69
+ { "kind": "expand", "choreId": null, "parentId": "<parent-id>", "title": "<parent title>", "agentId": "<agent-id>", "logLine": 1 }
70
+ ```
71
+ 4. **Report the mapping** the worker returns — `code`, `verify`, `review`, `document`, `featurePrReview` — and close nothing. The worker owns no bead on this run; the expansion is bookkeeping, not a stage.
72
+ 5. **Dispatch normally.** The next `bd ready -l execution:afk` pass picks up the `stage:code` chore, and the pre-created chain carries the rest.
73
+ 6. **Handle the completion as an expansion completion**, not a stage completion — see below.
74
+
75
+ **Never expand an existing bead with `create-task`** — or with any other command that creates a bead. `create-task` creates a bead first and expands second, so running it for an existing bead leaves a **second parent** beside the original, which stays chore-less and never gets dispatched. The guard exists so an `execution:afk` task bead always ends with exactly one parent: `create-chores.mjs` expands a bead that already exists; only `create-task` creates parents.
76
+
77
+ **Labels on the chain.** Stage chores inherit `execution:afk` from their parent task bead, so they surface in ralph's `bd ready -l execution:afk` query without extra tagging — an expanded task never needs its chores relabelled. The `featurePrReview` HITL gate is the one exception: it declares its own `execution:hitl` + `lifecycle:feature-pr` labels and the script passes `--no-inherit-labels` for it, so it never picks up the parent's `execution:afk`.
78
+
79
+ ### Expansion Completion Contract
80
+
81
+ An expansion worker is dispatched like a stage worker but is **not** one. Nothing downstream of a stage dispatch applies to it:
82
+
83
+ | Stage worker | Expansion worker |
84
+ |------|------|
85
+ | Correlates to a claimed chore: `kind: "stage"` with a `choreId` | Holds no chore: `kind: "expand"`, `choreId: null` |
86
+ | Emits a `---REPORT---` block | Emits none — it prints the `create-chores.mjs` JSON mapping |
87
+ | Owns its leaf bead, which must read `closed` | Owns nothing — no bead to close, nothing to confirm |
88
+ | Completion advances the parent along the chain | Completion means "chores now exist" — dispatch the ready `stage:code` chore |
89
+
90
+ On completion, remove the entry from `inflight` and confirm the chore tree exists rather than taking the worker's word for it:
91
+
92
+ ```bash
93
+ bd children <parent-id> --json | grep -c '"stage:'
94
+ ```
95
+
96
+ Expect a non-zero count — one match per `stage:*` label in the chain. A printed `0` means the
97
+ expansion failed. Surface the worker's output in chat and record the parent for the shutdown summary — **never re-dispatch the expansion**, because `create-chores.mjs` is not idempotent and a second run duplicates the chain beside the first. Then continue at the normal dispatch pass: either way nothing is created and nothing is closed by ralph.
98
+
99
+ ---
100
+
101
+ ## Feature Decomposition
102
+
103
+ Epic Q2 makes ralph responsible for decomposing a feature bead into the hierarchy; Q5 makes a
104
+ feature `execution:hitl` by default. Both hold because the **label**, not the bead type, decides
105
+ routing: a feature is invisible to ralph while it carries `execution:hitl`, and a human exposes it
106
+ to ralph by relabelling it `execution:afk` when its delivery is genuinely agent-routable. Ralph
107
+ then decomposes it once and immediately goes idle behind the planning bead — Q5b's dependency gate
108
+ does the pausing, so no extra "ready to decompose" label is needed.
109
+
110
+ A ready `execution:afk` bead of type `feature` with **no** children is not dispatchable work.
111
+ Decompose it:
112
+
113
+ 1. **Confirm it is childless** — any existing child means the feature is already decomposed and this
114
+ procedure does not apply:
115
+ ```bash
116
+ bd children <feature-id> --json
117
+ ```
118
+ Expect an empty list `[]`. A non-empty list, however few children, means stop here.
119
+ 2. **Dispatch a decomposition worker** in the feature worktree (`.agent-cortex/worktrees/<feature-id>`) whose whole job is to run the `create-task` hierarchy flow (`prd-to-tasks` → `create-task`) for that one **existing** feature — its planning bead and impl children only, never a second feature bead — and report the IDs it created. The worker builds the Q5 shape:
120
+ - a **planning bead** — `--parent <feature-id>`, `execution:hitl` — held for a human to confirm planning is sufficient;
121
+ - **implementation task children** — `--parent <feature-id>`, `execution:afk`, `--no-inherit-labels` — each wired to wait on the planning bead with `bd dep add <impl-child> <planning-bead>`.
122
+
123
+ This is the shape `create-task` builds on its feature path (`SKILL.md` steps 5–6): an `execution:hitl` planning bead owned by the feature, whose impl children depend on it, so the dependency — not a label — is the readiness gate.
124
+ 3. **Record it in `inflight`** so its completion is attributable to the feature and it stays in the wait set — it holds no chore, so `choreId` is `null`:
125
+ ```json
126
+ { "kind": "decompose", "choreId": null, "parentId": "<feature-id>", "title": "<feature title>", "agentId": "<agent-id>", "logLine": 1 }
127
+ ```
128
+ 4. **Confirm the children exist** rather than trusting the report — the worker's IDs are a claim, the bead graph is the evidence:
129
+ ```bash
130
+ bd children <feature-id> --json
131
+ ```
132
+ Surface the created IDs in chat. An empty list means the decomposition failed: record the feature for the shutdown summary and continue — do not re-dispatch.
133
+ 5. **Never re-dispatch a decomposition.** The bead creation it runs is not idempotent, so a second run duplicates the planning bead and every implementation child beside the first. This is the same hazard as re-running `create-chores.mjs`.
134
+ 6. **Go idle.** After decomposition nothing is dispatchable for that feature: `bd ready -l execution:afk` still lists the feature itself (it now has children, so it is skipped — never decomposed again) but none of its children until a human closes the planning bead. Returning to the event loop with *nothing* to dispatch is the correct outcome, not a failure to re-expand — that is Q5b working as designed.
135
+
136
+ ---
137
+
7
138
  ## Dispatching a Chore Bead
8
139
 
140
+ Chores already exist, so dispatch never creates one:
141
+
9
142
  1. **Claim** the bead: `bd update <id> --claim`.
10
143
  2. **Read its `stage:*` label** from `bd show <id>`.
11
144
  3. **Load the universal stage runner prompt** from `skills/workflow/run-pipeline-stage/prompts/stage-runner.md`.
@@ -13,7 +146,7 @@ Detailed procedures for the ralph orchestration workflow. See [SKILL.md](./SKILL
13
146
  5. **Ensure branch + worktree exist for this parent task** (see _Feature branches and worktrees_ below), then note the worktree path — you'll pass it as `cwd` to {{TOOL:task}}.
14
147
  6. **Fill in the prompt** — replace placeholders with:
15
148
  - Stage from bead label (`stage:<stage>`) for `<stage>`
16
- - Chore bead ID and its `bd show` output for the bead specification. Do **not** inject `bd prime` output — the stage runner runs `bd prime` itself if it needs project context
149
+ - The leaf execution bead ID and its `bd show` output for the bead specification. Do **not** inject `bd prime` output — the stage runner runs `bd prime` itself if it needs project context
17
150
  - Parent task description from `bd show <parent-id>`
18
151
  - For `fix` stage: `FILES_CHANGED` from the preceding stage's report (the required changes come from the fix bead's own description — read via `bd show <fix-id>`)
19
152
  - For `verify`, `review`, `document` stages: `SUMMARY` and `FILES_CHANGED` from the preceding stage's report
@@ -55,6 +188,10 @@ For each parent task bead (`<parent-id>`):
55
188
  # <base> is epic/<epic-id> for multi-feature epics, origin/main for single-feature
56
189
  git worktree add .agent-cortex/worktrees/<parent-id> -b feature/<parent-id> <base>
57
190
  ```
191
+ **`<base>` is `epic/<epic-id>` or `origin/main` — never another `feature/*` branch.** If this
192
+ task depends on another unmerged task, its `blocks` edge already keeps it out of `bd ready`;
193
+ do not create the worktree early to get ahead, and never reuse a sibling task's worktree — that
194
+ silently stacks the branches and turns the dependency into a squash-merge conflict later.
58
195
  If `.agent-cortex/worktrees/<parent-id>` already exists, reuse it.
59
196
  5. All chores for this parent run in `.agent-cortex/worktrees/<parent-id>`. The `feature/<parent-id>` branch is the agent branch for HITL PRs.
60
197
 
@@ -64,7 +201,7 @@ For each parent task bead (`<parent-id>`):
64
201
 
65
202
  When the `document` chore for a parent task completes:
66
203
 
67
- 1. Close the `document` chore.
204
+ 1. Confirm the document worker closed its own chore (`bd show <id>` reads `closed`); do not close it yourself.
68
205
  2. Create or update a feature PR immediately from the agent branch to the feature branch (`feature/<parent-id>` into `epic/<epic-id>`; into `main` for single-feature epics):
69
206
  ```bash
70
207
  # <base> is epic/<epic-id> for multi-feature epics, main for single-feature
@@ -72,45 +209,56 @@ When the `document` chore for a parent task completes:
72
209
  ```
73
210
  If an open PR already exists, update it instead of creating a duplicate.
74
211
  3. Report the PR URL in chat as soon as it is created.
75
- 4. Find the child HITL task bead for this parent with label `lifecycle:feature-pr` (created by `create-task`).
212
+ 4. Find the child HITL task bead for this parent with label `lifecycle:feature-pr` and `execution:hitl` (created by `create-task`).
76
213
  5. Update that HITL bead with the PR URL/status (comment or note) so the reviewer has the link.
77
- 6. Do not schedule new parent features while this HITL PR gate bead remains open.
78
- 7. Once the PR is merged, a human closes the HITL PR gate bead. After that, close the parent feature bead:
214
+ 6. Do not schedule new parent features while this gate is **unblocked** — an unblocked gate is a feature genuinely awaiting a human merge (see _Gate predicate_ below).
215
+ 7. Once the PR is merged, a human closes the HITL PR gate bead, which unblocks the scheduling brake. After that, close the parent feature bead:
79
216
  ```bash
80
217
  bd close <parent-id>
81
218
  ```
82
219
  Only then continue with next parent features.
83
220
 
84
- ---
221
+ ### Gate predicate — parked vs pending
85
222
 
86
- ## Fix Loop
223
+ Ralph's only scheduling brake is a gate that is **unblocked**. `create-chores` pre-creates a `lifecycle:feature-pr` gate for *every* planned feature, blocked behind that feature's own `document` chore; such a gate is **parked** — the feature has not reached its PR stage — and must never stop dispatch. Only when the `document` chore closes does the gate unblock, and that is the state in which a human must merge.
87
224
 
88
- When a verify or review stage fails:
225
+ Resolve the question with one command instead of ad-hoc `bd` queries:
89
226
 
90
- 1. **Determine the parent task**: look up the chore bead's parent via `bd show <chore-id>` (follow the `parent-child` dependency).
91
- 2. **Count existing fix rounds**: list all chore beads that are children of the parent task with label `stage:fix`. The count of these (including closed ones) is the number of fix rounds already attempted.
92
- 3. **Read `maxFixRounds`** from `skills/planning/create-task/pipeline.json` (held in memory since initialization).
93
- 4. **If fix rounds ≥ maxFixRounds**: close the parent task bead as failed (`bd close <parent-id> --reason "Max fix rounds reached"`). Do not create another fix chore.
94
- 5. **Otherwise, create a fix chore** with the feedback in its description so the fixer agent can read it directly from `bd show`:
95
- ```bash
96
- fix_id=$(bd create "[<parent-id>] Fix (round <N>)" --type chore \
97
- --priority <same as parent> \
98
- --description "Requirements: see <parent-id> acceptance criteria (`bd show <parent-id>`).
227
+ ```bash
228
+ node skills/workflow/ralph/scripts/pending-gates.mjs
229
+ ```
99
230
 
100
- <CHANGES_REQUESTED list or VERIFY_FAILURES list from the triggering REPORT>" -q)
101
- bd tag $fix_id stage:fix
102
- bd dep add $fix_id <parent-id> --type parent-child # fix-chore is child of parent
103
- ```
104
- 6. **Find the verify chore** for this parent task (the chore with label `stage:verify` and a `parent-child` dep to the parent).
105
- 7. **Block the verify chore** on the new fix chore:
231
+ | Field | Meaning | Effect on ralph |
232
+ | --- | --- | --- |
233
+ | `pendingHumanAction` | Unblocked `lifecycle:feature-pr` gates (all blockers closed) plus epics tagged `awaiting-epic-pr-merge`, each as `{ id, title, kind }` | Non-empty → do **not** schedule new parent features; the same list is the **Pending Human Action** table |
234
+ | `parked` | Open gates still blocked behind their own pipeline | Informational only — never stops dispatch, never appears in the table |
235
+
236
+ Gate queries match the HITL axis on either `execution:hitl` (current) or `implementation-type:hitl` (legacy), so gates created on either side of the two-axis migration are counted.
237
+
238
+ **Invariant — what may block a gate.** `parked` means "blocked by its own pipeline". A gate blocked by its parent **feature** bead is not parked in any harness: that bead stays open until after the merge, so the gate never reaches `bd ready`, never appears in `pendingHumanAction`, and a human merge is silently never requested. Keep the two shapes apart:
239
+
240
+ - A `create-chores` gate unblocks exactly once, when its `document` chore closes. Until then it is parked and must not stop dispatch.
241
+ - A gate must never carry a `blocks` dependency onto its own feature bead (e.g. `bd create ... --labels ...lifecycle:feature-pr` then dep it to `<id>`). Remove it with `bd dep rm <gate> <id>` if present, so the gate is unblocked while its PR awaits merge.
242
+
243
+ So the predicate is sensitive to *what* blocks a gate, not only whether something does. It is ralph's only gate predicate on every harness: the Claude-native agent file that kept an open-gate form is retired, so nothing else restates a second predicate.
244
+
245
+ ---
246
+
247
+ ## Cap Backstop (read-only)
248
+
249
+ Ralph never builds remediation. The worker that fails a stage creates its own `stage:fix` chore, a fresh instance of the failed stage blocked on that fix, and re-blocks the later stages behind the fresh bead (see the `run-pipeline-stage` skill, _Remediation Children_). Ralph only guards the cap, and only reads:
250
+
251
+ 1. **Read `maxFixRounds`** from `skills/planning/create-task/pipeline.json` (held in memory since initialization).
252
+ 2. **Count existing fix rounds** for the parent — closed chores count:
106
253
  ```bash
107
- bd dep add <verify-id> $fix_id --type blocks # verify waits for fix
254
+ fix_rounds=$(bd children <parent-id> --json | grep -c '"stage:fix"')
108
255
  ```
109
- 8. **Reopen the verify chore**:
256
+ 3. **Before dispatching any `stage:*` chore of that parent**, if `fix_rounds >= maxFixRounds`: create nothing and block the parent, so a human sees it in the shutdown summary:
110
257
  ```bash
111
- bd reopen <verify-id>
258
+ bd update <parent-id> --status blocked \
259
+ --append-notes "[<ISO-timestamp>] max fix rounds reached (<fix_rounds>/<maxFixRounds>)"
112
260
  ```
113
- This ensures the fix chore runs first, then verify re-runs automatically when the fix closes.
261
+ 4. Ralph does **not** close the parent as failed and does **not** reopen or re-wire any chore — the worker already closed the failed leaf bead and the fresh stage bead is already blocked on its fix.
114
262
 
115
263
  ---
116
264
 
@@ -118,44 +266,43 @@ When a verify or review stage fails:
118
266
 
119
267
  Run whenever completion handling is triggered (an agent completion):
120
268
 
121
- 1. **Query in-flight beads**: `bd list --status=in_progress --type=chore`. Extract each bead's ID and title.
122
- 2. For each in-flight bead, read new lines from its **parent's** log file — logs are keyed by **parent** bead ID, so all stages of a feature share one file. Track the next unread line number per parent in memory, starting at 1:
269
+ 1. **Read in-flight entries**: `inflight` in `.agent-cortex/ralph/state.json` — every dispatched worker: stage (`kind: "stage"`), decomposition (`kind: "decompose"`) or expansion (`kind: "expand"`). Each entry carries `parentId` and `logLine`.
270
+ 2. For each in-flight entry, read new lines from its **parent's** log file — logs are keyed by **parent** bead ID, so all stages of a feature share one file:
123
271
  ```bash
124
- tail -n +<lastLine> .agent-cortex/ralph/ralph-<parent-id>.log 2>/dev/null
272
+ tail -n +<logLine> .agent-cortex/ralph/ralph-<parentId>.log 2>/dev/null
125
273
  ```
126
- 3. For each bead that has new lines:
274
+ 3. For each entry that has new lines:
127
275
  - **Post a chat summary** of new key events (stage transitions and notable events — not every line verbatim):
128
276
  ```
129
- 📋 [bead-id] <title>
277
+ 📋 [parent-id] <title>
130
278
  coding → verifying (or whatever transition)
131
279
  Tests: 12 passed, 0 failed
132
280
  ```
133
- - Update the in-memory line offset for that bead.
134
- 4. If no bead had new lines, post nothing — do not spam the chat with empty polls.
281
+ - Update `logLine` in `state.json` for that entry.
282
+ 4. If no entry had new lines, post nothing — do not spam the chat with empty polls.
135
283
 
136
284
  ---
137
285
 
138
286
  ## HITL Pause
139
287
 
140
- Proceed here when no chore beads are in-flight, no `stage:*` chore beads are ready, and HITL gate beads are pending (open `lifecycle:feature-pr` beads or epics tagged `awaiting-epic-pr-merge`). Ralph stops rather than burning requests on idle polls.
288
+ Proceed here when no agent work is in flight (no stage, decomposition or expansion workers in `inflight`), nothing is dispatchable (`bd ready -l execution:afk` returns no `stage:*` chore, no childless feature to decompose, and no ready, claimable chore-less `execution:afk` task bead 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` (see _Gate predicate_). Gates still parked behind their own pipeline do not count. Ralph stops rather than burning requests on idle polls.
141
289
 
142
- 1. Regenerate `.agent-cortex/ralph/progress.md` one final time — do not delete it.
143
- 2. For each **multi-feature** epic whose feature beads are all closed but not yet tagged `awaiting-epic-pr-merge`, open/update an epic PR to main (skip single-feature epics — their feature branch PRs already target `main`):
290
+ 1. For each **multi-feature** epic whose feature beads are all closed but not yet tagged `awaiting-epic-pr-merge`, open/update an epic PR to main (skip single-feature epics — their feature branch PRs already target `main`):
144
291
  ```bash
145
292
  gh pr create --base main --head epic/<epic-id> --title "[<epic-id>] Merge epic into main" --body "<epic summary>"
146
293
  ```
147
294
  Tag each epic bead with `awaiting-epic-pr-merge` until merged.
148
- 3. Run:
295
+ 2. Run:
149
296
  ```bash
150
297
  bd dolt push
151
298
  ```
152
- 4. Collect pending HITL gate beads and their PR URLs:
299
+ **Gate on the exit status.** Non-zero: retry once, then stop and report the command, exit code and stderr as a sync blocker — no Pending Human Action table, and ralph does not claim a clean pause.
300
+ 3. Collect the table rows from the script's `pendingHumanAction` list:
153
301
  ```bash
154
- bd list -l lifecycle:feature-pr -l implementation-type:hitl
155
- bd list -l awaiting-epic-pr-merge
302
+ node skills/workflow/ralph/scripts/pending-gates.mjs
156
303
  ```
157
- For each bead, run `bd show <id>` to retrieve the PR URL from bead notes.
158
- 5. Output the **Pending Human Action** summary:
304
+ For each entry, run `bd show <id>` to retrieve the PR URL from bead notes. `kind: "feature-pr"` rows read "review and merge the feature PR"; `kind: "epic-pr"` rows read "review and merge the epic PR into main".
305
+ 4. Output the **Pending Human Action** summary:
159
306
  ```
160
307
  ⏸️ Ralph is paused — human action required before work can continue.
161
308
 
@@ -167,25 +314,25 @@ Proceed here when no chore beads are in-flight, no `stage:*` chore beads are rea
167
314
 
168
315
  When you've completed the above, prompt me to continue.
169
316
  ```
170
- 6. **Stop completely.** Do not continue the event loop. Wait for the user to re-prompt before doing any further work.
317
+ 5. **Stop completely.** Stop the wake mechanism as the wake section describes. Do not continue the event loop. Wait for the user to re-prompt before doing any further work.
171
318
 
172
319
  ---
173
320
 
174
321
  ## Shutdown
175
322
 
176
- When `bd list --status=in_progress --type=chore` returns no results AND `bd ready` returns no chore beads with `stage:*` labels:
323
+ When nothing is in flight AND nothing is dispatchable — `inflight` holds no entries, `bd ready -l execution:afk` returns nothing (no `stage:*` chore, no childless feature to decompose, no ready, claimable chore-less task bead awaiting expansion) (_The in-flight invariant_ above):
177
324
 
178
- 1. Regenerate `.agent-cortex/ralph/progress.md` one final time — do not delete it.
179
- 2. For each **multi-feature** epic whose feature beads are all closed, open/update an epic PR to main (skip single-feature epics — no epic branch exists):
325
+ 1. For each **multi-feature** epic whose feature beads are all closed, open/update an epic PR to main (skip single-feature epics — no epic branch exists):
180
326
  ```bash
181
327
  gh pr create --base main --head epic/<epic-id> --title "[<epic-id>] Merge epic into main" --body "<epic summary>"
182
328
  ```
183
329
  Tag each epic bead with `awaiting-epic-pr-merge` until merged.
184
- 3. Run:
330
+ 2. Run:
185
331
  ```bash
186
332
  bd dolt push
187
333
  ```
188
- 4. If any HITL beads were noted during the session, output:
334
+ **Gate on the exit status.** Non-zero: retry once, then stop and report the command, exit code and stderr as a sync blocker — no completion summary, no "All beads complete.", and the remaining shutdown steps are not run.
335
+ 3. If any HITL beads were noted during the session, output:
189
336
  ```
190
337
  All agent work is complete. The following steps require human action before work can continue:
191
338
 
@@ -206,20 +353,27 @@ When `bd list --status=in_progress --type=chore` returns no results AND `bd read
206
353
 
207
354
  ## State Files
208
355
 
356
+ Status is read from beads — there is no rendered status document to build or refresh:
357
+
358
+ ```bash
359
+ bd list --parent <parent-id> # every chore for a feature, with its state
360
+ bd ready -l execution:afk # the next dispatchable work
361
+ bd show <id> # full detail, including the worker's notes
362
+ ```
363
+
209
364
  | File | Purpose |
210
365
  |------|---------|
211
- | `.agent-cortex/ralph/progress.md` | Human-readable snapshot. Regenerate: `workspace="/abs/path"; pnpm --prefix skills/workflow/run-pipeline-stage/scripts exec tsx generate-progress.ts --workspace "$workspace" > "$workspace/.agent-cortex/ralph/progress.md"`. `workspace` must be an **absolute** path — never `.` or `$(pwd)`. **Never hand-edit.** |
212
- | `.agent-cortex/ralph/state.json` | Runtime bookkeeping only: the in-flight agent-ID→bead mapping. Shape: `{ "inflight": [ { "choreId": "...", "parentId": "...", "title": "...", "agentId": "...", "logLine": 1 } ] }`. Initialise at startup with `{ "inflight": [] }`. Update after every dispatch and every agent completion. **Never hand-edit.** |
366
+ | `.agent-cortex/ralph/state.json` | Runtime bookkeeping only: the in-flight agent-ID→bead mapping. Shape: `{ "inflight": [ { "kind": "stage", "choreId": "...", "parentId": "...", "title": "...", "agentId": "...", "logLine": 1 } ] }`. A decomposition worker is recorded with `"kind": "decompose"` and an expansion worker with `"kind": "expand"`, both with `"choreId": null` — they hold no chore but still occupy the wait set and the in-flight check. Initialise at startup with `{ "inflight": [] }`. Update after every dispatch and every agent completion. **Never hand-edit.** |
213
367
  | `.agent-cortex/ralph/ralph-*.log` | Per-parent log files written by subagents — every stage chore of a feature appends to `.agent-cortex/ralph/ralph-<parent-id>.log` (e.g. `ralph-abc-123.log`). |
214
368
 
215
369
  All task state is derived from beads; `state.json` holds only runtime bookkeeping:
216
370
 
217
371
  | Question | How to answer |
218
372
  |----------|---------------|
219
- | What is in-flight? | `bd list --status=in_progress --type=chore` |
220
- | What is ready? | `bd ready` — filter for chores with `stage:*` labels |
373
+ | What is in-flight? | The `inflight` entries in `.agent-cortex/ralph/state.json` — `kind: "stage"` for a dispatched stage chore, `kind: "decompose"` for a feature-decomposition worker, `kind: "expand"` for an expansion worker. Decomposition and expansion workers hold no chore, so beads alone under-report in-flight work. |
374
+ | What is ready? | `bd ready -l execution:afk` — the single dispatch predicate. Each result is routed by its shape: a childless `feature` bead is decomposed (_Feature Decomposition_), a bead with no `stage:*` children is expanded (_Expansion Guard_), a `stage:*` chore is dispatched. |
221
375
  | What stage is a bead in? | Read the `stage:*` label from `bd show <id>` |
222
376
  | Which agent-ID maps to which bead? | `inflight` entries in `.agent-cortex/ralph/state.json` |
223
- | How many fix rounds? | Count chore beads with label `stage:fix` that are children of the parent task. Read `maxFixRounds` from `skills/planning/create-task/pipeline.json`. |
224
- | Which features are review-gated? | Find open child task beads labelled `lifecycle:feature-pr` and `implementation-type:hitl` |
377
+ | How many fix rounds? | Count chore beads with label `stage:fix` that are children of the parent task (`bd children <parent-id> --json | grep -c '"stage:fix"'`). Read `maxFixRounds` from `skills/planning/create-task/pipeline.json`. Read-only: used for the cap backstop, never to build remediation. |
378
+ | Which features are review-gated? | `pendingHumanAction` entries with `kind: "feature-pr"` from `pending-gates.mjs` — unblocked `lifecycle:feature-pr` gates on either HITL axis. A gate in `parked` is pre-created but not yet actionable |
225
379
  | Which epics are review-gated? | `bd list -l awaiting-epic-pr-merge` |