@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,4 +1,8 @@
1
- ## Spawning subagents (PI)
1
+ ## Wake mechanism (PI — blocking wait)
2
+
3
+ **Mechanism: a blocking wait — `wait_for_agents` blocks until at least one background worker finishes and returns its result inline, so the wait itself is the completion signal and no timer, sleep, or poll loop exists.**
4
+
5
+ ### Spawn
2
6
 
3
7
  RALPH HAS ONLY ONE WAY TO SPAWN SUBAGENTS: call the **`task`** tool (not bash, not any other tool).
4
8
 
@@ -10,7 +14,7 @@ Example:
10
14
  ```
11
15
  Calling tool 'task' with arguments: { "prompt": "...", "cwd": ".agent-cortex/worktrees/abc-123" }
12
16
  ```
13
- The response is a plain agent ID string (e.g. `agent-550e8400-e29b-41d4-a716-446655440000`). Store it in memory — you need it later to wait for the result.
17
+ The response is a plain agent ID string (e.g. `agent-550e8400-e29b-41d4-a716-446655440000`). Store it in memory and in `state.json` — you need it later to wait for the result.
14
18
 
15
19
  **`wait_for_agents`** — Block until at least one background sub-agent completes. This is the primary way to get results back.
16
20
  - `agentIds` (string[], required): The agent IDs returned by `task` to wait on.
@@ -31,25 +35,20 @@ Rules:
31
35
  - ALWAYS set `cwd` to the feature worktree path when running stage chores.
32
36
  - ALWAYS keep the returned `agentId` in memory to wait on it / read its result later.
33
37
 
34
- ## Completion detection (PI)
38
+ ### Completion arrival
35
39
 
36
- PI detects subagent completion with a blocking wait, not polling: after dispatching, call `wait_for_agents` with every in-flight agent ID. It returns as soon as at least one agent completes, with that agent's result ready to process. Do not `sleep`, do not start background timers — the wait tool IS the completion mechanism.
40
+ A completion arrives **in the wait response**: `wait_for_agents` returns as soon as one worker finishes, carrying that worker's result inline, so you never go looking for it. Apply the shared completion handling in the **Event loop** section of agent.md (the result is included in the wait response, or re-read with `read_agent`; re-read state.json and branch on the entry's `kind` — `stage` parses the REPORT and confirms the worker closed its chore, `expand` confirms the parent now has `stage:*` chores and dispatches the ready `stage:code` — then check for newly ready beads and the shutdown check). An expansion worker is in the wait set but is never treated as a chore: it emits no REPORT and needs no close confirmation.
37
41
 
38
- ### Wait loop lifecycle
42
+ ### Id tracking
39
43
 
40
- - **Dispatch-and-wait** — during initialization, dispatch up to 5 AFK chore subagents with `task` and hold their agent IDs (recorded in `state.json`'s `inflight` list).
41
- - **Wait** — call `wait_for_agents` with the agent IDs of every in-flight chore (`timeout` defaults to 120s). The tool blocks until at least one finishes. For each completed agent:
42
- 1. Flush its log tail if it has new lines (see _Log polling_ below) to surface progress to chat.
43
- 2. Apply the shared completion handling in the **Event loop** section of agent.md (the result is included in the wait response, or re-read with `read_agent`; re-read state.json, parse the REPORT, close the chore, advance the parent, check for newly ready beads, run the shutdown check).
44
- 3. Drop the completed agent ID from the wait set.
45
- - **Repeat** — dispatch replacements for completed chores (up to 5 in flight), add their new IDs to the wait set, and call `wait_for_agents` again with the remaining + new IDs.
46
- - **Timeout / STILL RUNNING** — if the timeout elapses with agents still working, the tool returns those agents as STILL RUNNING (with `timed out` noted). Call `wait_for_agents` again with the same IDs — the still-running agents keep working; you never re-dispatch them. `read_agent` remains available to re-read a completed result at any time.
47
- - **Abort** — if the user aborts, `wait_for_agents` returns immediately with what is known so far (no hang); do not re-issue the wait.
48
- - **Stop** — when stopping completely (HITL Pause or Shutdown) there is no timer to kill on PI: just stop calling `wait_for_agents`. Never start background `sleep` timers for completion detection.
44
+ Initialize `.agent-cortex/ralph/state.json` as `{ "timerShellId": null, "inflight": [] }`. Only one handle matters here:
49
45
 
50
- ## Log polling
46
+ - **inflight[].agentId** — the ID `task` returned for that worker; it is the argument `wait_for_agents` takes, the identifier for a `read_agent` fallback, and the key the completion is correlated to its bead.
47
+ - **timerShellId** — stays `null` on PI forever: the blocking wait replaces a poll timer, so nothing is ever recorded there.
51
48
 
52
- Run this procedure each time `wait_for_agents` returns (or whenever a new agent is dispatched):
49
+ ### Log flush
50
+
51
+ Flush new log lines as part of handling each wait result — that is when the loop wakes, and a worker's final lines arrive with the completion. Run this procedure each time `wait_for_agents` returns (or whenever a new agent is dispatched):
53
52
 
54
53
  1. **Query in-flight beads**: read `inflight` from `state.json`. Each entry has a `parentId` and `logLine`.
55
54
  2. For each in-flight entry, read new lines from its log file:
@@ -66,9 +65,25 @@ Run this procedure each time `wait_for_agents` returns (or whenever a new agent
66
65
  - Update `logLine` in `state.json` for that entry.
67
66
  4. If no entry had new lines, post nothing — do not spam the chat with empty polls.
68
67
 
69
- ## Polling constraints
68
+ ### Wait loop lifecycle
69
+
70
+ - **Dispatch-and-wait** — during initialization, dispatch up to 5 AFK chore subagents with `task` (or an expansion worker for a chore-less AFK bead) and hold their agent IDs (recorded in `state.json`'s `inflight` list; expansion entries carry `kind: "expand"` and `choreId: null`).
71
+ - **Wait** — call `wait_for_agents` with the agent IDs of every in-flight agent, stage worker or expansion worker (`timeout` defaults to 120s). The tool blocks until at least one finishes. For each completed agent:
72
+ 1. Flush its log tail if it has new lines (see _Log flush_ above) to surface progress to chat.
73
+ 2. Apply the shared completion handling described under _Completion arrival_ above.
74
+ 3. Drop the completed agent ID from the wait set.
75
+ - **Repeat** — dispatch replacements for completed work (up to 5 in flight), add their new IDs to the wait set, and call `wait_for_agents` again with the remaining + new IDs. A completed expansion leaves a slot to fill with its parent's newly ready `stage:code` chore.
76
+ - **Empty wait set** — never call `wait_for_agents` with an empty `agentIds` list. When handling a completion leaves `inflight` empty, run the event loop's final check (agent.md, _If nothing remains in flight_): a ready `stage:*` chore, or a ready, claimable chore-less AFK task bead (expand it first), is dispatchable — dispatch it and wait again. With nothing dispatchable, pending HITL gate beads mean **HITL Pause** and none mean **Shutdown**; either way stop calling `wait_for_agents` and act again only when the user re-prompts.
77
+ - **Timeout / STILL RUNNING** — if the timeout elapses with agents still working, the tool returns those agents as STILL RUNNING (with `timed out` noted). Call `wait_for_agents` again with the same IDs — the still-running agents keep working; you never re-dispatch them. `read_agent` remains available to re-read a completed result at any time.
78
+ - **Abort** — if the user aborts, `wait_for_agents` returns immediately with what is known so far (no hang); do not re-issue the wait.
79
+
80
+ ### Stop
81
+
82
+ Nothing to kill: stopping means simply **stop calling `wait_for_agents`**. There is no timer, so there is no shellId to kill and nothing to unset — just do not issue another wait. Never start background `sleep` timers as a substitute for the wait, and never re-issue a wait once the HITL pause or shutdown condition has been met.
83
+
84
+ ### Waiting constraints
70
85
 
71
- - **Always** keep a `wait_for_agents` call outstanding while agents are in-flight — never let running agent work stall without a wait active.
86
+ - **Always** keep a `wait_for_agents` call outstanding while agents are in-flight — stage workers and expansion workers alike. Never let running agent work stall without a wait active.
72
87
  - **Never** re-dispatch an agent that is merely STILL RUNNING — wait again on the same ID.
73
- - **Never** start `sleep` / background timer loops for completion detection on PI — `wait_for_agents` replaces them. There is nothing to kill on HITL Pause for PI.
74
- - **Never** post empty poll updates to chat — only surface new log content.
88
+ - **Never** start `sleep` / background timer loops for completion detection on PI — `wait_for_agents` replaces them, and there is nothing to kill on HITL Pause.
89
+ - **Never** post empty poll updates to chat — only surface new log content.
@@ -51,23 +51,35 @@ Update the top-level bead's `design` field with a high-level implementation plan
51
51
  ### 6. Decompose into tasks
52
52
  For large workstreams (multiple distinct areas) invoke the **prd-to-tasks** skill. For a single self-contained task invoke **create-task**. Pass the full `bd prime` output and any relevant design context from the `design` field to each skill.
53
53
 
54
- For each new feature bead and each new task bead, create a HITL planning gate before handoff. The feature/task bead depends on this gate and stays blocked until the user explicitly confirms planning is sufficient **for that specific feature/task**.
54
+ **Planning gate.** Each feature carries exactly one HITL planning bead — the design gate that keeps the feature's implementation children out of `bd ready` until a human confirms planning is sufficient. It is the bead `create-task` builds on its feature path: that skill's steps 5–6 are the authority for this shape, so when you delegate the feature to `create-task` the gate already exists and you must not create a second one.
55
55
 
56
- Every planning gate description must be cold-start-ready so another person can pick it up without prior chat context. Include all of: (1) what is being built and why, (2) decisions already made, (3) open questions/risks, and (4) references (bead IDs, files, or docs) used during planning.
56
+ Ownership is `--parent`; ordering is `bd dep add`. The planning bead is **owned by the feature** and **blocks every implementation child** of that feature. The feature never depends on its own gate — a container that waits on its own child is neither owner nor ordering.
57
+
58
+ Every planning bead description must be cold-start-ready so another person can pick it up without prior chat context. Include all of: (1) what is being built and why, (2) decisions already made, (3) open questions/risks, and (4) references (bead IDs, files, or docs) used during planning.
59
+
60
+ Both routes above create the gate for you, so this block is the shape to build by hand only when the feature already exists and `bd children <feature-id>` lists no `Plan:` child. Never run it beside a gate `create-task` already made: bead creation is not idempotent, so a second run leaves two design gates blocking the same children. The guard is check-then-act and therefore not atomic — two planners on one feature at the same instant could both pass it and create a gate each; that is acceptable because the only automated creation path goes through `create-task`, this agent runs as a single interactive HITL session, and a stray second planning bead carries no `lifecycle:feature-pr`, so ralph never pauses on it.
57
61
 
58
62
  ```bash
59
- gate_id=$(bd create "Plan: <feature title>" --type task --description "<planning context, decisions, open questions, and references>
63
+ # Design gate: human-owned, owned by the feature, blocking every implementation child.
64
+ planning_id=$(bd create "Plan: <feature title>" --type task --priority <priority> \
65
+ -l execution:hitl --parent <feature-id> --no-inherit-labels \
66
+ --description "<planning context, decisions, open questions, and references>
60
67
 
61
68
  ## Acceptance Criteria
62
69
 
63
- - [ ] User confirms planning is sufficient for this feature/task." --validate)
64
- bd tag <planning-gate-id> implementation-type:hitl
65
- bd dep add <feature-or-task-id> <planning-gate-id> # feature/task depends on planning gate (gate blocks implementation)
70
+ - [ ] The user confirms planning is sufficient for this feature." --validate --silent)
71
+
72
+ # Readiness gate: every implementation child waits on the design gate.
73
+ bd dep add <impl-task-id> <planning-bead-id>
66
74
  ```
67
75
 
68
- Do not close planning gates in bulk. Only close a gate after the user explicitly confirms that exact feature/task is ready to implement; leave all unconfirmed gates open and blocking.
76
+ `--no-inherit-labels` is not optional: `bd` copies a parent's labels at create time, so without it a gate under an `execution:afk` feature picks up `execution:afk` beside its own `execution:hitl` and stops routing as human work.
77
+
78
+ A planning bead is **not** a PR gate and carries no `lifecycle:` label. `create-chores.mjs` owns the `lifecycle:feature-pr` gate — owned by the implementation task, blocked by its `document` chore (the `create-task` skill's `REFERENCE.md` → PR gate bead); creating one here would put a second, differently-wired gate on the same bead. A standalone task bead needs no planning bead: `create-task` classifies it, and its human checkpoint is that PR gate.
79
+
80
+ Do not close planning gates in bulk. Only close a gate after the user explicitly confirms that exact feature is ready to implement; leave all unconfirmed gates open and blocking.
69
81
 
70
- Before handing off, ensure every bead created in this step carries an `implementation-type` label — check `bd label list <id>` yourself. Do not spawn `classify-bead` here: planning gates were tagged inline above and `create-task` classifies its beads internally. Only invoke it for a bead that genuinely lacks both the label and a `## Type` field. Then run `bd lint <id>` for every bead created in this step and fix any missing sections before handoff.
82
+ Before handing off, ensure every bead created in this step carries an `execution:` label — check `bd label list <id>` yourself. Do not spawn `classify-bead` here: planning gates are labelled inline above and `create-task` classifies its beads internally. Only invoke it for a bead that genuinely lacks both the label and a `## Type` field. Then run `bd lint <id>` for every bead created in this step and fix any missing sections before handoff.
71
83
 
72
84
  Tag every bead created in this step with `workflow:ralph`:
73
85
 
@@ -95,12 +107,12 @@ bead against the full backlog — a P3 feature that blocks others may need a hig
95
107
  explicit priority than a standalone P4 feature.
96
108
 
97
109
  ### 7. Agree with the user
98
- Present the bead list (IDs, titles, one-line rationale each) plus planning gate status for each item using `✅` (confirmed/closed) or `⏳` (awaiting confirmation/open). Ask the user to confirm or request changes before finishing.
110
+ Present the bead list (IDs, titles, one-line rationale each) plus the planning-gate status of each feature using `✅` (confirmed/closed) or `⏳` (awaiting confirmation/open). Ask the user to confirm or request changes before finishing.
99
111
 
100
- If any planning gates remain open, include an explicit warning that those features/tasks are still blocked and cannot be handed off to ralph yet. Iterate until approved.
112
+ If any planning gate remains open, include an explicit warning that its implementation children are still blocked by it and cannot be handed off to ralph yet. Iterate until approved.
101
113
 
102
114
  ### 8. Hand off to ralph
103
- Once approved, report: "Plan complete — `bd ready` will show the first tasks for ralph."
115
+ Once approved, report: "Plan complete — `bd ready -l execution:afk` will show the first tasks for ralph."
104
116
 
105
117
  ## Exploration sub-agent instructions
106
118
 
@@ -2,8 +2,13 @@
2
2
 
3
3
  import { parseArgs, buildHelpText, validateHarness } from "../lib/cli.mjs";
4
4
  import { join, dirname } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { readFile } from "node:fs/promises";
5
7
  import { installPi, registerPi, sweepLegacyPiUserDirs } from "./installers/pi.mjs";
6
8
 
9
+ /** @typedef {import("./installers/pi.mjs").InstallPiResult} InstallPiResult */
10
+ /** @typedef {import("./installers/pi.mjs").RegisterPiResult} RegisterPiResult */
11
+
7
12
  const argv = process.argv.slice(2);
8
13
  const parsed = parseArgs(argv);
9
14
 
@@ -12,6 +17,41 @@ if (parsed.command === "help") {
12
17
  process.exit(0);
13
18
  }
14
19
 
20
+ /**
21
+ * Read the version of the package this CLI ships in: `bin/` sits one level below
22
+ * the package root, in the repo checkout and in the published tarball alike.
23
+ * Resolved from this file's own location, never from the cwd or node_modules
24
+ * resolution, so an installed CLI reports the version it was installed at.
25
+ * Throws when that manifest is missing, unreadable, malformed, or has no version
26
+ * string, so a broken install never prints a bogus version with a success exit.
27
+ * @returns {Promise<string>}
28
+ */
29
+ async function readPackageVersion() {
30
+ const manifestPath = join(dirname(fileURLToPath(import.meta.url)), "..", "package.json");
31
+ /** @type {unknown} */
32
+ let manifest;
33
+ try {
34
+ manifest = JSON.parse(await readFile(manifestPath, "utf-8"));
35
+ } catch (err) {
36
+ throw new Error(`Cannot read the package version from ${manifestPath}: ${/** @type {Error} */ (err).message}`);
37
+ }
38
+ const version = /** @type {{ version?: unknown }} */ (manifest).version;
39
+ if (typeof version !== "string" || version === "") {
40
+ throw new Error(`Cannot read the package version from ${manifestPath}: the manifest has no "version" string.`);
41
+ }
42
+ return version;
43
+ }
44
+
45
+ if (parsed.command === "version") {
46
+ try {
47
+ process.stdout.write(`${await readPackageVersion()}\n`);
48
+ } catch (err) {
49
+ process.stderr.write(`${/** @type {Error} */ (err).message}\n`);
50
+ process.exit(1);
51
+ }
52
+ process.exit(0);
53
+ }
54
+
15
55
  if (parsed.command === "unknown") {
16
56
  process.stderr.write(`Unknown command: ${parsed.name}\nRun "agent-cortex --help" for usage.\n`);
17
57
  process.exit(1);
@@ -66,7 +106,7 @@ if (parsed.command === "install") {
66
106
  process.stdout.write(` → register it with pi: pi install ${result.output}\n`);
67
107
  }
68
108
  } catch (err) {
69
- process.stderr.write(`Install failed: ${err.message}\n`);
109
+ process.stderr.write(`Install failed: ${/** @type {Error} */ (err).message}\n`);
70
110
  process.exit(1);
71
111
  }
72
112
  process.exit(0);
@@ -99,8 +139,11 @@ if (parsed.command === "install") {
99
139
  // keeps generating only (documented in --help).
100
140
  if (parsed.output === undefined) {
101
141
  await registerClaude({
102
- root: result.marketplaceRoot,
103
- manifest: result.marketplaceManifest,
142
+ // A default install always materialises the marketplace manifest; the
143
+ // generate-only form (--output) is the only path where it is null, and
144
+ // this branch is not that path.
145
+ root: /** @type {string} */ (result.marketplaceRoot),
146
+ manifest: /** @type {object} */ (result.marketplaceManifest),
104
147
  pluginVersion: result.pluginVersion,
105
148
  dryRun: parsed.dryRun ?? false,
106
149
  requireRegister: parsed.requireRegister ?? false,
@@ -108,12 +151,13 @@ if (parsed.command === "install") {
108
151
  }
109
152
  process.exit(0);
110
153
  } catch (err) {
111
- process.stderr.write(`Install failed: ${err.message}\n`);
154
+ process.stderr.write(`Install failed: ${/** @type {Error} */ (err).message}\n`);
112
155
  process.exit(1);
113
156
  }
114
157
  }
115
158
  }
116
159
 
160
+ /** @param {{ removed: string[] }} result */
117
161
  function printPiSweep({ removed }) {
118
162
  if (removed.length === 0) return;
119
163
  process.stdout.write(
@@ -124,6 +168,24 @@ function printPiSweep({ removed }) {
124
168
  }
125
169
  }
126
170
 
171
+ if (parsed.command === "migrate") {
172
+ if (parsed.optionError) {
173
+ process.stderr.write(`${parsed.optionError}\n`);
174
+ process.exit(1);
175
+ }
176
+
177
+ // Loaded lazily: the migration registry is only needed on this path.
178
+ const { runMigrate } = await import("../scripts/lib/migrate.mjs");
179
+ try {
180
+ await runMigrate({ apply: parsed.apply ?? false, dir: parsed.dir });
181
+ } catch (err) {
182
+ process.stderr.write(`Migration failed: ${/** @type {Error} */ (err).message}\n`);
183
+ process.exit(1);
184
+ }
185
+ process.exit(0);
186
+ }
187
+
188
+ /** @param {InstallPiResult} result */
127
189
  function printPiInstall(result) {
128
190
  process.stdout.write(`Installing agent-cortex for "pi" harness…\n`);
129
191
  process.stdout.write(` ✓ Staged pi package → ${result.output}\n`);