pan-wizard 3.35.0 → 3.37.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 (339) hide show
  1. package/CHANGELOG.md +3645 -0
  2. package/README.md +46 -52
  3. package/agents/pan-conductor.md +2 -3
  4. package/agents/pan-counterfactual.md +1 -2
  5. package/agents/pan-debugger.md +14 -3
  6. package/agents/pan-design-checker.md +1 -2
  7. package/agents/pan-designer.md +2 -3
  8. package/agents/pan-document_code.md +1 -2
  9. package/agents/pan-executor.md +25 -0
  10. package/agents/pan-hardener.md +4 -3
  11. package/agents/pan-integration-checker.md +1 -2
  12. package/agents/pan-knowledge.md +1 -2
  13. package/agents/pan-meta-reviewer.md +3 -3
  14. package/agents/pan-optimizer.md +4 -4
  15. package/agents/pan-phase-researcher.md +80 -475
  16. package/agents/pan-plan-checker.md +40 -3
  17. package/agents/pan-planner.md +21 -7
  18. package/agents/pan-previewer.md +3 -2
  19. package/agents/pan-project-researcher.md +72 -493
  20. package/agents/pan-release.md +1 -1
  21. package/agents/pan-reviewer.md +14 -3
  22. package/agents/pan-roadmapper.md +12 -7
  23. package/agents/pan-verifier.md +9 -4
  24. package/bin/install-lib.cjs +134 -14
  25. package/bin/install.js +59 -12
  26. package/commands/pan/army.md +1 -1
  27. package/commands/pan/autodev.md +76 -0
  28. package/commands/pan/cost.md +21 -1
  29. package/commands/pan/exec-phase.md +3 -4
  30. package/commands/pan/focus-auto.md +14 -7
  31. package/commands/pan/focus-design.md +4 -5
  32. package/commands/pan/focus-docs.md +24 -0
  33. package/commands/pan/learn.md +13 -6
  34. package/commands/pan/milestone-audit.md +8 -1
  35. package/commands/pan/milestone-done.md +10 -5
  36. package/commands/pan/milestone-new.md +2 -2
  37. package/commands/pan/new-project.md +15 -12
  38. package/commands/pan/plan-phase.md +15 -9
  39. package/commands/pan/preview.md +1 -1
  40. package/commands/pan/quick.md +1 -1
  41. package/commands/pan/review-deep.md +11 -5
  42. package/commands/pan/settings.md +6 -0
  43. package/commands/pan/verify-phase.md +6 -2
  44. package/docs/AGENTS.md +917 -0
  45. package/docs/ARCHITECTURE.md +1054 -0
  46. package/docs/CLI-REFERENCE.md +4582 -0
  47. package/docs/COMPARISON.md +116 -0
  48. package/docs/DEVELOPMENT.md +490 -0
  49. package/docs/ECOSYSTEM-REVIEW-2026-06.md +107 -0
  50. package/docs/ECOSYSTEM-REVIEW-2026-08.md +349 -0
  51. package/docs/EXAMPLES.md +584 -0
  52. package/docs/FAQ.md +254 -0
  53. package/docs/FIELD-HARVEST-2026-07.md +88 -0
  54. package/docs/FIELD-REPORT-army-2026-06.md +121 -0
  55. package/docs/HOOKS.md +638 -0
  56. package/docs/IMPROVEMENT-TODO.md +246 -0
  57. package/docs/INTERNALS.md +485 -0
  58. package/docs/MIGRATION-v2-to-v3.md +258 -0
  59. package/docs/SECURITY-HARDENING.md +230 -0
  60. package/docs/SKILLS-ENHANCEMENT-PLAN-V2.md +122 -0
  61. package/docs/SKILLS-FULL-TEXT.md +9685 -0
  62. package/docs/SKILLS-REFERENCE.md +1037 -0
  63. package/docs/TROUBLESHOOTING.md +1084 -0
  64. package/docs/USER-GUIDE.md +1437 -0
  65. package/docs/archive/SKILLS-ENHANCEMENT-PLAN.md +230 -0
  66. package/docs/audits/AUDIT-2026-08-e2e-ROADMAP.md +117 -0
  67. package/docs/audits/AUDIT-2026-08-e2e-VERIFICATION.md +693 -0
  68. package/docs/audits/AUDIT-2026-08-e2e.md +1546 -0
  69. package/docs/audits/OUTSTANDING-2026-08.md +275 -0
  70. package/docs/audits/STABILITY-TEST-2026-08.md +640 -0
  71. package/docs/branding/README-brand-draft.md +119 -0
  72. package/docs/branding/handoff/IMPLEMENTATION.md +205 -0
  73. package/docs/branding/handoff/README-brand-draft.md +119 -0
  74. package/docs/branding/handoff/image-prompts.md +46 -0
  75. package/docs/branding/image-prompts.md +46 -0
  76. package/docs/branding/nano-banana-prompts.txt +60 -0
  77. package/docs/context-monitor.md +13 -0
  78. package/docs/decisions/ADR-0001-strategic-feature-prioritization.md +83 -0
  79. package/docs/decisions/ADR-0002-copilot-cli-runtime.md +71 -0
  80. package/docs/decisions/ADR-0003-smart-execution.md +84 -0
  81. package/docs/decisions/ADR-0004-copilot-cli-interaction.md +89 -0
  82. package/docs/decisions/ADR-0005-command-naming.md +80 -0
  83. package/docs/decisions/ADR-0006-focus-commands.md +101 -0
  84. package/docs/decisions/ADR-0007-ship-v1.md +73 -0
  85. package/docs/decisions/ADR-0008-map-codebase-mermaid-togaf.md +80 -0
  86. package/docs/decisions/ADR-0009-production-deployment-checklist.md +68 -0
  87. package/docs/decisions/ADR-0010-standards-integration.md +79 -0
  88. package/docs/decisions/ADR-0011-help-commands-rewrite.md +64 -0
  89. package/docs/decisions/ADR-0012-contributors-attribution-index.md +42 -0
  90. package/docs/decisions/ADR-0013-strategic-feature-additions.md +53 -0
  91. package/docs/decisions/ADR-0014-internal-cleanup-code-quality.md +53 -0
  92. package/docs/decisions/ADR-0015-focus-auto-runner.md +296 -0
  93. package/docs/decisions/ADR-0016-enhanced-doc-sync.md +54 -0
  94. package/docs/decisions/ADR-0017-enhanced-focus-design.md +69 -0
  95. package/docs/decisions/ADR-0018-user-reality-testing.md +84 -0
  96. package/docs/decisions/ADR-0019-end-to-end-user-acceptance-testing.md +113 -0
  97. package/docs/decisions/ADR-0020-ai-drift-prevention.md +55 -0
  98. package/docs/decisions/ADR-0021-codebase-mapper-v2.md +76 -0
  99. package/docs/decisions/ADR-0022-lifecycle-completeness.md +63 -0
  100. package/docs/decisions/ADR-0023-opus-4-7-adoption.md +89 -0
  101. package/docs/decisions/ADR-0024-spec-b-v2-completion.md +137 -0
  102. package/docs/decisions/ADR-0025-behavioral-guardrails-layer.md +129 -0
  103. package/docs/decisions/ADR-0026-self-improvement-loop.md +171 -0
  104. package/docs/decisions/ADR-0027-doc-code-link-graph.md +164 -0
  105. package/docs/decisions/ADR-0028-unified-agents-skills-target.md +46 -0
  106. package/docs/decisions/ADR-0029-experiment-evaluator.md +76 -0
  107. package/docs/decisions/ADR-0030-planning-concurrency.md +37 -0
  108. package/docs/decisions/ADR-0031-focus-auto-backlog-source.md +47 -0
  109. package/docs/decisions/ADR-0032-squad-model.md +64 -0
  110. package/docs/decisions/ADR-0033-army-campaign.md +40 -0
  111. package/docs/decisions/ADR-0034-scheduled-campaigns.md +57 -0
  112. package/docs/decisions/ADR-0035-army-hud-dashboard.md +40 -0
  113. package/docs/decisions/ADR-0036-agentic-memory-architecture.md +106 -0
  114. package/docs/decisions/ADR-0037-pin-security-agents-to-opus.md +51 -0
  115. package/docs/decisions/ADR-0038-skill-aligned-decomposition.md +41 -0
  116. package/docs/decisions/ADR-0039-worktree-as-project-variant.md +37 -0
  117. package/docs/decisions/ADR-0040-memory-injection-defense.md +55 -0
  118. package/docs/decisions/ADR-0041-mcp-dual-era-bridge.md +47 -0
  119. package/docs/decisions/ADR-0042-design-parity-both-flows.md +45 -0
  120. package/docs/decisions/ADR-0043-addressable-planning-roots.md +56 -0
  121. package/docs/decisions/ADR-0044-bound-the-cached-context.md +104 -0
  122. package/docs/decisions/ADR-0045-agent-plugins-bundle.md +76 -0
  123. package/docs/decisions/ADR-0046-subagent-frontmatter-decisions.md +39 -0
  124. package/docs/decisions/ADR-0047-pan-harness.md +76 -0
  125. package/docs/decisions/ADR-0048-one-core-per-project.md +43 -0
  126. package/docs/decisions/ADR-0049-machine-verdicts-and-findings-ledger.md +116 -0
  127. package/docs/specs/ai_drift_prevention_featureai.md +286 -0
  128. package/docs/specs/codebase_mapper_v2_featureai.md +930 -0
  129. package/docs/specs/command_naming_optimization_featureai.md +930 -0
  130. package/docs/specs/comp_analysis_markdown_v1.md +149 -0
  131. package/docs/specs/continuous_autonomous_execution_featureai.md +304 -0
  132. package/docs/specs/contributors_attribution_index_featureai.md +476 -0
  133. package/docs/specs/copilot_cli_interaction_featureai.md +868 -0
  134. package/docs/specs/copilot_cli_runtime_featureai.md +647 -0
  135. package/docs/specs/custom-skills-assessment.md +461 -0
  136. package/docs/specs/deployment_audit_findings_featureai.md +243 -0
  137. package/docs/specs/doc_code_link_graph_featureai.md +253 -0
  138. package/docs/specs/documentation_alignment_cleanup_featureai.md +69 -0
  139. package/docs/specs/e2e_visual_testing_featureai.md +615 -0
  140. package/docs/specs/end_to_end_user_acceptance_testing_featureai.md +810 -0
  141. package/docs/specs/evidence-loop-plan.md +76 -0
  142. package/docs/specs/evidence_loop_featureai.md +497 -0
  143. package/docs/specs/focus-auto-optimize-category.md +449 -0
  144. package/docs/specs/focus-auto-optimize-superplan.md +188 -0
  145. package/docs/specs/focus_auto_runner_featureai.md +1102 -0
  146. package/docs/specs/focus_design_v2_featureai.md +197 -0
  147. package/docs/specs/focus_sync_v2_featureai.md +202 -0
  148. package/docs/specs/git_integration_overhaul_featureai.md +326 -0
  149. package/docs/specs/glm_zai_provider_featureai.md +200 -0
  150. package/docs/specs/googlecli_adoption_featureai.md +661 -0
  151. package/docs/specs/help_commands_rewrite_featureai.md +860 -0
  152. package/docs/specs/industry_analysis_strategic_additions_featureai.md +231 -0
  153. package/docs/specs/industry_comparison_and_feature_gaps_featureai.md +674 -0
  154. package/docs/specs/internal_cleanup_code_quality_featureai.md +486 -0
  155. package/docs/specs/investigations/README.md +31 -0
  156. package/docs/specs/investigations/digests/2026-09-28.md +47 -0
  157. package/docs/specs/investigations/digests/2026-10-08.md +62 -0
  158. package/docs/specs/investigations/digests/2026-10-10.md +61 -0
  159. package/docs/specs/investigations/features/debugger-red-loop-first.md +55 -0
  160. package/docs/specs/investigations/features/harness-cross-host-behaviour.md +93 -0
  161. package/docs/specs/investigations/features/optimize-apply-regression-gate.md +66 -0
  162. package/docs/specs/investigations/features/reviewer-smell-baseline.md +57 -0
  163. package/docs/specs/investigations/features/trace-failure-capture.md +69 -0
  164. package/docs/specs/lifecycle_completeness_featureai.md +754 -0
  165. package/docs/specs/local-first-ci.md +42 -0
  166. package/docs/specs/map_codebase_mermaid_togaf_featureai.md +805 -0
  167. package/docs/specs/market-delta-2026-09-superplan.md +310 -0
  168. package/docs/specs/market-ideas-2026-09.md +131 -0
  169. package/docs/specs/market-ideas-2026-10.md +428 -0
  170. package/docs/specs/market-ideas-ledger.md +177 -0
  171. package/docs/specs/memory-optimization-2026-10.md +285 -0
  172. package/docs/specs/multi-track-planning-roots.md +143 -0
  173. package/docs/specs/multi_model_routing_featureai.md +687 -0
  174. package/docs/specs/multi_model_routing_superplan.md +197 -0
  175. package/docs/specs/opus_47_existing_enhancements_featureai.md +247 -0
  176. package/docs/specs/opus_47_extended_features_featureai.md +363 -0
  177. package/docs/specs/opus_47_extended_features_v2_featureai.md +397 -0
  178. package/docs/specs/pan_focus_commands_featureai.md +2336 -0
  179. package/docs/specs/pan_zcode_mcp_bridge_featureai.md +120 -0
  180. package/docs/specs/product-excellence-superplan.md +315 -0
  181. package/docs/specs/product_excellence_program_2026_q4_featureai.md +365 -0
  182. package/docs/specs/production_deployment_readiness_featureai.md +433 -0
  183. package/docs/specs/production_readiness_ship_v1_featureai.md +698 -0
  184. package/docs/specs/real_test_enforcement_featureai.md +213 -0
  185. package/docs/specs/reality-check-2026-09-superplan.md +362 -0
  186. package/docs/specs/right-sized-ceremony.md +74 -0
  187. package/docs/specs/roadmap_and_competition_2026_q4_featureai.md +390 -0
  188. package/docs/specs/self_improvement_loop_featureai.md +875 -0
  189. package/docs/specs/skill-aligned-decomposition.md +155 -0
  190. package/docs/specs/standards_integration_featureai.md +833 -0
  191. package/docs/specs/testing-system-redesign-2026-09.md +267 -0
  192. package/docs/specs/user_reality_testing_system_featureai.md +788 -0
  193. package/docs/specs/watch-triggers.json +22 -0
  194. package/docs/specs/workflow-integration-redesign.md +742 -0
  195. package/docs/specs/workflow_state_consistency_featureai.md +183 -0
  196. package/hooks/dist/pan-context-monitor.js +9 -2
  197. package/hooks/dist/pan-cost-logger.js +5 -0
  198. package/hooks/dist/pan-guard.js +28 -5
  199. package/hooks/dist/pan-stop-guard.js +9 -9
  200. package/hooks/dist/pan-trace-logger.js +5 -0
  201. package/package.json +10 -2
  202. package/pan-wizard-core/bin/lib/agents-md.cjs +57 -8
  203. package/pan-wizard-core/bin/lib/autodev-report.cjs +180 -0
  204. package/pan-wizard-core/bin/lib/autodev.cjs +642 -0
  205. package/pan-wizard-core/bin/lib/ci.cjs +143 -0
  206. package/pan-wizard-core/bin/lib/commands.cjs +1 -1
  207. package/pan-wizard-core/bin/lib/config.cjs +41 -5
  208. package/pan-wizard-core/bin/lib/constants.cjs +27 -1
  209. package/pan-wizard-core/bin/lib/core.cjs +31 -14
  210. package/pan-wizard-core/bin/lib/cost.cjs +160 -4
  211. package/pan-wizard-core/bin/lib/cross-family.cjs +164 -0
  212. package/pan-wizard-core/bin/lib/debug-cases.cjs +104 -0
  213. package/pan-wizard-core/bin/lib/doc-lint.cjs +5 -3
  214. package/pan-wizard-core/bin/lib/failure-class.cjs +81 -0
  215. package/pan-wizard-core/bin/lib/findings.cjs +148 -9
  216. package/pan-wizard-core/bin/lib/focus.cjs +1 -1
  217. package/pan-wizard-core/bin/lib/git.cjs +1 -1
  218. package/pan-wizard-core/bin/lib/hosts.cjs +88 -0
  219. package/pan-wizard-core/bin/lib/init.cjs +7 -2
  220. package/pan-wizard-core/bin/lib/knowledge.cjs +2 -0
  221. package/pan-wizard-core/bin/lib/merge.cjs +50 -0
  222. package/pan-wizard-core/bin/lib/mutate.cjs +268 -0
  223. package/pan-wizard-core/bin/lib/next-action.cjs +112 -0
  224. package/pan-wizard-core/bin/lib/optimize.cjs +2 -2
  225. package/pan-wizard-core/bin/lib/phase-gate.cjs +15 -9
  226. package/pan-wizard-core/bin/lib/phase-remove.cjs +91 -11
  227. package/pan-wizard-core/bin/lib/phase.cjs +85 -13
  228. package/pan-wizard-core/bin/lib/plan-lint.cjs +310 -0
  229. package/pan-wizard-core/bin/lib/preview.cjs +26 -4
  230. package/pan-wizard-core/bin/lib/requirements-lint.cjs +130 -0
  231. package/pan-wizard-core/bin/lib/research-lint.cjs +268 -0
  232. package/pan-wizard-core/bin/lib/review-deep.cjs +14 -22
  233. package/pan-wizard-core/bin/lib/review-vote.cjs +105 -0
  234. package/pan-wizard-core/bin/lib/roadmap.cjs +1 -0
  235. package/pan-wizard-core/bin/lib/runner.cjs +2 -16
  236. package/pan-wizard-core/bin/lib/sizing.cjs +356 -0
  237. package/pan-wizard-core/bin/lib/squads.cjs +1 -1
  238. package/pan-wizard-core/bin/lib/state-write.cjs +247 -0
  239. package/pan-wizard-core/bin/lib/test-gate.cjs +433 -0
  240. package/pan-wizard-core/bin/lib/uat.cjs +149 -0
  241. package/pan-wizard-core/bin/lib/usage.cjs +104 -0
  242. package/pan-wizard-core/bin/lib/verdict.cjs +26 -3
  243. package/pan-wizard-core/bin/lib/verify-plan-set.cjs +30 -1
  244. package/pan-wizard-core/bin/lib/verify-preflight.cjs +2 -2
  245. package/pan-wizard-core/bin/lib/verify-red.cjs +174 -0
  246. package/pan-wizard-core/bin/lib/verify-retro.cjs +3 -2
  247. package/pan-wizard-core/bin/lib/verify-scope.cjs +143 -2
  248. package/pan-wizard-core/bin/lib/verify.cjs +86 -31
  249. package/pan-wizard-core/bin/lib/worktree.cjs +70 -0
  250. package/pan-wizard-core/bin/pan-tools.cjs +257 -28
  251. package/pan-wizard-core/learnings/universal/autonomous-loop.md +2 -2
  252. package/pan-wizard-core/mcp/orchestrator.cjs +4 -1
  253. package/pan-wizard-core/references/continuation-format.md +3 -3
  254. package/pan-wizard-core/references/design-methodology.md +1 -1
  255. package/pan-wizard-core/references/guardrails.md +1 -1
  256. package/pan-wizard-core/references/handoff-decisions.md +1 -1
  257. package/pan-wizard-core/references/model-profiles.md +2 -3
  258. package/pan-wizard-core/references/questioning.md +24 -0
  259. package/pan-wizard-core/references/ui-brand.md +4 -6
  260. package/pan-wizard-core/references/verdict-contract.md +2 -1
  261. package/pan-wizard-core/templates/config.json +10 -2
  262. package/pan-wizard-core/templates/debug.md +1 -0
  263. package/pan-wizard-core/templates/design.md +5 -4
  264. package/pan-wizard-core/templates/discovery.md +2 -2
  265. package/pan-wizard-core/templates/phase-prompt.md +7 -0
  266. package/pan-wizard-core/templates/requirements.md +9 -0
  267. package/pan-wizard-core/templates/research.md +10 -0
  268. package/pan-wizard-core/templates/summary-complex.md +5 -1
  269. package/pan-wizard-core/templates/summary-minimal.md +4 -0
  270. package/pan-wizard-core/templates/summary-standard.md +5 -1
  271. package/pan-wizard-core/templates/summary.md +8 -1
  272. package/pan-wizard-core/workflows/add-phase.md +4 -6
  273. package/pan-wizard-core/workflows/assumptions.md +19 -1
  274. package/pan-wizard-core/workflows/diagnose-issues.md +2 -0
  275. package/pan-wizard-core/workflows/discuss-phase.md +4 -2
  276. package/pan-wizard-core/workflows/exec-lean.md +69 -0
  277. package/pan-wizard-core/workflows/exec-phase.md +79 -15
  278. package/pan-wizard-core/workflows/execute-plan.md +3 -1
  279. package/{commands/pan → pan-wizard-core/workflows}/focus-doc-audit.md +13 -29
  280. package/{commands/pan → pan-wizard-core/workflows}/focus-drift-walking.md +3 -18
  281. package/{commands/pan → pan-wizard-core/workflows}/focus-exec.md +8 -23
  282. package/{commands/pan → pan-wizard-core/workflows}/focus-plan.md +6 -20
  283. package/{commands/pan → pan-wizard-core/workflows}/focus-scan.md +3 -16
  284. package/{commands/pan → pan-wizard-core/workflows}/focus-sync.md +7 -21
  285. package/pan-wizard-core/workflows/health.md +6 -0
  286. package/pan-wizard-core/workflows/help.md +114 -77
  287. package/pan-wizard-core/workflows/insert-phase.md +4 -6
  288. package/pan-wizard-core/workflows/learn.md +3 -3
  289. package/pan-wizard-core/workflows/milestone-audit.md +2 -2
  290. package/pan-wizard-core/workflows/milestone-new.md +38 -95
  291. package/pan-wizard-core/workflows/new-project.md +96 -258
  292. package/pan-wizard-core/workflows/optimize.md +107 -5
  293. package/pan-wizard-core/workflows/phase-tests.md +10 -0
  294. package/pan-wizard-core/workflows/plan-phase.md +106 -45
  295. package/pan-wizard-core/workflows/profile.md +50 -0
  296. package/pan-wizard-core/workflows/progress.md +10 -0
  297. package/pan-wizard-core/workflows/quick.md +34 -43
  298. package/pan-wizard-core/workflows/remove-phase.md +11 -1
  299. package/pan-wizard-core/workflows/research-phase.md +118 -40
  300. package/pan-wizard-core/workflows/resume-project.md +18 -2
  301. package/pan-wizard-core/workflows/settings.md +33 -19
  302. package/pan-wizard-core/workflows/todo-check.md +6 -2
  303. package/pan-wizard-core/workflows/transition.md +22 -4
  304. package/pan-wizard-core/workflows/uat-walkthrough.md +90 -0
  305. package/pan-wizard-core/workflows/update.md +1 -1
  306. package/pan-wizard-core/workflows/verify-phase.md +39 -46
  307. package/scripts/build-agent-plugin.js +35 -15
  308. package/scripts/build-help.cjs +106 -0
  309. package/scripts/build-plugin.js +10 -1
  310. package/scripts/deprecate-old-versions.js +70 -3
  311. package/scripts/generate-skills-docs.py +1 -1
  312. package/scripts/git-hooks/pre-push +27 -0
  313. package/scripts/install-git-hooks.js +7 -5
  314. package/scripts/install-pre-push.cjs +38 -0
  315. package/scripts/land.cjs +151 -0
  316. package/scripts/local-ci.cjs +501 -0
  317. package/scripts/local-schedule.cjs +277 -0
  318. package/scripts/mutation-probe.cjs +7 -80
  319. package/scripts/prompt-lint.cjs +32 -0
  320. package/scripts/prompt-rules.cjs +156 -0
  321. package/scripts/run-tests.cjs +7 -1
  322. package/scripts/test-quality-lint.cjs +3 -3
  323. package/scripts/test-surface.cjs +175 -6
  324. package/agents/pan-research-synthesizer.md +0 -246
  325. package/commands/pan/audit-deployment.md +0 -386
  326. package/commands/pan/dashboard.md +0 -22
  327. package/commands/pan/discord.md +0 -19
  328. package/commands/pan/mcp-bridge.md +0 -143
  329. package/commands/pan/milestone-cleanup.md +0 -19
  330. package/commands/pan/milestone-gaps.md +0 -35
  331. package/commands/pan/optimize.md +0 -115
  332. package/commands/pan/profile.md +0 -76
  333. package/commands/pan/research-phase.md +0 -189
  334. package/pan-wizard-core/bin/lib/bridge.cjs +0 -269
  335. package/pan-wizard-core/templates/research-project/architecture.md +0 -204
  336. package/pan-wizard-core/templates/research-project/features.md +0 -147
  337. package/pan-wizard-core/templates/research-project/pitfalls.md +0 -200
  338. package/pan-wizard-core/templates/research-project/stack.md +0 -120
  339. package/pan-wizard-core/templates/research-project/summary.md +0 -170
@@ -12,8 +12,7 @@ You are a PAN code reviewer. You perform read-only code review on files changed
12
12
 
13
13
  Your job: Check convention compliance, security patterns, and code quality. You do NOT modify files — you report findings. This is authorized, defensive review of the user's own codebase — surface security-relevant findings for the user to remediate; never produce exploit code.
14
14
 
15
- **CRITICAL: Mandatory Initial Read**
16
- If the prompt contains a `<files_to_read>` block, you MUST use the `Read` tool to load every file listed there before performing any other actions. This is your primary context.
15
+ **Initial read.** If the prompt contains a `<files_to_read>` block, read every file it lists before doing anything else. This is your primary context.
17
16
 
18
17
  **Read also:** `~/.claude/pan-wizard-core/references/guardrails.md` — anti-patterns and the Code Preservation Principle. Findings that violate Code Preservation (silent scope expansion, model swaps, refactor-while-here) should be flagged at high severity.
19
18
 
@@ -93,6 +92,10 @@ A fixed baseline that applies even when the project documents no standards (Fowl
93
92
 
94
93
  ## Scope (unrequested work)
95
94
 
95
+ When the prompt carries an `<intent>` block (the `review scope` JSON), it is what you judge the change against: each plan's `objective`, `must_haves` and `review_focus` (the risk the planner asked a reviewer to check, so check it first and say what you found), and the text of the requirements the plans claim. Its `unlisted` array names changed files no summary's key-files lists: review them as closely as the rest, and say in the report that the summary did not list them.
96
+
97
+ When the prompt carries an `<executor_concerns>` block, each entry is something an executor finished but was not sure of, with its cost if wrong. Check the high-cost ones against the code and report what you found: a concern that holds is a finding; one that does not, say so in a sentence.
98
+
96
99
  Compare what the changed code does with what the phase's plans asked for (their tasks and `must_haves`). Code that adds behaviour no plan task or requirement mentions is a finding: a feature nobody asked for, an unrelated refactor folded into the change, or an option no requirement needs. Use category `Unrequested` at WARNING, or at ERROR when it changes existing behaviour without a plan saying so. Its class in the `pan-verdict` block is `unrequested`. Supporting code the tasks need (tests, types, wiring) is not a finding.
97
100
 
98
101
  </review_checks>
@@ -128,7 +131,13 @@ Return a structured review report:
128
131
  {PASS | PASS_WITH_WARNINGS | NEEDS_FIXES}
129
132
  ```
130
133
 
131
- **Verdict rules:**
134
+ **Lens.** When the prompt names a `<lens>` (`correctness`, `security` or `maintainability`), review only through it. Two other passes cover the other lenses, and a vote keeps the findings at least two passes report. So report what your lens finds, and do not stretch it to cover the others.
135
+
136
+ **What you declined to judge.** If you set a behaviour aside (no way to run it, outside your lens, outside the diff), name it in the block's `declined` list as `{"behaviour": "...", "reason": "..."}`. Silence about a behaviour reads as a pass; a declined entry says it was not checked.
137
+
138
+ **Pre-existing problems.** A problem in code this phase did not change, such as an untouched file or untouched lines of a changed file, was there before the phase. Report it, tagged pre-existing, but leave it out of the verdict: it is the project's debt, not this change's defect. `review scope` and `git diff` tell you what the phase changed.
139
+
140
+ **Verdict rules** (pre-existing findings never count):
132
141
  - **PASS**: Zero errors, zero warnings
133
142
  - **PASS_WITH_WARNINGS**: Zero errors, warnings present
134
143
  - **NEEDS_FIXES**: Any errors present
@@ -138,7 +147,9 @@ Return a structured review report:
138
147
  - Add one finding per table row. ERROR → `high`, WARNING → `medium`, INFO → `info`.
139
148
  - Category maps to class: Convention → `quality`, Security → `risk`, Code Quality → `defect`, Design smell → `quality`, Unrequested → `unrequested`.
140
149
  - `where` is `file:line`.
150
+ - A pre-existing finding carries `"pre_existing": true`. The recorder files it as deferred debt with the reason, so it never blocks the phase, and the milestone audit still lists it.
141
151
  - A clean review has `"findings": []`.
152
+ - **Dismissed findings are filtered by the recorder, not by you.** When the project dismissed a finding with a reason, recording filters the same finding again for as long as its file is unchanged, and lets it back in once the file changes. Security and logic findings are never filtered. So report everything you find; do not leave out a finding because you think it was dismissed before. To see what is being filtered: `node ~/.claude/pan-wizard-core/bin/pan-tools.cjs findings suppressions --phase {phase_number} --agent pan-reviewer`.
142
153
  - **On a re-check you are given `<open_findings>`:** your earlier open findings on this phase, each with its `id`. Answer every one in a `resolutions` list in the block: `{"id":"f_…","status":"resolved","evidence":"what you checked and saw"}` when it is fixed, `still_present` when it is not, `cannot_tell` when you could not check it. A finding you leave out stays open: silence never closes a finding, and `resolved` without evidence closes nothing.
143
154
 
144
155
  The orchestrator records this block. It is how your findings reach the phase's findings ledger and `/pan:review-deep`.
@@ -16,8 +16,7 @@ You are spawned by:
16
16
 
17
17
  Your job: Transform requirements into a phase structure that delivers the project. Every v1 requirement maps to exactly one phase. Every phase has observable success criteria.
18
18
 
19
- **CRITICAL: Mandatory Initial Read**
20
- If the prompt contains a `<files_to_read>` block, you MUST use the `Read` tool to load every file listed there before performing any other actions. This is your primary context.
19
+ **Initial read.** If the prompt contains a `<files_to_read>` block, read every file it lists before doing anything else. This is your primary context.
21
20
 
22
21
  **Core responsibilities:**
23
22
  - Derive phases from requirements (not impose arbitrary structure)
@@ -334,7 +333,7 @@ Reference full template: `~/.claude/pan-wizard-core/templates/roadmap.md`
334
333
 
335
334
  ## state.md Structure
336
335
 
337
- Use template from `~/.claude/pan-wizard-core/templates/state.md`.
336
+ `pan-tools state init` writes it from the sections of `~/.claude/pan-wizard-core/templates/state.md`; you supply the values.
338
337
 
339
338
  Key sections:
340
339
  - Project Reference (core value, current focus)
@@ -352,7 +351,7 @@ Key sections:
352
351
  Orchestrator provides:
353
352
  - project.md content (core value, constraints)
354
353
  - requirements.md content (v1 requirements with REQ-IDs)
355
- - research/summary.md content (if exists - phase suggestions)
354
+ - research/research-summary.md content (if exists - phase suggestions; older projects have research/summary.md instead)
356
355
  - config.json (depth setting)
357
356
 
358
357
  Parse and confirm understanding before proceeding.
@@ -376,7 +375,7 @@ Total v1: 11 requirements
376
375
 
377
376
  ## Step 3: Load Research Context (if exists)
378
377
 
379
- If research/summary.md provided:
378
+ If research/research-summary.md (or an older project's research/summary.md) provided:
380
379
  - Extract suggested phase structure from "Implications for Roadmap"
381
380
  - Note research flags (which phases need deeper research)
382
381
  - Use as input, not mandate
@@ -415,7 +414,13 @@ If gaps found, resolve them (see Coverage Validation) and list each gap with the
415
414
 
416
415
  1. **Write roadmap.md** using output format
417
416
 
418
- 2. **Write state.md** using output format
417
+ 2. **Initialise state.md through the engine**, not with Write:
418
+
419
+ ```bash
420
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs state init --core-value "<core value from project.md>" --focus "<first phase name>" --phase <first phase number> --phase-name "<first phase name>" --total-phases <N>
421
+ ```
422
+
423
+ When state.md already exists (a new milestone), add `--force --keep-context`: the old file is backed up and its Accumulated Context carried over. The engine writes every section of the template and keeps the frontmatter in sync; never write state.md with the Write or Edit tool (under `hooks.guard: enforce` the guard denies it).
419
424
 
420
425
  3. **Update requirements.md traceability section**
421
426
 
@@ -500,7 +505,7 @@ After incorporating user feedback and updating files:
500
505
 
501
506
  **Files updated:**
502
507
  - .planning/roadmap.md
503
- - .planning/state.md (if needed)
508
+ - .planning/state.md (if needed, through `pan-tools state apply` or `state section`)
504
509
  - .planning/requirements.md (if traceability changed)
505
510
 
506
511
  ### Updated Summary
@@ -11,8 +11,7 @@ You are a PAN phase verifier. You verify that a phase achieved its GOAL, not jus
11
11
 
12
12
  Your job: Goal-backward verification. Start from what the phase SHOULD deliver, verify it actually exists and works in the codebase.
13
13
 
14
- **CRITICAL: Mandatory Initial Read**
15
- If the prompt contains a `<files_to_read>` block, you MUST use the `Read` tool to load every file listed there before performing any other actions. This is your primary context.
14
+ **Initial read.** If the prompt contains a `<files_to_read>` block, read every file it lists before doing anything else. This is your primary context.
16
15
 
17
16
  **Critical mindset:** Do NOT trust summary.md claims. SUMMARYs document what Claude SAID it did. You verify what ACTUALLY exists in the code. These often differ.
18
17
  </role>
@@ -199,6 +198,12 @@ If no must_haves in frontmatter AND no Success Criteria in ROADMAP:
199
198
 
200
199
  For each truth, determine if codebase enables it.
201
200
 
201
+ **Requirements with EARS criteria are read against their tests.** Run the trace matrix for the phase's requirement ids:
202
+ ```bash
203
+ node ~/.claude/pan-wizard-core/bin/pan-tools.cjs verify traceability <REQ-ID> <REQ-ID> …
204
+ ```
205
+ `passed` means the mapped tests pass. `failing` is a gap. `not_checked` means no test is mapped to the requirement, so list it under `not_checked` and never as verified. `legacy` (no criteria) is judged as before.
206
+
202
207
  **Verification status:**
203
208
 
204
209
  - ✓ VERIFIED: All supporting artifacts pass all checks
@@ -486,9 +491,9 @@ Unrequested work never changes the status on its own; a phase can pass with it.
486
491
 
487
492
  ## Step 8b: Run the Test Gate
488
493
 
489
- Run the project's test suite exactly as the verify-phase protocol's `run_test_suite` step says (`~/.claude/pan-wizard-core/workflows/verify-phase.md`): detect a test script first, then run it and judge the exit code before any count. Record the result in the frontmatter as `test_gate: passed | failed | skipped`. `skipped` is only for a project with no test script; a suite that exists and did not run is `failed`.
494
+ Run the test suite through the engine, as the verify-phase protocol's `run_test_suite` step says (`~/.claude/pan-wizard-core/workflows/verify-phase.md`): `pan-tools test run --phase <N>` detects the project's test command in any language, runs it, compares it with the phase's baseline and writes the record. Copy its `status` into the frontmatter as `test_gate: passed | failed | skipped`; do not run the suite yourself and do not re-judge the result. A failed record lowers a `passed` verification whatever you write, and reconcile refuses a `test_gate` that disagrees with it.
490
495
 
491
- A gate you could not run goes in `not_checked` with the reason, e.g. `- check: "tests"` / `reason: "no test script in package.json"`. If the orchestrator already ran the suite and gave you the result, record that result rather than running it again.
496
+ A `skipped` record goes in `not_checked` with the record's reason, e.g. `- check: "tests"` / `reason: "no test command: …"`. If the orchestrator already ran `test run` for this phase and gave you the result, record that result rather than running it again.
492
497
 
493
498
  ## Step 9: Determine Overall Status
494
499
 
@@ -130,6 +130,25 @@ function extractFrontmatterAndBody(content) {
130
130
  };
131
131
  }
132
132
 
133
+ /**
134
+ * Mark a Claude Code command or skill as user-invoked only (market-ideas M49): add
135
+ * `disable-model-invocation: true` to its frontmatter. Claude Code then keeps it out
136
+ * of the listing it sends the model on every turn, and it still runs as /pan:<name>.
137
+ * Seen to work on Claude Code 2.1.302 against the harness model double
138
+ * (skill-listing-claude, skill-listing-claude-commands; 2026-10-20). Claude only:
139
+ * no other runtime was seen to read the field (MI-022). Idempotent; content without
140
+ * frontmatter is returned unchanged.
141
+ * @param {string} content
142
+ * @returns {string}
143
+ */
144
+ function withClaudeUserInvokedOnly(content) {
145
+ const m = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
146
+ if (!m || /^disable-model-invocation:/m.test(m[1])) return content;
147
+ const eol = content.includes('\r\n') ? '\r\n' : '\n';
148
+ const end = m.index + m[0].length - 3; // the closing ---
149
+ return content.slice(0, end) + 'disable-model-invocation: true' + eol + content.slice(end);
150
+ }
151
+
133
152
  /** Extract a field value from YAML frontmatter string */
134
153
  function extractFrontmatterField(frontmatter, fieldName) {
135
154
  const regex = new RegExp(`^${fieldName}:\\s*(.+)$`, 'm');
@@ -593,6 +612,39 @@ function rewriteAgentFileRefs(content, runtime, pathPrefix) {
593
612
  return content.replace(new RegExp(`(${prefix}agents/pan-[a-z0-9_-]+)\\.md\\b`, 'g'), (_, base) => base + ext);
594
613
  }
595
614
 
615
+ /**
616
+ * Build the alias command for a renamed command (program L7, COMMAND_ALIASES).
617
+ * The alias is the target command itself under the old name: its frontmatter `name`
618
+ * becomes the old one, its description says what it was renamed to, and a line after
619
+ * the frontmatter presets the flags. Carrying the whole body, rather than a pointer to
620
+ * the target's installed path, is what makes it resolve on every runtime: each one
621
+ * installs commands at a different path and in a different shape. Pure.
622
+ * @param {string} targetContent - the target command's source (commands/pan/<to>.md)
623
+ * @param {string} oldName - the old command name, without prefix
624
+ * @param {{to: string, args: string}} alias
625
+ * @returns {string}
626
+ */
627
+ function renderCommandAlias(targetContent, oldName, alias) {
628
+ const now = alias.args ? `/pan:${alias.to} ${alias.args}` : `/pan:${alias.to}`;
629
+ const m = targetContent.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/);
630
+ if (!m) throw new Error(`renderCommandAlias: ${alias.to} has no frontmatter`);
631
+ const fm = m[1].split(/\r?\n/).map((line) => {
632
+ const name = line.match(/^name:\s*(pan:)?\S+/);
633
+ if (name) return `name: ${name[1] || ''}${oldName}`;
634
+ const desc = line.match(/^description:\s*(.*)$/);
635
+ if (desc) {
636
+ const raw = desc[1].trim();
637
+ const unq = raw.match(/^(["'])([\s\S]*)\1$/);
638
+ const text = (unq ? unq[2].replace(/\\"/g, '"') : raw).replace(/\\/g, '\\\\').replace(/"/g, '\\"');
639
+ return `description: "Renamed: now ${now}. ${text}"`;
640
+ }
641
+ return line;
642
+ });
643
+ const preset = alias.args ? `${alias.args} $ARGUMENTS` : '$ARGUMENTS';
644
+ const note = `> \`/pan:${oldName}\` is now \`${now}\`. Run the command below with the arguments \`${preset}\`.\n\n`;
645
+ return `---\n${fm.join('\n')}\n---\n${note}${targetContent.slice(m[0].length)}`;
646
+ }
647
+
596
648
  function rewriteAgentReferenceCopy(content, corePrefix) {
597
649
  content = content.replace(/~\/\.claude\/pan-wizard-core\//g, `${corePrefix}pan-wizard-core/`);
598
650
  content = content.replace(/\.\/\.claude\/pan-wizard-core\//g, `${corePrefix}pan-wizard-core/`);
@@ -708,7 +760,8 @@ function buildCopilotPluginHooksConfig(commands) {
708
760
  const { updateCheckCommand, contextMonitorCommand, costLoggerCommand, traceLoggerCommand, stopGuardCommand } = commands || {};
709
761
  const hooks = {};
710
762
  if (updateCheckCommand) hooks.SessionStart = [{ type: 'command', command: updateCheckCommand }];
711
- if (contextMonitorCommand) hooks.PostToolUse = [{ type: 'command', command: contextMonitorCommand }];
763
+ // No context monitor: it cannot measure on Copilot (HOOK_EVENT_MAP, M50).
764
+ if (contextMonitorCommand && HOOK_EVENT_MAP.copilot.postToolUse) hooks.PostToolUse = [{ type: 'command', command: contextMonitorCommand }];
712
765
  const subagentStop = [];
713
766
  if (costLoggerCommand) subagentStop.push({ type: 'command', command: costLoggerCommand });
714
767
  if (traceLoggerCommand) subagentStop.push({ type: 'command', command: traceLoggerCommand });
@@ -1171,7 +1224,7 @@ function buildCopilotHooksConfig(commands) {
1171
1224
  config.hooks.preToolUse = [{ type: 'command', command: guardCommand }];
1172
1225
  }
1173
1226
  const postToolUse = [];
1174
- if (contextMonitorCommand) postToolUse.push({ type: 'command', command: contextMonitorCommand });
1227
+ if (contextMonitorCommand && HOOK_EVENT_MAP.copilot.postToolUse) postToolUse.push({ type: 'command', command: contextMonitorCommand });
1175
1228
  // State re-injection after a compaction (M33): preCompact leaves the marker, the
1176
1229
  // next postToolUse returns the block once (hooks/pan-state-reinject.js).
1177
1230
  if (stateReinjectInjectCommand) postToolUse.push({ type: 'command', command: stateReinjectInjectCommand });
@@ -1241,12 +1294,19 @@ function buildCopilotHooksConfig(commands) {
1241
1294
  * next tool result, the first point after it where both hosts take added context
1242
1295
  * (gemini-cli v0.61.0 docs/hooks/reference.md; Copilot hooks reference; read
1243
1296
  * 2026-10-03, and live on Copilot CLI 1.0.88 the same day).
1297
+ *
1298
+ * `postToolUse` is the context monitor's slot, and it is set only where the monitor
1299
+ * can measure (market-ideas M50). Its numbers come from Claude Code's status-line
1300
+ * bridge or a Claude-shaped transcript. Copilot sends camelCase `sessionId`, so the
1301
+ * hook exited at its session_id check on every call. Codex has no bridge, and its
1302
+ * transcripts are not Claude-shaped. Both events exist on those hosts, but PAN
1303
+ * registers nothing there (reality check 2026-10-19).
1244
1304
  */
1245
1305
  const HOOK_EVENT_MAP = Object.freeze({
1246
1306
  claude: { surface: 'settings.json', sessionStart: 'SessionStart', preToolUse: 'PreToolUse', postToolUse: 'PostToolUse', subagentStop: 'SubagentStop', stop: 'Stop', compact: 'SessionStart', compactMark: null, compactInject: null },
1247
1307
  gemini: { surface: 'settings.json', sessionStart: 'SessionStart', preToolUse: 'BeforeTool', postToolUse: null, subagentStop: null, stop: 'AfterAgent', compact: null, compactMark: 'PreCompress', compactInject: 'AfterTool' },
1248
- codex: { surface: 'hooks.json', sessionStart: 'SessionStart', preToolUse: 'PreToolUse', postToolUse: 'PostToolUse', subagentStop: 'SubagentStop', stop: 'Stop', compact: 'SessionStart', compactMark: null, compactInject: null },
1249
- copilot: { surface: 'hooks/pan.json', sessionStart: 'sessionStart', preToolUse: 'preToolUse', postToolUse: 'postToolUse', subagentStop: 'subagentStop', stop: 'agentStop', compact: null, compactMark: 'preCompact', compactInject: 'postToolUse' },
1308
+ codex: { surface: 'hooks.json', sessionStart: 'SessionStart', preToolUse: 'PreToolUse', postToolUse: null, subagentStop: 'SubagentStop', stop: 'Stop', compact: 'SessionStart', compactMark: null, compactInject: null },
1309
+ copilot: { surface: 'hooks/pan.json', sessionStart: 'sessionStart', preToolUse: 'preToolUse', postToolUse: null, subagentStop: 'subagentStop', stop: 'agentStop', compact: null, compactMark: 'preCompact', compactInject: 'postToolUse' },
1250
1310
  opencode: null,
1251
1311
  });
1252
1312
 
@@ -1543,7 +1603,7 @@ function mergeCodexHooksConfig(existing, commands) {
1543
1603
  ['SessionStart', updateCheckCommand, 'pan-check-update', true],
1544
1604
  // The guard decides whether a call may run, which an async handler cannot (A7).
1545
1605
  ['PreToolUse', guardCommand, 'pan-guard', false],
1546
- ['PostToolUse', contextMonitorCommand, 'pan-context-monitor', false],
1606
+ ['PostToolUse', HOOK_EVENT_MAP.codex.postToolUse ? contextMonitorCommand : null, 'pan-context-monitor', false],
1547
1607
  ['SubagentStop', costLoggerCommand, 'pan-cost-logger', true],
1548
1608
  ['SubagentStop', traceLoggerCommand, 'pan-trace-logger', true],
1549
1609
  ['Stop', stopGuardCommand, 'pan-stop-guard', false],
@@ -1572,6 +1632,14 @@ function mergeCodexHooksConfig(existing, commands) {
1572
1632
  if (async) handler.async = true;
1573
1633
  config.hooks[event].push({ ...(matcher ? { matcher } : {}), hooks: [handler] });
1574
1634
  }
1635
+ // An install from before M50 registered the context monitor here; it cannot measure
1636
+ // on Codex, so an upgrade drops that handler (foreign hooks in the group stay).
1637
+ if (!HOOK_EVENT_MAP.codex.postToolUse && Array.isArray(config.hooks.PostToolUse)) {
1638
+ config.hooks.PostToolUse = config.hooks.PostToolUse
1639
+ .map((group) => (Array.isArray(group.hooks) ? { ...group, hooks: group.hooks.filter((h) => !(h && h.command && h.command.includes('pan-context-monitor'))) } : group))
1640
+ .filter((group) => !Array.isArray(group.hooks) || group.hooks.length > 0);
1641
+ if (config.hooks.PostToolUse.length === 0) delete config.hooks.PostToolUse;
1642
+ }
1575
1643
  return config;
1576
1644
  }
1577
1645
 
@@ -2338,6 +2406,7 @@ return { areas_mapped: maps.filter(Boolean).length, synthesis }
2338
2406
  phases: [
2339
2407
  { title: 'Index', detail: 'plan inventory with wave grouping, from the PAN engine' },
2340
2408
  { title: 'Execute', detail: 'one executor per plan; waves in order, plans within a wave in parallel' },
2409
+ { title: 'Review', detail: 'pan-reviewer over the phase diff (review scope); the verdict recorded, and the phase budget read' },
2341
2410
  { title: 'Verify', detail: 'the phase verifier over the completed plans' },
2342
2411
  { title: 'Gate', detail: 'the PAN phase gate: stops when the phase may not be completed' },
2343
2412
  ],
@@ -2361,8 +2430,10 @@ const INDEX = {
2361
2430
  phase_name: { type: 'string' },
2362
2431
  phase_dir: { type: 'string' },
2363
2432
  parallelization: { type: 'boolean' },
2433
+ worktree_isolation: { type: 'boolean' },
2364
2434
  verifier_enabled: { type: 'boolean' },
2365
2435
  has_checkpoints: { type: 'boolean' },
2436
+ test_baseline: { type: 'string' },
2366
2437
  plans: {
2367
2438
  type: 'array',
2368
2439
  items: {
@@ -2371,6 +2442,7 @@ const INDEX = {
2371
2442
  id: { type: 'string' },
2372
2443
  file: { type: 'string' },
2373
2444
  wave: { type: 'integer' },
2445
+ sub_wave: { type: 'integer' },
2374
2446
  autonomous: { type: 'boolean' },
2375
2447
  has_summary: { type: 'boolean' },
2376
2448
  objective: { type: 'string' },
@@ -2382,7 +2454,7 @@ const INDEX = {
2382
2454
  required: ['phase_found', 'has_checkpoints', 'plans'],
2383
2455
  }
2384
2456
  const index = await agent(
2385
- 'Index phase ' + phaseArg + ' for execution using the ' + PAN_TOOLS + ' Run two verbs and merge their JSON: (1) init execute-phase ' + phaseArg + ' — take phase_found, phase_number, phase_name, phase_dir, parallelization, verifier_enabled; (2) phase-plan-index ' + phaseArg + ' — take has_checkpoints and plans[] (id, wave, autonomous, has_summary, objective; include each plan file path as file). Do not execute anything; return only the merged index.',
2457
+ 'Index phase ' + phaseArg + ' for execution using the ' + PAN_TOOLS + ' Run two verbs and merge their JSON: (1) init execute-phase ' + phaseArg + ' — take phase_found, phase_number, phase_name, phase_dir, parallelization, worktree_isolation, verifier_enabled; (2) phase-plan-index ' + phaseArg + ' — take has_checkpoints and plans[] (id, wave, sub_wave, autonomous, has_summary, objective; include each plan file path as file). Then, only if phase_found is true and has_checkpoints is false, (3) test run --phase ' + phaseArg + ' --baseline — it records what the test suite does before the first wave, so the verifier can tell a failure this phase caused from one it inherited; a phase that already has a baseline keeps it (kept_existing), and a failing or empty baseline is not an error. Put one line describing its result in test_baseline. Do not execute any plan; return only the merged index.',
2386
2458
  { label: 'index', phase: 'Index', schema: INDEX })
2387
2459
  if (!index || !index.phase_found) return { error: 'phase ' + phaseArg + ' not found' }
2388
2460
  if (index.has_checkpoints) {
@@ -2391,6 +2463,14 @@ if (index.has_checkpoints) {
2391
2463
  const pending = index.plans.filter(p => !p.has_summary)
2392
2464
  if (pending.length === 0) return { phase: phaseArg, done: true, message: 'every plan already has a summary — nothing to execute' }
2393
2465
  const waveNumbers = [...new Set(pending.map(p => p.wave))].sort((a, b) => a - b)
2466
+ // A3: plans of one wave that modify the same file are in different sub-waves, run in turn.
2467
+ const groups = []
2468
+ for (const w of waveNumbers) {
2469
+ const inWave = pending.filter(p => p.wave === w)
2470
+ for (const sw of [...new Set(inWave.map(p => p.sub_wave || 0))].sort((a, b) => a - b)) groups.push({ wave: w, sub: sw, plans: inWave.filter(p => (p.sub_wave || 0) === sw) })
2471
+ }
2472
+ // workflow.worktree_isolation: each executor works in its own git worktree.
2473
+ const iso = index.worktree_isolation === true ? { isolation: 'worktree' } : {}
2394
2474
  const parallelWithinWave = index.parallelization !== false
2395
2475
  log(pending.length + ' plans across ' + waveNumbers.length + ' wave(s)' + (parallelWithinWave ? '' : ', sequential within waves'))
2396
2476
 
@@ -2414,17 +2494,18 @@ const executorPrompt = (p) =>
2414
2494
  + 'Report plan_id, status (complete | failed | checkpoint), summary_path, the number of commits you made, and self_check (passed if your summary carries no "Self-Check: FAILED" marker).'
2415
2495
  const executed = []
2416
2496
  let halted = null
2417
- for (const w of waveNumbers) {
2418
- const wavePlans = pending.filter(p => p.wave === w)
2419
- log('wave ' + w + ': ' + wavePlans.map(p => p.id).join(', '))
2497
+ for (const g of groups) {
2498
+ const w = g.wave
2499
+ const wavePlans = g.plans
2500
+ log('wave ' + w + (g.sub ? '.' + g.sub : '') + ': ' + wavePlans.map(p => p.id).join(', '))
2420
2501
  let results
2421
2502
  if (parallelWithinWave) {
2422
2503
  results = await parallel(wavePlans.map(p => () =>
2423
- agent(executorPrompt(p), { agentType: 'pan-executor', label: 'exec:' + p.id, phase: 'Execute', schema: EXEC_RESULT })))
2504
+ agent(executorPrompt(p), { agentType: 'pan-executor', label: 'exec:' + p.id, phase: 'Execute', schema: EXEC_RESULT, ...iso })))
2424
2505
  } else {
2425
2506
  results = []
2426
2507
  for (const p of wavePlans) {
2427
- results.push(await agent(executorPrompt(p), { agentType: 'pan-executor', label: 'exec:' + p.id, phase: 'Execute', schema: EXEC_RESULT }))
2508
+ results.push(await agent(executorPrompt(p), { agentType: 'pan-executor', label: 'exec:' + p.id, phase: 'Execute', schema: EXEC_RESULT, ...iso }))
2428
2509
  }
2429
2510
  }
2430
2511
  const settled = results.filter(Boolean)
@@ -2441,9 +2522,44 @@ for (const w of waveNumbers) {
2441
2522
  if (halted) {
2442
2523
  return { phase: phaseArg, halted, executed, next: 'Inspect the failed plan(s), then re-run /pan-exec-waves ' + phaseArg + ' (completed plans are skipped) or fall back to /pan:exec-phase ' + phaseArg }
2443
2524
  }
2525
+
2526
+ // Code review before verification, as in exec-phase.md (code_review). The reviewer is
2527
+ // read-only, so a second agent saves its report, records the verdict in the findings
2528
+ // ledger and reads the phase budget. A script cannot ask "fix before verification?",
2529
+ // so NEEDS_FIXES halts and hands the choice back. { skipReview: true } in args skips it,
2530
+ // like --skip-review.
2531
+ phase('Review')
2532
+ const skipReview = !!(args && typeof args === 'object' && args.skipReview === true)
2533
+ let review = null
2534
+ if (!skipReview) {
2535
+ const REPORT = { type: 'object', properties: { report: { type: 'string' } }, required: ['report'] }
2536
+ const reviewed = await agent(
2537
+ 'Review the code phase ' + phaseArg + ' changed, following your agent definition. Get the scope with the ' + PAN_TOOLS + ' Run review scope ' + phaseArg + ' (JSON: the changed files, the unlisted ones no summary names, and the intent to judge them against: objectives, must_haves, Review Focus) and findings list --phase ' + phaseArg + ' --agent pan-reviewer --status open (your earlier open findings; answer each in resolutions). Review every file in the scope, unlisted ones included. Return your full report, verbatim, closing pan-verdict block included, as report.',
2538
+ { agentType: 'pan-reviewer', label: 'review', phase: 'Review', schema: REPORT })
2539
+ const RECORD = {
2540
+ type: 'object',
2541
+ properties: {
2542
+ verdict: { type: 'string', enum: ['PASS', 'PASS_WITH_WARNINGS', 'NEEDS_FIXES', 'unknown'] },
2543
+ errors: { type: 'integer' },
2544
+ warnings: { type: 'integer' },
2545
+ review_path: { type: 'string' },
2546
+ budget_status: { type: 'string' },
2547
+ budget_line: { type: 'string' },
2548
+ },
2549
+ required: ['verdict'],
2550
+ }
2551
+ review = await agent(
2552
+ 'Record a PAN code review for phase ' + phaseArg + ' with the ' + PAN_TOOLS + ' (1) Write the report below, verbatim and in full, to ' + (index.phase_dir || '.planning/phases/<phase dir>') + '/' + (index.phase_number || phaseArg) + '-review.md. (2) Run findings record --phase ' + phaseArg + ' --agent pan-reviewer --file <that path> --raw and take the verdict it prints (if it fails, read the word under ### Verdict in the report). (3) If the verdict is PASS_WITH_WARNINGS, run findings dispose --phase ' + phaseArg + ' --agent pan-reviewer --open --as deferred --reason "accepted at review: PASS_WITH_WARNINGS". (4) Run cost budget --phase ' + phaseArg + ' and report its status as budget_status; when it is near or over, set budget_line to "Spend: <spent_usd> of the <budget_usd> phase budget (<pct>%)", adding "over budget: the phase keeps running" for over. The budget warns, it never blocks. Return verdict, error and warning counts, review_path, budget_status and budget_line. Do not change any code.\\n\\nREPORT:\\n' + ((reviewed && reviewed.report) || '(the reviewer returned no report)'),
2553
+ { label: 'review-record', phase: 'Review', schema: RECORD })
2554
+ if (review && review.budget_line) log(review.budget_line)
2555
+ if (!review || !review.verdict || review.verdict === 'NEEDS_FIXES' || review.verdict === 'unknown') {
2556
+ return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, review, halted: 'review', next: 'The review ' + (review ? 'found errors (' + review.verdict + ')' : 'returned no verdict') + '. Fix them and re-run /pan-exec-waves ' + phaseArg + ', or continue past them with /pan:exec-phase ' + phaseArg + ', which asks and records why. Do not mark the phase complete yet.' }
2557
+ }
2558
+ }
2559
+
2444
2560
  // workflow.verifier: false (/pan:settings) turns the phase verifier off, as in exec-phase.
2445
2561
  if (index.verifier_enabled === false) {
2446
- return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, verification: null, next: 'Verification skipped: workflow.verifier is off. /pan:verify-phase ' + phaseArg + ' verifies on demand; then continue with /pan:exec-phase ' + phaseArg + ' (transition)' }
2562
+ return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, review, verification: null, next: 'Verification skipped: workflow.verifier is off. /pan:verify-phase ' + phaseArg + ' verifies on demand; then continue with /pan:exec-phase ' + phaseArg + ' (transition)' }
2447
2563
  }
2448
2564
 
2449
2565
  phase('Verify')
@@ -2476,9 +2592,9 @@ const gate = await agent(
2476
2592
  { label: 'gate', phase: 'Gate', schema: GATE })
2477
2593
  const gateReasons = gate && Array.isArray(gate.reasons) ? gate.reasons : []
2478
2594
  if (!gate || gate.ok !== true) {
2479
- return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, verification: verdict, gate, halted: 'phase_gate', next: 'The phase gate refused: ' + (gateReasons.map((r) => r.code).join(', ') || 'the gate step returned no verdict') + '. Fix each reason (or close the gaps with /pan:plan-phase ' + phaseArg + ' --gaps), then re-run /pan:exec-phase ' + phaseArg + '. Do not mark the phase complete until the gate passes.' }
2595
+ return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, review, verification: verdict, gate, halted: 'phase_gate', next: 'The phase gate refused: ' + (gateReasons.map((r) => r.code).join(', ') || 'the gate step returned no verdict') + '. Fix each reason (or close the gaps with /pan:plan-phase ' + phaseArg + ' --gaps), then re-run /pan:exec-phase ' + phaseArg + '. Do not mark the phase complete until the gate passes.' }
2480
2596
  }
2481
- return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, verification: verdict, gate, next: 'The phase gate passes. Continue with /pan:exec-phase ' + phaseArg + ' (transition) or /pan:plan-phase for the next phase' }
2597
+ return { phase: phaseArg, waves_run: waveNumbers.length, plans_complete: executed.length, review, verification: verdict, gate, next: 'The phase gate passes. Continue with /pan:exec-phase ' + phaseArg + ' (transition) or /pan:plan-phase for the next phase' }
2482
2598
  `;
2483
2599
 
2484
2600
  const diagnoseIssues = `export const meta = {
@@ -2589,6 +2705,7 @@ const {
2589
2705
  PAN_AGENTS_END,
2590
2706
  buildAgentsMdSection,
2591
2707
  upsertAgentsMdSection,
2708
+ sectionState,
2592
2709
  removeAgentsMdSection,
2593
2710
  ensureClaudeMdImport,
2594
2711
  removeClaudeMdImport,
@@ -2597,6 +2714,8 @@ const {
2597
2714
  // ─── Exports ────────────────────────────────────────────────────────────────
2598
2715
 
2599
2716
  module.exports = {
2717
+ withClaudeUserInvokedOnly,
2718
+ renderCommandAlias,
2600
2719
  // Constants
2601
2720
  colorNameToHex,
2602
2721
  claudeToOpencodeTools,
@@ -2696,6 +2815,7 @@ module.exports = {
2696
2815
  // AGENTS.md universal rules layer (ADR-0028 Phase 3)
2697
2816
  buildAgentsMdSection,
2698
2817
  upsertAgentsMdSection,
2818
+ sectionState,
2699
2819
  removeAgentsMdSection,
2700
2820
  ensureClaudeMdImport,
2701
2821
  removeClaudeMdImport,
package/bin/install.js CHANGED
@@ -47,7 +47,7 @@ const pkg = require('../package.json');
47
47
  // that keep the advice actionable. Nothing in PAN gates on these values.
48
48
  const RECOMMENDED_MODELS = {
49
49
  flagship: 'claude-fable-5-1',
50
- reasoningTier: 'claude-opus-5 / claude-opus-4-8',
50
+ reasoningTier: 'claude-opus-5-5',
51
51
  };
52
52
 
53
53
  // Source repo root — prevent installing PAN into its own source directory
@@ -673,7 +673,14 @@ function mirrorUnifiedSkillsForClaude(sharedSkillsDir, targetDir, prefix) {
673
673
  try {
674
674
  fs.mkdirSync(destDir, { recursive: true });
675
675
  for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
676
- if (entry.isFile()) fs.copyFileSync(path.join(srcDir, entry.name), path.join(destDir, entry.name));
676
+ if (!entry.isFile()) continue;
677
+ // SKILL.md gains disable-model-invocation for Claude Code (M49); the shared
678
+ // tree keeps the plain file, since no other runtime was seen to read the field.
679
+ if (entry.name === 'SKILL.md') {
680
+ fs.writeFileSync(path.join(destDir, entry.name), lib.withClaudeUserInvokedOnly(fs.readFileSync(path.join(srcDir, entry.name), 'utf8')));
681
+ } else {
682
+ fs.copyFileSync(path.join(srcDir, entry.name), path.join(destDir, entry.name));
683
+ }
677
684
  }
678
685
  copied++;
679
686
  } catch (err) { pushInstallWarning('claudeSkillMirror', `skills/${name}`, err); }
@@ -845,6 +852,33 @@ function copyCommandsAsCopilotSkills(srcDir, skillsDir, prefix, pathPrefix, runt
845
852
  * @param {string} pathPrefix - Path prefix for file references
846
853
  * @param {string} runtime - Target runtime ('claude', 'opencode', 'gemini', 'codex', 'copilot')
847
854
  */
855
+ /**
856
+ * The command source every runtime installs from: commands/pan/ plus an alias command
857
+ * for each renamed command (COMMAND_ALIASES, program L7), so an old name keeps working
858
+ * on all five runtimes. The aliases are generated into a staging copy in the OS temp
859
+ * directory, removed when the installer exits; with no aliases it is commands/pan/.
860
+ */
861
+ let stagedCommandSource = null;
862
+ function stageCommandSource(src) {
863
+ const panSrc = path.join(src, 'commands', 'pan');
864
+ if (stagedCommandSource && stagedCommandSource.src === src) return stagedCommandSource.dir;
865
+ let aliases = {};
866
+ try { aliases = require(path.join(src, 'pan-wizard-core', 'bin', 'lib', 'constants.cjs')).COMMAND_ALIASES || {}; } catch {}
867
+ if (Object.keys(aliases).length === 0) return panSrc;
868
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'pan-commands-'));
869
+ for (const f of fs.readdirSync(panSrc)) {
870
+ if (f.endsWith('.md')) fs.copyFileSync(path.join(panSrc, f), path.join(dir, f));
871
+ }
872
+ for (const [oldName, alias] of Object.entries(aliases)) {
873
+ const target = path.join(panSrc, `${alias.to}.md`);
874
+ if (!fs.existsSync(target) || fs.existsSync(path.join(panSrc, `${oldName}.md`))) continue;
875
+ fs.writeFileSync(path.join(dir, `${oldName}.md`), lib.renderCommandAlias(fs.readFileSync(target, 'utf8'), oldName, alias));
876
+ }
877
+ stagedCommandSource = { src, dir };
878
+ process.on('exit', () => { try { fs.rmSync(dir, { recursive: true, force: true }); } catch {} });
879
+ return dir;
880
+ }
881
+
848
882
  function copyWithPathReplacement(srcDir, destDir, pathPrefix, runtime, isCommand = false) {
849
883
  const isOpencode = runtime === 'opencode';
850
884
  const isCodex = runtime === 'codex';
@@ -907,6 +941,9 @@ function copyWithPathReplacement(srcDir, destDir, pathPrefix, runtime, isCommand
907
941
  content = convertClaudeToCopilotMarkdown(content);
908
942
  fs.writeFileSync(destPath, content);
909
943
  } else {
944
+ // Claude Code: PAN's commands are user-invoked only (M49), so their
945
+ // descriptions stay out of the listing the model gets every turn.
946
+ if (runtime === 'claude' && isCommand) content = lib.withClaudeUserInvokedOnly(content);
910
947
  fs.writeFileSync(destPath, content);
911
948
  }
912
949
  } catch (err) {
@@ -2244,6 +2281,8 @@ function install(isGlobal, runtime = 'claude') {
2244
2281
  // With its newline, as the per-runtime core writes it: `/pan:update` cats the file
2245
2282
  // and prints the runtime flag next, which glued onto a bare version.
2246
2283
  try { fs.writeFileSync(path.join(sharedCoreDest, 'VERSION'), pkg.version + '\n'); } catch { /* non-fatal */ }
2284
+ // `/pan:update` points at the changelog beside VERSION, so the shared core carries it too.
2285
+ try { fs.copyFileSync(path.join(src, 'CHANGELOG.md'), path.join(sharedCoreDest, 'CHANGELOG.md')); } catch { /* non-fatal */ }
2247
2286
 
2248
2287
  // Canonical agent-definition reference copies (ADR-0028 agent-ref
2249
2288
  // canonicalization): shared content references these instead of the
@@ -2264,7 +2303,7 @@ function install(isGlobal, runtime = 'claude') {
2264
2303
  }
2265
2304
  console.log(` ${green}✓${reset} Installed shared pan-wizard-core to ${isGlobal ? '~/.agents/' : '.agents/'}`);
2266
2305
 
2267
- const panSrc = path.join(src, 'commands', 'pan');
2306
+ const panSrc = stageCommandSource(src);
2268
2307
  copyCommandsAsUnifiedSkills(panSrc, skillsDir, 'pan', pathPrefix, corePrefix, runtime);
2269
2308
  sweepProprietaryCommandSurfaces(targetDir, runtime);
2270
2309
 
@@ -2293,7 +2332,7 @@ function install(isGlobal, runtime = 'claude') {
2293
2332
  fs.mkdirSync(commandDir, { recursive: true });
2294
2333
 
2295
2334
  // Copy commands/pan/*.md as commands/pan-*.md (flatten structure)
2296
- const panSrc = path.join(src, 'commands', 'pan');
2335
+ const panSrc = stageCommandSource(src);
2297
2336
  copyFlattenedCommands(panSrc, commandDir, 'pan', pathPrefix, runtime);
2298
2337
 
2299
2338
  // Upgrade path: remove PAN files left in the legacy singular command/
@@ -2317,7 +2356,7 @@ function install(isGlobal, runtime = 'claude') {
2317
2356
  // Codex reads skills from the shared .agents/skills tree (repo or user
2318
2357
  // scope) — $CODEX_HOME/skills is no longer a read location (2026-06).
2319
2358
  const skillsDir = getCodexSkillsRoot(isGlobal);
2320
- const panSrc = path.join(src, 'commands', 'pan');
2359
+ const panSrc = stageCommandSource(src);
2321
2360
  copyCommandsAsCodexSkills(panSrc, skillsDir, 'pan', pathPrefix, runtime);
2322
2361
 
2323
2362
  // Upgrade path: remove pan-* skills left in the legacy .codex/skills/
@@ -2340,7 +2379,7 @@ function install(isGlobal, runtime = 'claude') {
2340
2379
  }
2341
2380
  } else if (isCopilot) {
2342
2381
  const skillsDir = path.join(targetDir, 'skills');
2343
- const panSrc = path.join(src, 'commands', 'pan');
2382
+ const panSrc = stageCommandSource(src);
2344
2383
  copyCommandsAsCopilotSkills(panSrc, skillsDir, 'pan', pathPrefix, runtime);
2345
2384
  const installedSkills = fs.readdirSync(skillsDir, { withFileTypes: true })
2346
2385
  .filter(e => e.isDirectory() && e.name.startsWith('pan-'));
@@ -2354,7 +2393,7 @@ function install(isGlobal, runtime = 'claude') {
2354
2393
  const commandsDir = path.join(targetDir, 'commands');
2355
2394
  fs.mkdirSync(commandsDir, { recursive: true });
2356
2395
 
2357
- const panSrc = path.join(src, 'commands', 'pan');
2396
+ const panSrc = stageCommandSource(src);
2358
2397
  const panDest = path.join(commandsDir, 'pan');
2359
2398
  copyWithPathReplacement(panSrc, panDest, pathPrefix, runtime, true);
2360
2399
  if (verifyInstalled(panDest, 'commands/pan')) {
@@ -2671,15 +2710,23 @@ function install(isGlobal, runtime = 'claude') {
2671
2710
  const agentsMdPath = path.join(process.cwd(), 'AGENTS.md');
2672
2711
  let agentsExisting = null;
2673
2712
  try { agentsExisting = fs.readFileSync(agentsMdPath, 'utf8'); } catch { /* absent */ }
2674
- fs.writeFileSync(agentsMdPath, lib.upsertAgentsMdSection(agentsExisting, lib.buildAgentsMdSection()));
2675
- console.log(` ${green}✓${reset} ${agentsExisting === null ? 'Created' : 'Updated'} AGENTS.md (PAN section)`);
2713
+ if (lib.sectionState(agentsExisting, 'agents') === 'edited') {
2714
+ // The project rewrote PAN's section for itself: an update must not put PAN's
2715
+ // generic text back over it (field report, 2026-10-21).
2716
+ console.log(` ${yellow}!${reset} AGENTS.md: kept the PAN section this project edited. To take PAN's current text, delete the section between the PAN WIZARD markers and run the installer again.`);
2717
+ } else {
2718
+ fs.writeFileSync(agentsMdPath, lib.upsertAgentsMdSection(agentsExisting, lib.buildAgentsMdSection()));
2719
+ console.log(` ${green}✓${reset} ${agentsExisting === null ? 'Created' : 'Updated'} AGENTS.md (PAN section)`);
2720
+ }
2676
2721
 
2677
2722
  if (runtime === 'claude') {
2678
2723
  const claudeMdPath = path.join(process.cwd(), 'CLAUDE.md');
2679
2724
  let claudeExisting = null;
2680
2725
  try { claudeExisting = fs.readFileSync(claudeMdPath, 'utf8'); } catch { /* absent */ }
2681
2726
  const bridged = lib.ensureClaudeMdImport(claudeExisting);
2682
- if (bridged !== claudeExisting) {
2727
+ if (lib.sectionState(claudeExisting, 'claude') === 'edited') {
2728
+ console.log(` ${yellow}!${reset} CLAUDE.md: kept the PAN block this project edited (the @AGENTS.md import and compact instructions).`);
2729
+ } else if (bridged !== claudeExisting) {
2683
2730
  fs.writeFileSync(claudeMdPath, bridged);
2684
2731
  console.log(` ${green}✓${reset} Bridged CLAUDE.md to AGENTS.md (@AGENTS.md import)`);
2685
2732
  }
@@ -2795,7 +2842,7 @@ function install(isGlobal, runtime = 'claude') {
2795
2842
  // Print the path we actually wrote. The hardcoded '.codex/hooks.json' was
2796
2843
  // wrong for --global and for --config-dir, telling users to inspect a file
2797
2844
  // that does not exist while the real one sat elsewhere.
2798
- console.log(` ${green}✓${reset} Configured hooks (${displayPath(hooksJsonPath)}: update check, context monitor, cost + trace loggers, stop guard, state re-injection)`);
2845
+ console.log(` ${green}✓${reset} Configured hooks (${displayPath(hooksJsonPath)}: update check, guard, cost + trace loggers, stop guard, state re-injection)`);
2799
2846
  } catch (e) {
2800
2847
  pushInstallWarning('codexHooks', 'hooks.json', e);
2801
2848
  }
@@ -2812,7 +2859,7 @@ function install(isGlobal, runtime = 'claude') {
2812
2859
  fs.mkdirSync(path.dirname(hooksConfigPath), { recursive: true });
2813
2860
  fs.writeFileSync(hooksConfigPath, JSON.stringify(hooksConfig, null, 2) + '\n');
2814
2861
  // Same as the Codex case: a global Copilot install writes to ~/.copilot/, not .github/.
2815
- console.log(` ${green}✓${reset} Configured hooks (${displayPath(hooksConfigPath)}: update check, context monitor, cost + trace loggers, stop guard, state re-injection)`);
2862
+ console.log(` ${green}✓${reset} Configured hooks (${displayPath(hooksConfigPath)}: update check, guard, cost + trace loggers, stop guard, state re-injection)`);
2816
2863
  } catch (e) {
2817
2864
  console.error(` ${yellow}✗${reset} Failed to write Copilot hooks config: ${e.message}`);
2818
2865
  }
@@ -133,7 +133,7 @@ Spawn the conductor in campaign mode (it plans, it does not code). It decomposes
133
133
  Spawn the Quality squad on the built tree (parallel, read-only). Merge findings into one verdict (`/pan:review-deep` if available). `block` / `review_required` → fix serially, then re-review. Never integrate red.
134
134
 
135
135
  ### Phase 5 — Integrate (Release, human-gated)
136
- Spawn `pan-release`. It prepares the squash-merge, runs the configured `verification`, and surfaces an **always-ask** approval request. A human approves the merge to the protected branch; release then tags and records the rollback target. `--push` pushes the approved result.
136
+ Spawn `pan-release`. It prepares the squash-merge, runs the configured `verification`, stages the merge with `pan-tools merge request <branch> --phase <N>`, and surfaces an **always-ask** approval request. A human approves the merge to the protected branch by running `pan-tools merge confirm <branch>` in their own terminal. The command refuses without an interactive terminal, so no agent can approve its own merge. On a runtime where nobody is at a terminal, the campaign stops at this gate; release then tags and records the rollback target. `--push` pushes the approved result.
137
137
 
138
138
  **Teardown after the merge lands (P-1815):** worktrees are scaffolding, not deliverables — the squash-merge is the permanent artifact. Once the approval lands, remove each integrated task's worktree **and** its branch in one call: `pan-tools worktree remove ../pan-army-<slug> --branch army/<slug>`. The `--branch` half is not optional: a squash-merged branch never looks merged to git, so nothing else will ever clean it. At campaign end — and on **any** abort path — sweep whatever remains: `pan-tools worktree cleanup` (`--force` also discards dirty worktrees and unintegrated branches; without it the sweep keeps anything that might hold the only copy of work, and says exactly why and how to delete it). A campaign that ends with `pan-tools worktree list` non-empty has skipped this step.
139
139