@sienklogic/plan-build-run 2.51.0 → 2.53.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 (229) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/package.json +4 -2
  3. package/plugins/copilot-pbr/agents/audit.agent.md +2 -5
  4. package/plugins/copilot-pbr/agents/codebase-mapper.agent.md +1 -4
  5. package/plugins/copilot-pbr/agents/debugger.agent.md +1 -4
  6. package/plugins/copilot-pbr/agents/dev-sync.agent.md +6 -9
  7. package/plugins/copilot-pbr/agents/executor.agent.md +1 -6
  8. package/plugins/copilot-pbr/agents/general.agent.md +1 -4
  9. package/plugins/copilot-pbr/agents/integration-checker.agent.md +1 -4
  10. package/plugins/copilot-pbr/agents/plan-checker.agent.md +1 -4
  11. package/plugins/copilot-pbr/agents/planner.agent.md +1 -4
  12. package/plugins/copilot-pbr/agents/researcher.agent.md +1 -4
  13. package/plugins/copilot-pbr/agents/synthesizer.agent.md +1 -4
  14. package/plugins/copilot-pbr/agents/verifier.agent.md +2 -4
  15. package/plugins/copilot-pbr/commands/audit.md +5 -0
  16. package/plugins/copilot-pbr/commands/begin.md +5 -0
  17. package/plugins/copilot-pbr/commands/build.md +5 -0
  18. package/plugins/copilot-pbr/commands/config.md +5 -0
  19. package/plugins/copilot-pbr/commands/continue.md +5 -0
  20. package/plugins/copilot-pbr/commands/dashboard.md +5 -0
  21. package/plugins/copilot-pbr/commands/debug.md +5 -0
  22. package/plugins/copilot-pbr/commands/discuss.md +5 -0
  23. package/plugins/copilot-pbr/commands/do.md +5 -0
  24. package/plugins/copilot-pbr/commands/explore.md +5 -0
  25. package/plugins/copilot-pbr/commands/health.md +5 -0
  26. package/plugins/copilot-pbr/commands/help.md +5 -0
  27. package/plugins/copilot-pbr/commands/import.md +5 -0
  28. package/plugins/copilot-pbr/commands/milestone.md +5 -0
  29. package/plugins/copilot-pbr/commands/note.md +5 -0
  30. package/plugins/copilot-pbr/commands/pause.md +5 -0
  31. package/plugins/copilot-pbr/commands/plan.md +5 -0
  32. package/plugins/copilot-pbr/commands/quick.md +5 -0
  33. package/plugins/copilot-pbr/commands/resume.md +5 -0
  34. package/plugins/copilot-pbr/commands/review.md +5 -0
  35. package/plugins/copilot-pbr/commands/scan.md +5 -0
  36. package/plugins/copilot-pbr/commands/setup.md +5 -0
  37. package/plugins/copilot-pbr/commands/status.md +5 -0
  38. package/plugins/copilot-pbr/commands/statusline.md +5 -0
  39. package/plugins/copilot-pbr/commands/todo.md +5 -0
  40. package/plugins/copilot-pbr/plugin.json +1 -1
  41. package/plugins/copilot-pbr/references/agent-teams.md +0 -1
  42. package/plugins/copilot-pbr/references/common-bug-patterns.md +0 -1
  43. package/plugins/copilot-pbr/references/config-reference.md +0 -1
  44. package/plugins/copilot-pbr/references/continuation-format.md +0 -1
  45. package/plugins/copilot-pbr/references/deviation-rules.md +0 -1
  46. package/plugins/copilot-pbr/references/git-integration.md +0 -1
  47. package/plugins/copilot-pbr/references/integration-patterns.md +0 -1
  48. package/plugins/copilot-pbr/references/model-profiles.md +0 -1
  49. package/plugins/copilot-pbr/references/model-selection.md +0 -1
  50. package/plugins/copilot-pbr/references/plan-authoring.md +0 -1
  51. package/plugins/copilot-pbr/references/plan-format.md +0 -1
  52. package/plugins/copilot-pbr/references/reading-verification.md +0 -1
  53. package/plugins/copilot-pbr/references/signal-files.md +41 -0
  54. package/plugins/copilot-pbr/references/stub-patterns.md +0 -1
  55. package/plugins/copilot-pbr/references/wave-execution.md +0 -1
  56. package/plugins/copilot-pbr/skills/begin/SKILL.md +74 -52
  57. package/plugins/copilot-pbr/skills/build/SKILL.md +55 -69
  58. package/plugins/copilot-pbr/skills/config/SKILL.md +7 -0
  59. package/plugins/copilot-pbr/skills/continue/SKILL.md +31 -24
  60. package/plugins/copilot-pbr/skills/dashboard/SKILL.md +8 -7
  61. package/plugins/copilot-pbr/skills/debug/SKILL.md +11 -0
  62. package/plugins/copilot-pbr/skills/discuss/SKILL.md +2 -0
  63. package/plugins/copilot-pbr/skills/do/SKILL.md +2 -0
  64. package/plugins/copilot-pbr/skills/explore/SKILL.md +7 -1
  65. package/plugins/copilot-pbr/skills/health/SKILL.md +2 -0
  66. package/plugins/copilot-pbr/skills/help/SKILL.md +6 -0
  67. package/plugins/copilot-pbr/skills/import/SKILL.md +9 -0
  68. package/plugins/copilot-pbr/skills/milestone/SKILL.md +20 -196
  69. package/plugins/copilot-pbr/skills/note/SKILL.md +2 -0
  70. package/plugins/copilot-pbr/skills/pause/SKILL.md +5 -0
  71. package/plugins/copilot-pbr/skills/plan/SKILL.md +87 -119
  72. package/plugins/copilot-pbr/skills/quick/SKILL.md +13 -8
  73. package/plugins/copilot-pbr/skills/resume/SKILL.md +4 -0
  74. package/plugins/copilot-pbr/skills/review/SKILL.md +85 -47
  75. package/plugins/copilot-pbr/skills/scan/SKILL.md +6 -0
  76. package/plugins/copilot-pbr/skills/setup/SKILL.md +2 -0
  77. package/plugins/copilot-pbr/skills/shared/commit-planning-docs.md +0 -1
  78. package/plugins/copilot-pbr/skills/shared/config-loading.md +0 -1
  79. package/plugins/copilot-pbr/skills/shared/context-budget.md +0 -1
  80. package/plugins/copilot-pbr/skills/shared/context-loader-task.md +0 -1
  81. package/plugins/copilot-pbr/skills/shared/digest-select.md +0 -1
  82. package/plugins/copilot-pbr/skills/shared/domain-probes.md +0 -1
  83. package/plugins/copilot-pbr/skills/shared/gate-prompts.md +0 -1
  84. package/plugins/copilot-pbr/skills/shared/phase-argument-parsing.md +0 -1
  85. package/plugins/copilot-pbr/skills/shared/revision-loop.md +0 -1
  86. package/plugins/copilot-pbr/skills/shared/state-update.md +0 -1
  87. package/plugins/copilot-pbr/skills/shared/universal-anti-patterns.md +1 -2
  88. package/plugins/copilot-pbr/skills/status/SKILL.md +35 -26
  89. package/plugins/copilot-pbr/skills/test/SKILL.md +2 -2
  90. package/plugins/copilot-pbr/skills/todo/SKILL.md +2 -0
  91. package/plugins/copilot-pbr/templates/CONTEXT.md.tmpl +0 -1
  92. package/plugins/copilot-pbr/templates/INTEGRATION-REPORT.md.tmpl +0 -1
  93. package/plugins/copilot-pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -1
  94. package/plugins/copilot-pbr/templates/ROADMAP.md.tmpl +0 -1
  95. package/plugins/copilot-pbr/templates/SUMMARY.md.tmpl +0 -1
  96. package/plugins/copilot-pbr/templates/VERIFICATION-DETAIL.md.tmpl +0 -1
  97. package/plugins/copilot-pbr/templates/continue-here.md.tmpl +0 -1
  98. package/plugins/copilot-pbr/templates/prompt-partials/phase-project-context.md.tmpl +0 -1
  99. package/plugins/cursor-pbr/.cursor-plugin/plugin.json +1 -1
  100. package/plugins/cursor-pbr/agents/audit.md +1 -1
  101. package/plugins/cursor-pbr/agents/codebase-mapper.md +1 -1
  102. package/plugins/cursor-pbr/agents/debugger.md +1 -1
  103. package/plugins/cursor-pbr/agents/dev-sync.md +6 -6
  104. package/plugins/cursor-pbr/agents/executor.md +1 -3
  105. package/plugins/cursor-pbr/agents/general.md +1 -1
  106. package/plugins/cursor-pbr/agents/integration-checker.md +2 -2
  107. package/plugins/cursor-pbr/agents/plan-checker.md +2 -2
  108. package/plugins/cursor-pbr/agents/planner.md +1 -1
  109. package/plugins/cursor-pbr/agents/researcher.md +2 -2
  110. package/plugins/cursor-pbr/agents/synthesizer.md +1 -1
  111. package/plugins/cursor-pbr/agents/verifier.md +3 -2
  112. package/plugins/cursor-pbr/commands/audit.md +5 -0
  113. package/plugins/cursor-pbr/commands/begin.md +5 -0
  114. package/plugins/cursor-pbr/commands/build.md +5 -0
  115. package/plugins/cursor-pbr/commands/config.md +5 -0
  116. package/plugins/cursor-pbr/commands/continue.md +5 -0
  117. package/plugins/cursor-pbr/commands/dashboard.md +5 -0
  118. package/plugins/cursor-pbr/commands/debug.md +5 -0
  119. package/plugins/cursor-pbr/commands/discuss.md +5 -0
  120. package/plugins/cursor-pbr/commands/do.md +5 -0
  121. package/plugins/cursor-pbr/commands/explore.md +5 -0
  122. package/plugins/cursor-pbr/commands/health.md +5 -0
  123. package/plugins/cursor-pbr/commands/help.md +5 -0
  124. package/plugins/cursor-pbr/commands/import.md +5 -0
  125. package/plugins/cursor-pbr/commands/milestone.md +5 -0
  126. package/plugins/cursor-pbr/commands/note.md +5 -0
  127. package/plugins/cursor-pbr/commands/pause.md +5 -0
  128. package/plugins/cursor-pbr/commands/plan.md +5 -0
  129. package/plugins/cursor-pbr/commands/quick.md +5 -0
  130. package/plugins/cursor-pbr/commands/resume.md +5 -0
  131. package/plugins/cursor-pbr/commands/review.md +5 -0
  132. package/plugins/cursor-pbr/commands/scan.md +5 -0
  133. package/plugins/cursor-pbr/commands/setup.md +5 -0
  134. package/plugins/cursor-pbr/commands/status.md +5 -0
  135. package/plugins/cursor-pbr/commands/statusline.md +5 -0
  136. package/plugins/cursor-pbr/commands/todo.md +5 -0
  137. package/plugins/cursor-pbr/hooks/hooks.json +4 -10
  138. package/plugins/cursor-pbr/references/agent-teams.md +0 -1
  139. package/plugins/{copilot-pbr/references → cursor-pbr/references/archive}/agent-anti-patterns.md +0 -1
  140. package/plugins/cursor-pbr/references/{pbr-rules.md → archive/pbr-rules.md} +0 -1
  141. package/plugins/cursor-pbr/references/common-bug-patterns.md +0 -1
  142. package/plugins/cursor-pbr/references/config-reference.md +0 -1
  143. package/plugins/cursor-pbr/references/continuation-format.md +0 -1
  144. package/plugins/cursor-pbr/references/deviation-rules.md +0 -1
  145. package/plugins/cursor-pbr/references/git-integration.md +0 -1
  146. package/plugins/cursor-pbr/references/integration-patterns.md +0 -1
  147. package/plugins/cursor-pbr/references/model-profiles.md +0 -1
  148. package/plugins/cursor-pbr/references/model-selection.md +0 -1
  149. package/plugins/cursor-pbr/references/plan-authoring.md +0 -1
  150. package/plugins/cursor-pbr/references/plan-format.md +0 -1
  151. package/plugins/cursor-pbr/references/reading-verification.md +0 -1
  152. package/plugins/cursor-pbr/references/signal-files.md +41 -0
  153. package/plugins/cursor-pbr/references/stub-patterns.md +0 -1
  154. package/plugins/cursor-pbr/references/wave-execution.md +0 -1
  155. package/plugins/cursor-pbr/skills/begin/SKILL.md +74 -52
  156. package/plugins/cursor-pbr/skills/build/SKILL.md +58 -70
  157. package/plugins/cursor-pbr/skills/config/SKILL.md +5 -0
  158. package/plugins/cursor-pbr/skills/continue/SKILL.md +31 -24
  159. package/plugins/cursor-pbr/skills/dashboard/SKILL.md +8 -7
  160. package/plugins/cursor-pbr/skills/debug/SKILL.md +8 -0
  161. package/plugins/cursor-pbr/skills/discuss/SKILL.md +2 -0
  162. package/plugins/cursor-pbr/skills/do/SKILL.md +2 -0
  163. package/plugins/cursor-pbr/skills/explore/SKILL.md +5 -1
  164. package/plugins/cursor-pbr/skills/health/SKILL.md +2 -0
  165. package/plugins/cursor-pbr/skills/help/SKILL.md +6 -0
  166. package/plugins/cursor-pbr/skills/import/SKILL.md +7 -0
  167. package/plugins/cursor-pbr/skills/milestone/SKILL.md +20 -196
  168. package/plugins/cursor-pbr/skills/note/SKILL.md +2 -0
  169. package/plugins/cursor-pbr/skills/pause/SKILL.md +4 -0
  170. package/plugins/cursor-pbr/skills/plan/SKILL.md +87 -119
  171. package/plugins/cursor-pbr/skills/quick/SKILL.md +13 -8
  172. package/plugins/cursor-pbr/skills/resume/SKILL.md +4 -0
  173. package/plugins/cursor-pbr/skills/review/SKILL.md +85 -47
  174. package/plugins/cursor-pbr/skills/scan/SKILL.md +5 -0
  175. package/plugins/cursor-pbr/skills/setup/SKILL.md +2 -0
  176. package/plugins/cursor-pbr/skills/shared/commit-planning-docs.md +0 -1
  177. package/plugins/cursor-pbr/skills/shared/config-loading.md +0 -1
  178. package/plugins/cursor-pbr/skills/shared/context-budget.md +0 -1
  179. package/plugins/cursor-pbr/skills/shared/context-loader-task.md +0 -1
  180. package/plugins/cursor-pbr/skills/shared/digest-select.md +0 -1
  181. package/plugins/cursor-pbr/skills/shared/domain-probes.md +0 -1
  182. package/plugins/cursor-pbr/skills/shared/gate-prompts.md +0 -1
  183. package/plugins/cursor-pbr/skills/shared/phase-argument-parsing.md +0 -1
  184. package/plugins/cursor-pbr/skills/shared/revision-loop.md +0 -1
  185. package/plugins/cursor-pbr/skills/shared/state-update.md +0 -1
  186. package/plugins/cursor-pbr/skills/shared/universal-anti-patterns.md +1 -2
  187. package/plugins/cursor-pbr/skills/status/SKILL.md +35 -26
  188. package/plugins/cursor-pbr/skills/test/SKILL.md +2 -2
  189. package/plugins/cursor-pbr/skills/todo/SKILL.md +2 -0
  190. package/plugins/cursor-pbr/templates/CONTEXT.md.tmpl +0 -1
  191. package/plugins/cursor-pbr/templates/INTEGRATION-REPORT.md.tmpl +0 -1
  192. package/plugins/cursor-pbr/templates/RESEARCH-SUMMARY.md.tmpl +0 -1
  193. package/plugins/cursor-pbr/templates/ROADMAP.md.tmpl +0 -1
  194. package/plugins/cursor-pbr/templates/SUMMARY.md.tmpl +0 -1
  195. package/plugins/cursor-pbr/templates/VERIFICATION-DETAIL.md.tmpl +0 -1
  196. package/plugins/cursor-pbr/templates/continue-here.md.tmpl +0 -1
  197. package/plugins/cursor-pbr/templates/prompt-partials/phase-project-context.md.tmpl +0 -1
  198. package/plugins/pbr/.claude-plugin/plugin.json +1 -1
  199. package/plugins/pbr/agents/executor.md +0 -2
  200. package/plugins/{cursor-pbr/references → pbr/references/archive}/agent-anti-patterns.md +0 -1
  201. package/plugins/{copilot-pbr/references → pbr/references/archive}/pbr-rules.md +0 -1
  202. package/plugins/pbr/references/signal-files.md +41 -0
  203. package/plugins/pbr/scripts/check-skill-workflow.js +7 -8
  204. package/plugins/pbr/scripts/check-subagent-output.js +7 -6
  205. package/plugins/pbr/scripts/context-budget-check.js +13 -1
  206. package/plugins/pbr/scripts/enforce-pbr-workflow.js +15 -6
  207. package/plugins/pbr/scripts/lib/core.js +53 -1
  208. package/plugins/pbr/scripts/log-subagent.js +7 -10
  209. package/plugins/pbr/scripts/pbr-tools.js +49 -3
  210. package/plugins/pbr/scripts/progress-tracker.js +13 -3
  211. package/plugins/pbr/scripts/session-cleanup.js +6 -0
  212. package/plugins/pbr/scripts/suggest-compact.js +13 -1
  213. package/plugins/pbr/skills/begin/SKILL.md +13 -13
  214. package/plugins/pbr/skills/build/SKILL.md +24 -7
  215. package/plugins/pbr/skills/milestone/SKILL.md +10 -10
  216. package/plugins/pbr/skills/plan/SKILL.md +9 -9
  217. package/plugins/pbr/skills/quick/SKILL.md +3 -3
  218. package/plugins/pbr/skills/review/SKILL.md +6 -6
  219. /package/plugins/{pbr/references → copilot-pbr/references/archive}/agent-anti-patterns.md +0 -0
  220. /package/plugins/copilot-pbr/references/{checkpoints.md → archive/checkpoints.md} +0 -0
  221. /package/plugins/copilot-pbr/references/{context-quality-tiers.md → archive/context-quality-tiers.md} +0 -0
  222. /package/plugins/{pbr/references → copilot-pbr/references/archive}/pbr-rules.md +0 -0
  223. /package/plugins/copilot-pbr/references/{verification-patterns.md → archive/verification-patterns.md} +0 -0
  224. /package/plugins/cursor-pbr/references/{checkpoints.md → archive/checkpoints.md} +0 -0
  225. /package/plugins/cursor-pbr/references/{context-quality-tiers.md → archive/context-quality-tiers.md} +0 -0
  226. /package/plugins/cursor-pbr/references/{verification-patterns.md → archive/verification-patterns.md} +0 -0
  227. /package/plugins/pbr/references/{checkpoints.md → archive/checkpoints.md} +0 -0
  228. /package/plugins/pbr/references/{context-quality-tiers.md → archive/context-quality-tiers.md} +0 -0
  229. /package/plugins/pbr/references/{verification-patterns.md → archive/verification-patterns.md} +0 -0
@@ -1,4 +1,3 @@
1
- <!-- canonical: ../../pbr/templates/RESEARCH-SUMMARY.md.tmpl -->
2
1
  # Research Summary
3
2
 
4
3
  > Synthesized: {date}
@@ -1,4 +1,3 @@
1
- <!-- canonical: ../../pbr/templates/ROADMAP.md.tmpl -->
2
1
  # Project Roadmap
3
2
 
4
3
  > Generated: {date}
@@ -1,4 +1,3 @@
1
- <!-- canonical: ../../pbr/templates/SUMMARY.md.tmpl -->
2
1
  # SUMMARY.md Template
3
2
 
4
3
  > Referenced by: executor agent, build skill, review skill
@@ -1,4 +1,3 @@
1
- <!-- canonical: ../../pbr/templates/VERIFICATION-DETAIL.md.tmpl -->
2
1
  <!-- Source: agents/verifier.md | Purpose: Detailed output format for verification reports produced by the verifier agent -->
3
2
 
4
3
  ```yaml
@@ -1,4 +1,3 @@
1
- <!-- canonical: ../../pbr/templates/continue-here.md.tmpl -->
2
1
  <!-- Source: skills/pause/SKILL.md | Purpose: Handoff file for session pause/resume, placed in the active phase directory -->
3
2
 
4
3
  # Template: Continue Here Handoff File
@@ -1,4 +1,3 @@
1
- <!-- canonical: ../../../pbr/templates/prompt-partials/phase-project-context.md.tmpl -->
2
1
  <!-- Source: templates/prompt-partials/ | Purpose: Shared context blocks for agent prompt templates -->
3
2
  <!-- Usage: Read this file and fill in placeholders, then include the result in agent prompts. -->
4
3
  <!-- Orchestrators should omit sections that don't apply to their agent type. -->
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pbr",
3
- "version": "2.51.0",
3
+ "version": "2.53.0",
4
4
  "description": "Plan-Build-Run — Structured development workflow for Claude Code. Solves context rot through disciplined subagent delegation, structured planning, atomic execution, and goal-backward verification.",
5
5
  "author": {
6
6
  "name": "SienkLogic",
@@ -141,8 +141,6 @@ Only append to the LAST commit of the plan — intermediate commits (RED/GREEN i
141
141
 
142
142
  ## Deviation Rules
143
143
 
144
- Reference: `references/deviation-rules.md` for examples and decision tree.
145
-
146
144
  | Rule | Trigger | Action | Approval |
147
145
  |------|---------|--------|----------|
148
146
  | 1 — Bug | Code bug (typo, wrong import, syntax) | Auto-fix in same commit. 3 attempts max. | No |
@@ -1,4 +1,3 @@
1
- <!-- canonical: ../../pbr/references/agent-anti-patterns.md -->
2
1
  # Universal Agent Anti-Patterns
3
2
 
4
3
  These anti-patterns apply to ALL Plan-Build-Run agents. Each agent also has role-specific anti-patterns defined in its own agent file.
@@ -1,4 +1,3 @@
1
- <!-- canonical: ../../pbr/references/pbr-rules.md -->
2
1
  # Plan-Build-Run Rules
3
2
 
4
3
  Authoritative rules for all Plan-Build-Run skills, agents, hooks, and workflows.
@@ -0,0 +1,41 @@
1
+ # Signal Files Reference
2
+
3
+ Signal files are ephemeral files in `.planning/` that coordinate state between hook scripts
4
+ and skills. They are scoped to either the current session or the current phase/plan.
5
+
6
+ ## Session-Scoped Files
7
+
8
+ All 5 session signals are consolidated in `.planning/.session.json`. Scripts must read and write
9
+ `.session.json` via `pbr-tools session get|set|clear` — never read the raw `.session.json` file directly.
10
+ The `.session.json` schema is an object with the keys documented below.
11
+
12
+ | JSON Key | Former File | Written By | Read By | Semantics |
13
+ |----------|-------------|------------|---------|-----------|
14
+ | `activeSkill` | `.active-skill` | Skills (Write tool) | check-skill-workflow, enforce-pbr-workflow, check-subagent-output, log-subagent, block-skill-self-read | Which skill is active. Written at skill start, cleared at skill end (session-cleanup). |
15
+ | `compactCounter` | `.compact-counter` | suggest-compact.js | suggest-compact.js | Write count since last /compact. Resets on SessionStart. |
16
+ | `sessionStart` | `.session-start` | progress-tracker.js | local-llm metrics | ISO timestamp of session start. Used for LLM metrics correlation. |
17
+ | `activeOperation` | `.active-operation` | context-budget-check.js | context-budget-check.js | Current named operation for budget display. |
18
+ | `activePlan` | `.active-plan` | context-budget-check.js | context-budget-check.js | Current plan ID for budget display. |
19
+
20
+ **Atomic access**: Use `pbr-tools session get|set|clear` for safe reads/writes from hook scripts.
21
+
22
+ **Lifecycle**: Written during SessionStart (progress-tracker), cleared during SessionEnd (session-cleanup).
23
+ Stale sessions (> 60 min) are auto-cleaned by progress-tracker.js on next SessionStart.
24
+
25
+ ## One-Shot Files
26
+
27
+ These files are NOT consolidated — they use write-once, delete-on-read semantics.
28
+
29
+ | File | Written By | Read By | Semantics |
30
+ |------|------------|---------|-----------|
31
+ | `.planning/.auto-next` | auto-continue.js | auto-continue.js (Stop hook) | Next command to run after session stops. Deleted after read. |
32
+ | `.planning/.auto-verify` | event-handler.js | event-handler.js (SubagentStop hook) | Trigger auto-verification after agent completes. Deleted after read. |
33
+
34
+ ## Phase-Scoped Files
35
+
36
+ These files persist across sessions, scoped to a specific phase or plan.
37
+
38
+ | File Pattern | Written By | Read By | Semantics |
39
+ |-------------|------------|---------|-----------|
40
+ | `.planning/phases/{id}/.checkpoint-manifest.json` | build skill | validate-task.js, session-cleanup.js | Checkpoint state for a plan in progress. Cleaned up after 24h. |
41
+ | `.planning/phases/{id}/.PROGRESS-{taskId}` | executor agent | validate-task.js | Task progress marker for crash recovery. Orphaned files warn on SessionStart. |
@@ -25,6 +25,7 @@ const fs = require('fs');
25
25
  const path = require('path');
26
26
  const { logHook } = require('./hook-logger');
27
27
  const { logEvent } = require('./event-logger');
28
+ const { sessionLoad } = require('./pbr-tools');
28
29
 
29
30
  function main() {
30
31
  let input = '';
@@ -80,15 +81,13 @@ function main() {
80
81
  }
81
82
 
82
83
  function readActiveSkill(planningDir) {
83
- const skillFile = path.join(planningDir, '.active-skill');
84
- if (!fs.existsSync(skillFile)) return null;
85
-
86
- try {
87
- const content = fs.readFileSync(skillFile, 'utf8').trim();
88
- return content || null;
89
- } catch (_e) {
90
- return null;
84
+ // Try .session.json first, fall back to legacy .active-skill
85
+ let activeSkill = sessionLoad(planningDir).activeSkill || null;
86
+ if (!activeSkill) {
87
+ try { activeSkill = fs.readFileSync(path.join(planningDir, '.active-skill'), 'utf8').trim(); } catch (_) { /* legacy file missing */ }
91
88
  }
89
+ // TODO(Phase 55+): Remove legacy .active-skill fallback once .session.json is confirmed stable
90
+ return activeSkill || null;
92
91
  }
93
92
 
94
93
  /**
@@ -20,7 +20,7 @@
20
20
  const fs = require('fs');
21
21
  const path = require('path');
22
22
  const { logHook } = require('./hook-logger');
23
- const { KNOWN_AGENTS } = require('./pbr-tools');
23
+ const { KNOWN_AGENTS, sessionLoad } = require('./pbr-tools');
24
24
  const { resolveConfig } = require('./local-llm/health');
25
25
  const { classifyError } = require('./local-llm/operations/classify-error');
26
26
 
@@ -437,11 +437,12 @@ async function main() {
437
437
  process.exit(0);
438
438
  }
439
439
 
440
- // Read active skill
441
- let activeSkill = '';
442
- try {
443
- activeSkill = fs.readFileSync(path.join(planningDir, '.active-skill'), 'utf8').trim();
444
- } catch (_e) { /* no active skill */ }
440
+ // Read active skill — try .session.json first, fall back to legacy .active-skill
441
+ let activeSkill = sessionLoad(planningDir).activeSkill || '';
442
+ if (!activeSkill) {
443
+ try { activeSkill = fs.readFileSync(path.join(planningDir, '.active-skill'), 'utf8').trim(); } catch (_) { /* legacy file missing */ }
444
+ }
445
+ // TODO(Phase 55+): Remove legacy .active-skill fallback once .session.json is confirmed stable
445
446
 
446
447
  // Check for expected outputs
447
448
  const found = outputSpec.check(planningDir);
@@ -21,7 +21,7 @@ const fs = require('fs');
21
21
  const path = require('path');
22
22
  const { logHook } = require('./hook-logger');
23
23
  const { logEvent } = require('./event-logger');
24
- const { configLoad, tailLines, lockedFileUpdate } = require('./pbr-tools');
24
+ const { configLoad, tailLines, lockedFileUpdate, sessionLoad } = require('./pbr-tools');
25
25
 
26
26
  function main() {
27
27
  const cwd = process.cwd();
@@ -113,6 +113,12 @@ function main() {
113
113
  }
114
114
 
115
115
  function readActiveOperation(planningDir) {
116
+ // Try .session.json first (new), fall back to legacy .active-operation file
117
+ try {
118
+ const session = sessionLoad(planningDir);
119
+ if (session.activeOperation) return session.activeOperation;
120
+ } catch (_e) { /* fall through */ }
121
+
116
122
  const activeOpFile = path.join(planningDir, '.active-operation');
117
123
  if (!fs.existsSync(activeOpFile)) return '';
118
124
  try {
@@ -160,6 +166,12 @@ function readRoadmapSummary(planningDir) {
160
166
  }
161
167
 
162
168
  function readCurrentPlan(planningDir, stateContent) {
169
+ // Try .session.json first (new), then .active-plan file (legacy)
170
+ try {
171
+ const session = sessionLoad(planningDir);
172
+ if (session.activePlan) return session.activePlan;
173
+ } catch (_e) { /* fall through */ }
174
+
163
175
  // Prefer .active-plan signal file (definitive) over directory listing (guesswork)
164
176
  const activePlanFile = path.join(planningDir, '.active-plan');
165
177
  if (fs.existsSync(activePlanFile)) {
@@ -21,6 +21,7 @@
21
21
  const fs = require('fs');
22
22
  const path = require('path');
23
23
  const { logHook } = require('./hook-logger');
24
+ const { sessionLoad } = require('./pbr-tools');
24
25
 
25
26
  /**
26
27
  * Load the enforcement configuration from .planning/config.json.
@@ -73,9 +74,13 @@ function checkUnmanagedSourceWrite(data) {
73
74
  // Skip if not a PBR project
74
75
  if (!fs.existsSync(planningDir)) return null;
75
76
 
76
- // Skip if a PBR skill is active
77
- const activeSkillFile = path.join(planningDir, '.active-skill');
78
- if (fs.existsSync(activeSkillFile)) return null;
77
+ // Skip if a PBR skill is active — try .session.json first, fall back to legacy .active-skill
78
+ let activeSkill = sessionLoad(planningDir).activeSkill || '';
79
+ if (!activeSkill) {
80
+ try { activeSkill = fs.readFileSync(path.join(planningDir, '.active-skill'), 'utf8').trim(); } catch (_) { /* legacy file missing */ }
81
+ }
82
+ // TODO(Phase 55+): Remove legacy .active-skill fallback once .session.json is confirmed stable
83
+ if (activeSkill) return null;
79
84
 
80
85
  // Skip if writing inside .planning/
81
86
  const normalizedFile = filePath.replace(/\\/g, '/');
@@ -208,9 +213,13 @@ function checkUnmanagedCommit(data) {
208
213
  // Skip if not a PBR project
209
214
  if (!fs.existsSync(planningDir)) return null;
210
215
 
211
- // Skip if a PBR skill is active
212
- const activeSkillFile = path.join(planningDir, '.active-skill');
213
- if (fs.existsSync(activeSkillFile)) return null;
216
+ // Skip if a PBR skill is active — try .session.json first, fall back to legacy .active-skill
217
+ let activeSkillCommit = sessionLoad(planningDir).activeSkill || '';
218
+ if (!activeSkillCommit) {
219
+ try { activeSkillCommit = fs.readFileSync(path.join(planningDir, '.active-skill'), 'utf8').trim(); } catch (_) { /* legacy file missing */ }
220
+ }
221
+ // TODO(Phase 55+): Remove legacy .active-skill fallback once .session.json is confirmed stable
222
+ if (activeSkillCommit) return null;
214
223
 
215
224
  const config = loadEnforcementConfig(planningDir);
216
225
  if (config.level === 'off') return null;
@@ -450,8 +450,54 @@ function lockedFileUpdate(filePath, updateFn, opts = {}) {
450
450
  }
451
451
  }
452
452
 
453
+ // --- Session state management (.planning/.session.json) ---
454
+
455
+ const SESSION_ALLOWED_KEYS = ['activeSkill', 'compactCounter', 'sessionStart', 'activeOperation', 'activePlan'];
456
+
457
+ /**
458
+ * Load .session.json from .planning/ directory.
459
+ * Returns parsed object or {} if file is missing or unreadable.
460
+ *
461
+ * @param {string} dir - Path to .planning/ directory
462
+ * @returns {object}
463
+ */
464
+ function sessionLoad(dir) {
465
+ const sessionPath = path.join(dir, '.session.json');
466
+ try {
467
+ if (!fs.existsSync(sessionPath)) return {};
468
+ const content = fs.readFileSync(sessionPath, 'utf8');
469
+ return JSON.parse(content);
470
+ } catch (_e) {
471
+ return {};
472
+ }
473
+ }
474
+
475
+ /**
476
+ * Save data to .session.json using atomic write (write .tmp, then rename).
477
+ * Merges provided data with existing session data.
478
+ *
479
+ * @param {string} dir - Path to .planning/ directory
480
+ * @param {object} data - Key-value pairs to merge into session
481
+ * @returns {{ success: boolean, error?: string }}
482
+ */
483
+ function sessionSave(dir, data) {
484
+ const sessionPath = path.join(dir, '.session.json');
485
+ const tmpPath = sessionPath + '.tmp';
486
+ try {
487
+ const existing = sessionLoad(dir);
488
+ const merged = Object.assign(existing, data);
489
+ fs.writeFileSync(tmpPath, JSON.stringify(merged, null, 2), 'utf8');
490
+ fs.renameSync(tmpPath, sessionPath);
491
+ return { success: true };
492
+ } catch (e) {
493
+ try { if (fs.existsSync(tmpPath)) fs.unlinkSync(tmpPath); } catch (_) { /* cleanup */ }
494
+ return { success: false, error: e.message };
495
+ }
496
+ }
497
+
453
498
  /**
454
499
  * Write .active-skill with OS-level mutual exclusion.
500
+ * Also writes activeSkill to .session.json for consolidated session tracking.
455
501
  *
456
502
  * @param {string} planningDir - Path to .planning/ directory
457
503
  * @param {string} skillName - Skill name to write
@@ -485,9 +531,12 @@ function writeActiveSkill(planningDir, skillName) {
485
531
  }
486
532
  }
487
533
 
488
- // Write the skill name
534
+ // Write the skill name (legacy file — kept for backward compat with reader scripts)
489
535
  fs.writeFileSync(skillFile, skillName, 'utf8');
490
536
 
537
+ // Also write to .session.json for consolidated session tracking
538
+ try { sessionSave(planningDir, { activeSkill: skillName }); } catch (_e) { /* non-fatal */ }
539
+
491
540
  // Release lock
492
541
  try { fs.unlinkSync(lockFile); } catch (_e) { /* best effort */ }
493
542
 
@@ -585,5 +634,8 @@ module.exports = {
585
634
  atomicWrite,
586
635
  lockedFileUpdate,
587
636
  writeActiveSkill,
637
+ sessionLoad,
638
+ sessionSave,
639
+ SESSION_ALLOWED_KEYS,
588
640
  validateObject
589
641
  };
@@ -17,7 +17,7 @@ const fs = require('fs');
17
17
  const path = require('path');
18
18
  const { logHook } = require('./hook-logger');
19
19
  const { logEvent } = require('./event-logger');
20
- const { configLoad } = require('./pbr-tools');
20
+ const { configLoad, sessionLoad } = require('./pbr-tools');
21
21
 
22
22
  function readStdin() {
23
23
  try {
@@ -136,16 +136,13 @@ function buildAgentContext() {
136
136
  }
137
137
  }
138
138
 
139
- // Active skill context
140
- const activeSkillFile = path.join(planningDir, '.active-skill');
141
- if (fs.existsSync(activeSkillFile)) {
142
- try {
143
- const skill = fs.readFileSync(activeSkillFile, 'utf8').trim();
144
- if (skill) parts.push(`Active skill: /pbr:${skill}`);
145
- } catch (_e) {
146
- // skip
147
- }
139
+ // Active skill context — try .session.json first, fall back to legacy .active-skill
140
+ let activeSkill = sessionLoad(planningDir).activeSkill || '';
141
+ if (!activeSkill) {
142
+ try { activeSkill = fs.readFileSync(path.join(planningDir, '.active-skill'), 'utf8').trim(); } catch (_) { /* legacy file missing */ }
148
143
  }
144
+ // TODO(Phase 55+): Remove legacy .active-skill fallback once .session.json is confirmed stable
145
+ if (activeSkill) parts.push(`Active skill: /pbr:${activeSkill}`);
149
146
 
150
147
  // Config highlights
151
148
  const config = configLoad(planningDir);
@@ -46,6 +46,10 @@
46
46
  * checkpoint init <phase-slug> [--plans "id1,id2"] — Initialize checkpoint manifest
47
47
  * checkpoint update <phase-slug> --wave N --resolved id [--sha hash] — Update manifest
48
48
  * seeds match <phase-slug> <phase-number> — Find matching seed files for a phase
49
+ * session get <key> — Read a key from .planning/.session.json
50
+ * session set <key> <value> — Write a key to .planning/.session.json
51
+ * session clear [key] — Delete .session.json or set key to null
52
+ * session dump — Print entire .session.json content
49
53
  *
50
54
  * Environment: PBR_PROJECT_ROOT — Override project root directory (used when hooks fire from subagent cwd)
51
55
  */
@@ -68,7 +72,10 @@ const {
68
72
  determinePhaseStatus,
69
73
  atomicWrite,
70
74
  lockedFileUpdate,
71
- writeActiveSkill
75
+ writeActiveSkill,
76
+ sessionLoad,
77
+ sessionSave,
78
+ SESSION_ALLOWED_KEYS
72
79
  } = require('./lib/core');
73
80
 
74
81
  const {
@@ -833,6 +840,45 @@ async function main() {
833
840
  const manifestPath = args[1];
834
841
  if (!manifestPath) { error('Usage: pbr-tools.js rollback <manifest-path>'); return; }
835
842
  output(rollbackPlan(manifestPath));
843
+ } else if (command === 'session') {
844
+ const sub = args[1];
845
+ const key = args[2];
846
+ const value = args[3];
847
+ const dir = planningDir;
848
+ if (sub === 'get') {
849
+ if (!key) { error('Usage: pbr-tools.js session get <key>'); return; }
850
+ if (!SESSION_ALLOWED_KEYS.includes(key)) { error(`Unknown session key: ${key}. Allowed: ${SESSION_ALLOWED_KEYS.join(', ')}`); return; }
851
+ const data = sessionLoad(dir);
852
+ const val = Object.prototype.hasOwnProperty.call(data, key) ? data[key] : null;
853
+ output({ key, value: val });
854
+ } else if (sub === 'set') {
855
+ if (!key || value === undefined) { error('Usage: pbr-tools.js session set <key> <value>'); return; }
856
+ if (!SESSION_ALLOWED_KEYS.includes(key)) { error(`Unknown session key: ${key}. Allowed: ${SESSION_ALLOWED_KEYS.join(', ')}`); return; }
857
+ // Coerce numeric strings
858
+ let coerced = value;
859
+ if (/^\d+$/.test(value)) coerced = parseInt(value, 10);
860
+ else if (value === 'null') coerced = null;
861
+ const result = sessionSave(dir, { [key]: coerced });
862
+ if (!result.success) { error(result.error || 'Failed to save session'); return; }
863
+ output({ ok: true });
864
+ } else if (sub === 'clear') {
865
+ const sessionPath = path.join(dir, '.session.json');
866
+ if (key) {
867
+ // Clear a specific key — set to null
868
+ if (!SESSION_ALLOWED_KEYS.includes(key)) { error(`Unknown session key: ${key}. Allowed: ${SESSION_ALLOWED_KEYS.join(', ')}`); return; }
869
+ const result = sessionSave(dir, { [key]: null });
870
+ if (!result.success) { error(result.error || 'Failed to clear session key'); return; }
871
+ } else {
872
+ // Clear entire session file
873
+ try { if (fs.existsSync(sessionPath)) fs.unlinkSync(sessionPath); } catch (e) { error(e.message); return; }
874
+ }
875
+ output({ ok: true });
876
+ } else if (sub === 'dump') {
877
+ const data = sessionLoad(dir);
878
+ output(data);
879
+ } else {
880
+ error('Usage: pbr-tools.js session get|set|clear|dump <key> [value]');
881
+ }
836
882
  } else if (command === 'context-triage') {
837
883
  const options = {};
838
884
  const agentsIdx = args.indexOf('--agents-done');
@@ -856,7 +902,7 @@ async function main() {
856
902
  } else if (command === 'validate-project') {
857
903
  output(validateProject());
858
904
  } else {
859
- error(`Unknown command: ${args.join(' ')}\nCommands: state load|check-progress|update|patch|advance-plan|record-metric, config validate|load-defaults|save-defaults|resolve-depth, validate-project, migrate [--dry-run] [--force], init execute-phase|plan-phase|quick|verify-work|resume|progress, state-bundle <phase>, plan-index, frontmatter, must-haves, phase-info, phase add|remove|list, roadmap update-status|update-plans, history append|load, todo list|get|add|done, event, llm health|status|classify|score-source|classify-error|summarize|metrics [--session <ISO>]|adjust-thresholds, learnings ingest|query|check-thresholds, milestone-stats <version>, context-triage [--agents-done N] [--plans-total N] [--step NAME], ci-poll <run-id> [--timeout <seconds>], rollback <manifest-path>`);
905
+ error(`Unknown command: ${args.join(' ')}\nCommands: state load|check-progress|update|patch|advance-plan|record-metric, config validate|load-defaults|save-defaults|resolve-depth, validate-project, migrate [--dry-run] [--force], init execute-phase|plan-phase|quick|verify-work|resume|progress, state-bundle <phase>, plan-index, frontmatter, must-haves, phase-info, phase add|remove|list, roadmap update-status|update-plans, history append|load, todo list|get|add|done, event, llm health|status|classify|score-source|classify-error|summarize|metrics [--session <ISO>]|adjust-thresholds, learnings ingest|query|check-thresholds, milestone-stats <version>, context-triage [--agents-done N] [--plans-total N] [--step NAME], ci-poll <run-id> [--timeout <seconds>], rollback <manifest-path>, session get|set|clear|dump`);
860
906
  }
861
907
  } catch (e) {
862
908
  error(e.message);
@@ -864,6 +910,6 @@ async function main() {
864
910
  }
865
911
 
866
912
  if (require.main === module || process.argv[1] === __filename) { main().catch(err => { process.stderr.write(err.message + '\n'); process.exit(1); }); }
867
- module.exports = { KNOWN_AGENTS, initExecutePhase, initPlanPhase, initQuick, initVerifyWork, initResume, initProgress, initStateBundle: stateBundle, stateBundle, statePatch, stateAdvancePlan, stateRecordMetric, parseStateMd, parseRoadmapMd, parseYamlFrontmatter, parseMustHaves, countMustHaves, stateLoad, stateCheckProgress, configLoad, configClearCache, configValidate, lockedFileUpdate, planIndex, determinePhaseStatus, findFiles, atomicWrite, tailLines, frontmatter, mustHavesCollect, phaseInfo, stateUpdate, roadmapUpdateStatus, roadmapUpdatePlans, updateLegacyStateField, updateFrontmatterField, updateTableRow, findRoadmapRow, resolveDepthProfile, DEPTH_PROFILE_DEFAULTS, historyAppend, historyLoad, VALID_STATUS_TRANSITIONS, validateStatusTransition, writeActiveSkill, validateProject, phaseAdd, phaseRemove, phaseList, loadUserDefaults, saveUserDefaults, mergeUserDefaults, USER_DEFAULTS_PATH, todoList, todoGet, todoAdd, todoDone, migrate, spotCheck, referenceGet, milestoneStats, contextTriage, stalenessCheck, summaryGate, checkpointInit, checkpointUpdate, seedsMatch, ciPoll, rollbackPlan };
913
+ module.exports = { KNOWN_AGENTS, initExecutePhase, initPlanPhase, initQuick, initVerifyWork, initResume, initProgress, initStateBundle: stateBundle, stateBundle, statePatch, stateAdvancePlan, stateRecordMetric, parseStateMd, parseRoadmapMd, parseYamlFrontmatter, parseMustHaves, countMustHaves, stateLoad, stateCheckProgress, configLoad, configClearCache, configValidate, lockedFileUpdate, planIndex, determinePhaseStatus, findFiles, atomicWrite, tailLines, frontmatter, mustHavesCollect, phaseInfo, stateUpdate, roadmapUpdateStatus, roadmapUpdatePlans, updateLegacyStateField, updateFrontmatterField, updateTableRow, findRoadmapRow, resolveDepthProfile, DEPTH_PROFILE_DEFAULTS, historyAppend, historyLoad, VALID_STATUS_TRANSITIONS, validateStatusTransition, writeActiveSkill, validateProject, phaseAdd, phaseRemove, phaseList, loadUserDefaults, saveUserDefaults, mergeUserDefaults, USER_DEFAULTS_PATH, todoList, todoGet, todoAdd, todoDone, migrate, spotCheck, referenceGet, milestoneStats, contextTriage, stalenessCheck, summaryGate, checkpointInit, checkpointUpdate, seedsMatch, ciPoll, rollbackPlan, sessionLoad, sessionSave, SESSION_ALLOWED_KEYS };
868
914
  // NOTE: validateProject, phaseAdd, phaseRemove, phaseList were previously CLI-only (not exported).
869
915
  // They are now exported for testability. This is additive and backwards-compatible.
@@ -14,7 +14,7 @@ const os = require('os');
14
14
  const { execSync } = require('child_process');
15
15
  const { logHook } = require('./hook-logger');
16
16
  const { logEvent } = require('./event-logger');
17
- const { configLoad } = require('./pbr-tools');
17
+ const { configLoad, sessionSave } = require('./pbr-tools');
18
18
  const { resolveConfig, checkHealth, warmUp } = require('./local-llm/health');
19
19
 
20
20
  async function main() {
@@ -40,9 +40,13 @@ async function main() {
40
40
  }
41
41
 
42
42
  // Write session-start timestamp for local-llm metrics correlation
43
+ // Primary: write to .session.json (unified session state)
44
+ // Legacy: also write .session-start file for session-cleanup.js backward compat
45
+ const sessionStart = new Date().toISOString();
46
+ try { sessionSave(planningDir, { sessionStart }); } catch (_e) { /* non-fatal */ }
43
47
  const sessionStartFile = path.join(planningDir, '.session-start');
44
48
  try {
45
- fs.writeFileSync(sessionStartFile, new Date().toISOString(), 'utf8');
49
+ fs.writeFileSync(sessionStartFile, sessionStart, 'utf8');
46
50
  } catch (_e) { /* non-fatal */ }
47
51
 
48
52
  // Local LLM health check (advisory only — never blocks SessionStart)
@@ -217,14 +221,20 @@ function buildContext(planningDir, stateFile) {
217
221
  }
218
222
 
219
223
  // Check for stale .active-skill (multi-session conflict detection)
224
+ // Try .session.json first (new), fall back to .active-skill file (legacy)
220
225
  const activeSkillFile = path.join(planningDir, '.active-skill');
226
+ const { sessionLoad: _sessionLoad } = require('./pbr-tools');
227
+ const sessionData = _sessionLoad(planningDir);
228
+ const sessionActiveSkill = sessionData.activeSkill || null;
229
+
221
230
  if (fs.existsSync(activeSkillFile)) {
222
231
  try {
223
232
  const stats = fs.statSync(activeSkillFile);
224
233
  const ageMs = Date.now() - stats.mtimeMs;
225
234
  const ageMinutes = Math.floor(ageMs / 60000);
226
235
  if (ageMinutes > 60) {
227
- const skill = fs.readFileSync(activeSkillFile, 'utf8').trim();
236
+ // Prefer skill name from .session.json if available
237
+ const skill = sessionActiveSkill || fs.readFileSync(activeSkillFile, 'utf8').trim();
228
238
  // Auto-cleanup stale .active-skill lock (> 60 minutes = certainly stale)
229
239
  try {
230
240
  fs.unlinkSync(activeSkillFile);
@@ -216,6 +216,12 @@ function main() {
216
216
  // NOTE: .auto-next is intentionally NOT cleaned here — it is a one-shot
217
217
  // signal consumed by auto-continue.js (Stop hook). SessionEnd cleanup
218
218
  // races with the Stop hook and would delete the signal before it is read.
219
+
220
+ // Primary: remove .session.json (consolidated session state)
221
+ if (tryRemove(path.join(planningDir, '.session.json'))) {
222
+ cleaned.push('.session.json');
223
+ }
224
+ // Legacy fallback: also clean individual signal files during transition period
219
225
  if (tryRemove(path.join(planningDir, '.active-operation'))) {
220
226
  cleaned.push('.active-operation');
221
227
  }
@@ -20,7 +20,7 @@
20
20
  const fs = require('fs');
21
21
  const path = require('path');
22
22
  const { logHook } = require('./hook-logger');
23
- const { configLoad } = require('./pbr-tools');
23
+ const { configLoad, sessionSave } = require('./pbr-tools');
24
24
  const { loadBridge, TIER_MESSAGES } = require('./context-bridge');
25
25
 
26
26
  const DEFAULT_THRESHOLD = 50;
@@ -155,6 +155,12 @@ function saveCounter(counterPath, counter) {
155
155
  } catch (_e) {
156
156
  // Best-effort
157
157
  }
158
+ // Mirror to .session.json for consolidated session state tracking
159
+ // Derive planningDir from counterPath (counterPath is planningDir/.compact-counter)
160
+ try {
161
+ const planningDir = path.dirname(counterPath);
162
+ sessionSave(planningDir, { compactCounter: counter });
163
+ } catch (_e) { /* non-fatal mirror */ }
158
164
  }
159
165
 
160
166
  function getThreshold(cwd) {
@@ -165,6 +171,12 @@ function getThreshold(cwd) {
165
171
  }
166
172
 
167
173
  function resetCounter(planningDir) {
174
+ // Primary: reset compactCounter in .session.json to 0
175
+ try {
176
+ sessionSave(planningDir, { compactCounter: { count: 0, lastSuggested: 0 } });
177
+ } catch (_e) { /* best-effort */ }
178
+
179
+ // Legacy: also delete .compact-counter file if present
168
180
  const counterPath = path.join(planningDir, '.compact-counter');
169
181
  try {
170
182
  if (fs.existsSync(counterPath)) {
@@ -168,7 +168,7 @@ Use the **yes-no** pattern from `skills/shared/gate-prompts.md`:
168
168
 
169
169
  **After gathering preferences:**
170
170
 
171
- **CRITICAL: You MUST create the .planning/ directory and write config.json NOW. Do not proceed without this.**
171
+ **CRITICAL (no hook): You MUST create the .planning/ directory and write config.json NOW. Do not proceed without this.**
172
172
 
173
173
  1. Read the config template from `skills/begin/templates/config.json.tmpl`
174
174
  2. Apply the user's choices to the template
@@ -177,7 +177,7 @@ Use the **yes-no** pattern from `skills/shared/gate-prompts.md`:
177
177
 
178
178
  **IMPORTANT**: This step MUST happen BEFORE research (Step 5) because depth controls how many researchers to spawn.
179
179
 
180
- **CRITICAL: Write .active-skill NOW.** Write the text "begin" to `.planning/.active-skill` using the Write tool. Verify the file exists before proceeding.
180
+ **CRITICAL (hook-enforced): Write .active-skill NOW.** Write the text "begin" to `.planning/.active-skill` using the Write tool. Verify the file exists before proceeding.
181
181
 
182
182
  ---
183
183
 
@@ -213,7 +213,7 @@ Use the **yes-no** pattern from `skills/shared/gate-prompts.md`:
213
213
 
214
214
  Spawn parallel Task() subagents for research. Each researcher writes to `.planning/research/`.
215
215
 
216
- **CRITICAL: Create .planning/research/ directory NOW before spawning researchers. Do NOT skip this step.**
216
+ **CRITICAL (no hook): Create .planning/research/ directory NOW before spawning researchers. Do NOT skip this step.**
217
217
 
218
218
  **Learnings injection (opt-in):** Before spawning researchers, check if global learnings exist:
219
219
 
@@ -258,7 +258,7 @@ Read `skills/begin/templates/researcher-prompt.md.tmpl` for the prompt structure
258
258
 
259
259
  ```
260
260
  <files_to_read>
261
- CRITICAL: Read these files BEFORE any other action:
261
+ CRITICAL (no hook): Read these files BEFORE any other action:
262
262
  1. .planning/REQUIREMENTS.md — scoped requirements (if exists)
263
263
  {if learnings_temp_path exists}2. {learnings_temp_path} — cross-project learnings (tech stack patterns from past PBR projects){/if}
264
264
  </files_to_read>
@@ -338,7 +338,7 @@ Read `skills/begin/templates/synthesis-prompt.md.tmpl` for the prompt structure.
338
338
  **Prepend this block to the synthesizer prompt before sending:**
339
339
  ```
340
340
  <files_to_read>
341
- CRITICAL: Read these files BEFORE any other action:
341
+ CRITICAL (no hook): Read these files BEFORE any other action:
342
342
  1. .planning/research/*.md — all research output files from Step 5
343
343
  </files_to_read>
344
344
  ```
@@ -406,7 +406,7 @@ Each requirement must be:
406
406
 
407
407
  **7e. Write REQUIREMENTS.md:**
408
408
 
409
- **CRITICAL: Write REQUIREMENTS.md NOW. The roadmap planner depends on this file.**
409
+ **CRITICAL (no hook): Write REQUIREMENTS.md NOW. The roadmap planner depends on this file.**
410
410
 
411
411
  Read the template from `skills/begin/templates/REQUIREMENTS.md.tmpl` and write `.planning/REQUIREMENTS.md` with:
412
412
  - All v1 requirements grouped by category
@@ -441,7 +441,7 @@ Read `skills/begin/templates/roadmap-prompt.md.tmpl` for the prompt structure.
441
441
  **Prepend this block to the roadmap planner prompt before sending:**
442
442
  ```
443
443
  <files_to_read>
444
- CRITICAL: Read these files BEFORE any other action:
444
+ CRITICAL (no hook): Read these files BEFORE any other action:
445
445
  1. .planning/REQUIREMENTS.md — scoped requirements for phase planning
446
446
  2. .planning/research/SUMMARY.md — research synthesis (if exists)
447
447
  </files_to_read>
@@ -477,9 +477,9 @@ CRITICAL: Read these files BEFORE any other action:
477
477
 
478
478
  Write the project state files from templates:
479
479
 
480
- **CRITICAL: You MUST write all 5 state initialization files (Steps 9a-9e). Do NOT skip any.**
480
+ **CRITICAL (no hook): You MUST write all 5 state initialization files (Steps 9a-9e). Do NOT skip any.**
481
481
 
482
- **CRITICAL: Write PROJECT.md NOW. Do NOT skip this step.**
482
+ **CRITICAL (no hook): Write PROJECT.md NOW. Do NOT skip this step.**
483
483
 
484
484
  **9a. Write PROJECT.md:**
485
485
  1. Read `skills/begin/templates/PROJECT.md.tmpl`
@@ -493,7 +493,7 @@ Write the project state files from templates:
493
493
  3. Write to `.planning/PROJECT.md`
494
494
  4. Ensure the `## Milestones` section is filled in with the project name and phase count from the roadmap
495
495
 
496
- **CRITICAL: Write STATE.md NOW. Do NOT skip this step.**
496
+ **CRITICAL (no hook): Write STATE.md NOW. Do NOT skip this step.**
497
497
 
498
498
  **9b. Write STATE.md:**
499
499
  1. Read `skills/begin/templates/STATE.md.tmpl`
@@ -507,7 +507,7 @@ Write the project state files from templates:
507
507
  4. Fill in the `## Milestone` section with the project name and total phase count
508
508
  5. **STATE.md size limit**: Follow size limit enforcement rules in `skills/shared/state-update.md` (150 lines max).
509
509
 
510
- **CRITICAL: Write CONTEXT.md NOW. Do NOT skip this step.**
510
+ **CRITICAL (no hook): Write CONTEXT.md NOW. Do NOT skip this step.**
511
511
 
512
512
  **9c. Write CONTEXT.md:**
513
513
  Create `.planning/CONTEXT.md` from information gathered during questioning:
@@ -533,7 +533,7 @@ Create `.planning/CONTEXT.md` from information gathered during questioning:
533
533
  | {feature} | {reason} |
534
534
  ```
535
535
 
536
- **CRITICAL: Write HISTORY.md NOW. Do NOT skip this step.**
536
+ **CRITICAL (no hook): Write HISTORY.md NOW. Do NOT skip this step.**
537
537
 
538
538
  **9d. Write HISTORY.md:**
539
539
  Create `.planning/HISTORY.md` with an initial entry:
@@ -548,7 +548,7 @@ Create `.planning/HISTORY.md` with an initial entry:
548
548
  - Roadmap: {N} phases planned
549
549
  ```
550
550
 
551
- **CRITICAL: Create phase directories NOW. Do NOT skip this step.**
551
+ **CRITICAL (no hook): Create phase directories NOW. Do NOT skip this step.**
552
552
 
553
553
  **9e. Create phase directories:**
554
554
  For each phase in the roadmap, create the directory structure: