pan-wizard 3.36.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 (314) hide show
  1. package/CHANGELOG.md +3645 -0
  2. package/README.md +36 -48
  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 +1 -2
  8. package/agents/pan-document_code.md +1 -2
  9. package/agents/pan-hardener.md +2 -3
  10. package/agents/pan-integration-checker.md +1 -2
  11. package/agents/pan-knowledge.md +1 -2
  12. package/agents/pan-meta-reviewer.md +3 -3
  13. package/agents/pan-optimizer.md +4 -4
  14. package/agents/pan-phase-researcher.md +79 -488
  15. package/agents/pan-plan-checker.md +12 -2
  16. package/agents/pan-planner.md +10 -6
  17. package/agents/pan-previewer.md +1 -2
  18. package/agents/pan-project-researcher.md +70 -499
  19. package/agents/pan-release.md +1 -1
  20. package/agents/pan-reviewer.md +9 -3
  21. package/agents/pan-roadmapper.md +12 -7
  22. package/agents/pan-verifier.md +7 -2
  23. package/bin/install-lib.cjs +134 -14
  24. package/bin/install.js +59 -12
  25. package/commands/pan/army.md +1 -1
  26. package/commands/pan/autodev.md +76 -0
  27. package/commands/pan/exec-phase.md +3 -4
  28. package/commands/pan/focus-auto.md +14 -7
  29. package/commands/pan/focus-design.md +4 -5
  30. package/commands/pan/focus-docs.md +24 -0
  31. package/commands/pan/learn.md +13 -6
  32. package/commands/pan/milestone-audit.md +8 -1
  33. package/commands/pan/milestone-done.md +10 -5
  34. package/commands/pan/milestone-new.md +2 -2
  35. package/commands/pan/new-project.md +15 -12
  36. package/commands/pan/plan-phase.md +15 -9
  37. package/commands/pan/quick.md +1 -1
  38. package/commands/pan/review-deep.md +11 -5
  39. package/commands/pan/settings.md +6 -0
  40. package/commands/pan/verify-phase.md +6 -2
  41. package/docs/AGENTS.md +917 -0
  42. package/docs/ARCHITECTURE.md +1054 -0
  43. package/docs/CLI-REFERENCE.md +4582 -0
  44. package/docs/COMPARISON.md +116 -0
  45. package/docs/DEVELOPMENT.md +490 -0
  46. package/docs/ECOSYSTEM-REVIEW-2026-06.md +107 -0
  47. package/docs/ECOSYSTEM-REVIEW-2026-08.md +349 -0
  48. package/docs/EXAMPLES.md +584 -0
  49. package/docs/FAQ.md +254 -0
  50. package/docs/FIELD-HARVEST-2026-07.md +88 -0
  51. package/docs/FIELD-REPORT-army-2026-06.md +121 -0
  52. package/docs/HOOKS.md +638 -0
  53. package/docs/IMPROVEMENT-TODO.md +246 -0
  54. package/docs/INTERNALS.md +485 -0
  55. package/docs/MIGRATION-v2-to-v3.md +258 -0
  56. package/docs/SECURITY-HARDENING.md +230 -0
  57. package/docs/SKILLS-ENHANCEMENT-PLAN-V2.md +122 -0
  58. package/docs/SKILLS-FULL-TEXT.md +9685 -0
  59. package/docs/SKILLS-REFERENCE.md +1037 -0
  60. package/docs/TROUBLESHOOTING.md +1084 -0
  61. package/docs/USER-GUIDE.md +1437 -0
  62. package/docs/archive/SKILLS-ENHANCEMENT-PLAN.md +230 -0
  63. package/docs/audits/AUDIT-2026-08-e2e-ROADMAP.md +117 -0
  64. package/docs/audits/AUDIT-2026-08-e2e-VERIFICATION.md +693 -0
  65. package/docs/audits/AUDIT-2026-08-e2e.md +1546 -0
  66. package/docs/audits/OUTSTANDING-2026-08.md +275 -0
  67. package/docs/audits/STABILITY-TEST-2026-08.md +640 -0
  68. package/docs/branding/README-brand-draft.md +119 -0
  69. package/docs/branding/handoff/IMPLEMENTATION.md +205 -0
  70. package/docs/branding/handoff/README-brand-draft.md +119 -0
  71. package/docs/branding/handoff/image-prompts.md +46 -0
  72. package/docs/branding/image-prompts.md +46 -0
  73. package/docs/branding/nano-banana-prompts.txt +60 -0
  74. package/docs/context-monitor.md +13 -0
  75. package/docs/decisions/ADR-0001-strategic-feature-prioritization.md +83 -0
  76. package/docs/decisions/ADR-0002-copilot-cli-runtime.md +71 -0
  77. package/docs/decisions/ADR-0003-smart-execution.md +84 -0
  78. package/docs/decisions/ADR-0004-copilot-cli-interaction.md +89 -0
  79. package/docs/decisions/ADR-0005-command-naming.md +80 -0
  80. package/docs/decisions/ADR-0006-focus-commands.md +101 -0
  81. package/docs/decisions/ADR-0007-ship-v1.md +73 -0
  82. package/docs/decisions/ADR-0008-map-codebase-mermaid-togaf.md +80 -0
  83. package/docs/decisions/ADR-0009-production-deployment-checklist.md +68 -0
  84. package/docs/decisions/ADR-0010-standards-integration.md +79 -0
  85. package/docs/decisions/ADR-0011-help-commands-rewrite.md +64 -0
  86. package/docs/decisions/ADR-0012-contributors-attribution-index.md +42 -0
  87. package/docs/decisions/ADR-0013-strategic-feature-additions.md +53 -0
  88. package/docs/decisions/ADR-0014-internal-cleanup-code-quality.md +53 -0
  89. package/docs/decisions/ADR-0015-focus-auto-runner.md +296 -0
  90. package/docs/decisions/ADR-0016-enhanced-doc-sync.md +54 -0
  91. package/docs/decisions/ADR-0017-enhanced-focus-design.md +69 -0
  92. package/docs/decisions/ADR-0018-user-reality-testing.md +84 -0
  93. package/docs/decisions/ADR-0019-end-to-end-user-acceptance-testing.md +113 -0
  94. package/docs/decisions/ADR-0020-ai-drift-prevention.md +55 -0
  95. package/docs/decisions/ADR-0021-codebase-mapper-v2.md +76 -0
  96. package/docs/decisions/ADR-0022-lifecycle-completeness.md +63 -0
  97. package/docs/decisions/ADR-0023-opus-4-7-adoption.md +89 -0
  98. package/docs/decisions/ADR-0024-spec-b-v2-completion.md +137 -0
  99. package/docs/decisions/ADR-0025-behavioral-guardrails-layer.md +129 -0
  100. package/docs/decisions/ADR-0026-self-improvement-loop.md +171 -0
  101. package/docs/decisions/ADR-0027-doc-code-link-graph.md +164 -0
  102. package/docs/decisions/ADR-0028-unified-agents-skills-target.md +46 -0
  103. package/docs/decisions/ADR-0029-experiment-evaluator.md +76 -0
  104. package/docs/decisions/ADR-0030-planning-concurrency.md +37 -0
  105. package/docs/decisions/ADR-0031-focus-auto-backlog-source.md +47 -0
  106. package/docs/decisions/ADR-0032-squad-model.md +64 -0
  107. package/docs/decisions/ADR-0033-army-campaign.md +40 -0
  108. package/docs/decisions/ADR-0034-scheduled-campaigns.md +57 -0
  109. package/docs/decisions/ADR-0035-army-hud-dashboard.md +40 -0
  110. package/docs/decisions/ADR-0036-agentic-memory-architecture.md +106 -0
  111. package/docs/decisions/ADR-0037-pin-security-agents-to-opus.md +51 -0
  112. package/docs/decisions/ADR-0038-skill-aligned-decomposition.md +41 -0
  113. package/docs/decisions/ADR-0039-worktree-as-project-variant.md +37 -0
  114. package/docs/decisions/ADR-0040-memory-injection-defense.md +55 -0
  115. package/docs/decisions/ADR-0041-mcp-dual-era-bridge.md +47 -0
  116. package/docs/decisions/ADR-0042-design-parity-both-flows.md +45 -0
  117. package/docs/decisions/ADR-0043-addressable-planning-roots.md +56 -0
  118. package/docs/decisions/ADR-0044-bound-the-cached-context.md +104 -0
  119. package/docs/decisions/ADR-0045-agent-plugins-bundle.md +76 -0
  120. package/docs/decisions/ADR-0046-subagent-frontmatter-decisions.md +39 -0
  121. package/docs/decisions/ADR-0047-pan-harness.md +76 -0
  122. package/docs/decisions/ADR-0048-one-core-per-project.md +43 -0
  123. package/docs/decisions/ADR-0049-machine-verdicts-and-findings-ledger.md +116 -0
  124. package/docs/specs/ai_drift_prevention_featureai.md +286 -0
  125. package/docs/specs/codebase_mapper_v2_featureai.md +930 -0
  126. package/docs/specs/command_naming_optimization_featureai.md +930 -0
  127. package/docs/specs/comp_analysis_markdown_v1.md +149 -0
  128. package/docs/specs/continuous_autonomous_execution_featureai.md +304 -0
  129. package/docs/specs/contributors_attribution_index_featureai.md +476 -0
  130. package/docs/specs/copilot_cli_interaction_featureai.md +868 -0
  131. package/docs/specs/copilot_cli_runtime_featureai.md +647 -0
  132. package/docs/specs/custom-skills-assessment.md +461 -0
  133. package/docs/specs/deployment_audit_findings_featureai.md +243 -0
  134. package/docs/specs/doc_code_link_graph_featureai.md +253 -0
  135. package/docs/specs/documentation_alignment_cleanup_featureai.md +69 -0
  136. package/docs/specs/e2e_visual_testing_featureai.md +615 -0
  137. package/docs/specs/end_to_end_user_acceptance_testing_featureai.md +810 -0
  138. package/docs/specs/evidence-loop-plan.md +76 -0
  139. package/docs/specs/evidence_loop_featureai.md +497 -0
  140. package/docs/specs/focus-auto-optimize-category.md +449 -0
  141. package/docs/specs/focus-auto-optimize-superplan.md +188 -0
  142. package/docs/specs/focus_auto_runner_featureai.md +1102 -0
  143. package/docs/specs/focus_design_v2_featureai.md +197 -0
  144. package/docs/specs/focus_sync_v2_featureai.md +202 -0
  145. package/docs/specs/git_integration_overhaul_featureai.md +326 -0
  146. package/docs/specs/glm_zai_provider_featureai.md +200 -0
  147. package/docs/specs/googlecli_adoption_featureai.md +661 -0
  148. package/docs/specs/help_commands_rewrite_featureai.md +860 -0
  149. package/docs/specs/industry_analysis_strategic_additions_featureai.md +231 -0
  150. package/docs/specs/industry_comparison_and_feature_gaps_featureai.md +674 -0
  151. package/docs/specs/internal_cleanup_code_quality_featureai.md +486 -0
  152. package/docs/specs/investigations/README.md +31 -0
  153. package/docs/specs/investigations/digests/2026-09-28.md +47 -0
  154. package/docs/specs/investigations/digests/2026-10-08.md +62 -0
  155. package/docs/specs/investigations/digests/2026-10-10.md +61 -0
  156. package/docs/specs/investigations/features/debugger-red-loop-first.md +55 -0
  157. package/docs/specs/investigations/features/harness-cross-host-behaviour.md +93 -0
  158. package/docs/specs/investigations/features/optimize-apply-regression-gate.md +66 -0
  159. package/docs/specs/investigations/features/reviewer-smell-baseline.md +57 -0
  160. package/docs/specs/investigations/features/trace-failure-capture.md +69 -0
  161. package/docs/specs/lifecycle_completeness_featureai.md +754 -0
  162. package/docs/specs/local-first-ci.md +42 -0
  163. package/docs/specs/map_codebase_mermaid_togaf_featureai.md +805 -0
  164. package/docs/specs/market-delta-2026-09-superplan.md +310 -0
  165. package/docs/specs/market-ideas-2026-09.md +131 -0
  166. package/docs/specs/market-ideas-2026-10.md +428 -0
  167. package/docs/specs/market-ideas-ledger.md +177 -0
  168. package/docs/specs/memory-optimization-2026-10.md +285 -0
  169. package/docs/specs/multi-track-planning-roots.md +143 -0
  170. package/docs/specs/multi_model_routing_featureai.md +687 -0
  171. package/docs/specs/multi_model_routing_superplan.md +197 -0
  172. package/docs/specs/opus_47_existing_enhancements_featureai.md +247 -0
  173. package/docs/specs/opus_47_extended_features_featureai.md +363 -0
  174. package/docs/specs/opus_47_extended_features_v2_featureai.md +397 -0
  175. package/docs/specs/pan_focus_commands_featureai.md +2336 -0
  176. package/docs/specs/pan_zcode_mcp_bridge_featureai.md +120 -0
  177. package/docs/specs/product-excellence-superplan.md +315 -0
  178. package/docs/specs/product_excellence_program_2026_q4_featureai.md +365 -0
  179. package/docs/specs/production_deployment_readiness_featureai.md +433 -0
  180. package/docs/specs/production_readiness_ship_v1_featureai.md +698 -0
  181. package/docs/specs/real_test_enforcement_featureai.md +213 -0
  182. package/docs/specs/reality-check-2026-09-superplan.md +362 -0
  183. package/docs/specs/right-sized-ceremony.md +74 -0
  184. package/docs/specs/roadmap_and_competition_2026_q4_featureai.md +390 -0
  185. package/docs/specs/self_improvement_loop_featureai.md +875 -0
  186. package/docs/specs/skill-aligned-decomposition.md +155 -0
  187. package/docs/specs/standards_integration_featureai.md +833 -0
  188. package/docs/specs/testing-system-redesign-2026-09.md +267 -0
  189. package/docs/specs/user_reality_testing_system_featureai.md +788 -0
  190. package/docs/specs/watch-triggers.json +22 -0
  191. package/docs/specs/workflow-integration-redesign.md +742 -0
  192. package/docs/specs/workflow_state_consistency_featureai.md +183 -0
  193. package/hooks/dist/pan-context-monitor.js +9 -2
  194. package/hooks/dist/pan-cost-logger.js +5 -0
  195. package/hooks/dist/pan-guard.js +28 -5
  196. package/hooks/dist/pan-stop-guard.js +9 -9
  197. package/hooks/dist/pan-trace-logger.js +5 -0
  198. package/package.json +10 -2
  199. package/pan-wizard-core/bin/lib/agents-md.cjs +57 -8
  200. package/pan-wizard-core/bin/lib/autodev-report.cjs +180 -0
  201. package/pan-wizard-core/bin/lib/autodev.cjs +642 -0
  202. package/pan-wizard-core/bin/lib/ci.cjs +143 -0
  203. package/pan-wizard-core/bin/lib/commands.cjs +1 -1
  204. package/pan-wizard-core/bin/lib/config.cjs +31 -2
  205. package/pan-wizard-core/bin/lib/constants.cjs +27 -1
  206. package/pan-wizard-core/bin/lib/core.cjs +22 -10
  207. package/pan-wizard-core/bin/lib/cost.cjs +14 -4
  208. package/pan-wizard-core/bin/lib/cross-family.cjs +164 -0
  209. package/pan-wizard-core/bin/lib/debug-cases.cjs +104 -0
  210. package/pan-wizard-core/bin/lib/failure-class.cjs +81 -0
  211. package/pan-wizard-core/bin/lib/findings.cjs +34 -4
  212. package/pan-wizard-core/bin/lib/focus.cjs +1 -1
  213. package/pan-wizard-core/bin/lib/hosts.cjs +88 -0
  214. package/pan-wizard-core/bin/lib/init.cjs +7 -2
  215. package/pan-wizard-core/bin/lib/knowledge.cjs +2 -0
  216. package/pan-wizard-core/bin/lib/merge.cjs +50 -0
  217. package/pan-wizard-core/bin/lib/mutate.cjs +16 -5
  218. package/pan-wizard-core/bin/lib/next-action.cjs +112 -0
  219. package/pan-wizard-core/bin/lib/optimize.cjs +2 -2
  220. package/pan-wizard-core/bin/lib/phase.cjs +48 -4
  221. package/pan-wizard-core/bin/lib/plan-lint.cjs +150 -1
  222. package/pan-wizard-core/bin/lib/preview.cjs +23 -4
  223. package/pan-wizard-core/bin/lib/requirements-lint.cjs +130 -0
  224. package/pan-wizard-core/bin/lib/research-lint.cjs +150 -3
  225. package/pan-wizard-core/bin/lib/review-deep.cjs +14 -22
  226. package/pan-wizard-core/bin/lib/review-vote.cjs +105 -0
  227. package/pan-wizard-core/bin/lib/runner.cjs +2 -16
  228. package/pan-wizard-core/bin/lib/sizing.cjs +356 -0
  229. package/pan-wizard-core/bin/lib/squads.cjs +1 -1
  230. package/pan-wizard-core/bin/lib/state-write.cjs +247 -0
  231. package/pan-wizard-core/bin/lib/uat.cjs +149 -0
  232. package/pan-wizard-core/bin/lib/verdict.cjs +26 -3
  233. package/pan-wizard-core/bin/lib/verify-plan-set.cjs +30 -1
  234. package/pan-wizard-core/bin/lib/verify-preflight.cjs +2 -2
  235. package/pan-wizard-core/bin/lib/verify-red.cjs +37 -1
  236. package/pan-wizard-core/bin/lib/verify-retro.cjs +3 -2
  237. package/pan-wizard-core/bin/lib/verify.cjs +59 -4
  238. package/pan-wizard-core/bin/lib/worktree.cjs +70 -0
  239. package/pan-wizard-core/bin/pan-tools.cjs +168 -27
  240. package/pan-wizard-core/learnings/universal/autonomous-loop.md +2 -2
  241. package/pan-wizard-core/references/continuation-format.md +3 -3
  242. package/pan-wizard-core/references/guardrails.md +1 -1
  243. package/pan-wizard-core/references/model-profiles.md +2 -3
  244. package/pan-wizard-core/references/questioning.md +24 -0
  245. package/pan-wizard-core/references/ui-brand.md +4 -6
  246. package/pan-wizard-core/references/verdict-contract.md +2 -1
  247. package/pan-wizard-core/templates/config.json +5 -1
  248. package/pan-wizard-core/templates/debug.md +1 -0
  249. package/pan-wizard-core/templates/discovery.md +2 -2
  250. package/pan-wizard-core/templates/requirements.md +9 -0
  251. package/pan-wizard-core/workflows/add-phase.md +4 -6
  252. package/pan-wizard-core/workflows/assumptions.md +19 -1
  253. package/pan-wizard-core/workflows/diagnose-issues.md +2 -0
  254. package/pan-wizard-core/workflows/discuss-phase.md +4 -2
  255. package/pan-wizard-core/workflows/exec-lean.md +69 -0
  256. package/pan-wizard-core/workflows/exec-phase.md +36 -8
  257. package/{commands/pan → pan-wizard-core/workflows}/focus-doc-audit.md +13 -29
  258. package/{commands/pan → pan-wizard-core/workflows}/focus-drift-walking.md +3 -18
  259. package/{commands/pan → pan-wizard-core/workflows}/focus-exec.md +8 -23
  260. package/{commands/pan → pan-wizard-core/workflows}/focus-plan.md +6 -20
  261. package/{commands/pan → pan-wizard-core/workflows}/focus-scan.md +3 -16
  262. package/{commands/pan → pan-wizard-core/workflows}/focus-sync.md +7 -21
  263. package/pan-wizard-core/workflows/health.md +6 -0
  264. package/pan-wizard-core/workflows/help.md +31 -53
  265. package/pan-wizard-core/workflows/insert-phase.md +4 -6
  266. package/pan-wizard-core/workflows/learn.md +3 -3
  267. package/pan-wizard-core/workflows/milestone-audit.md +2 -2
  268. package/pan-wizard-core/workflows/milestone-new.md +38 -95
  269. package/pan-wizard-core/workflows/new-project.md +96 -258
  270. package/pan-wizard-core/workflows/optimize.md +107 -5
  271. package/pan-wizard-core/workflows/phase-tests.md +10 -0
  272. package/pan-wizard-core/workflows/plan-phase.md +86 -43
  273. package/pan-wizard-core/workflows/profile.md +50 -0
  274. package/pan-wizard-core/workflows/progress.md +10 -0
  275. package/pan-wizard-core/workflows/quick.md +34 -43
  276. package/pan-wizard-core/workflows/research-phase.md +118 -40
  277. package/pan-wizard-core/workflows/resume-project.md +18 -2
  278. package/pan-wizard-core/workflows/settings.md +21 -24
  279. package/pan-wizard-core/workflows/todo-check.md +6 -2
  280. package/pan-wizard-core/workflows/transition.md +22 -4
  281. package/pan-wizard-core/workflows/uat-walkthrough.md +90 -0
  282. package/pan-wizard-core/workflows/update.md +1 -1
  283. package/pan-wizard-core/workflows/verify-phase.md +2 -2
  284. package/scripts/build-agent-plugin.js +35 -15
  285. package/scripts/build-plugin.js +10 -1
  286. package/scripts/deprecate-old-versions.js +70 -3
  287. package/scripts/generate-skills-docs.py +1 -1
  288. package/scripts/git-hooks/pre-push +27 -0
  289. package/scripts/install-git-hooks.js +7 -5
  290. package/scripts/install-pre-push.cjs +38 -0
  291. package/scripts/land.cjs +151 -0
  292. package/scripts/local-ci.cjs +501 -0
  293. package/scripts/local-schedule.cjs +277 -0
  294. package/scripts/prompt-lint.cjs +32 -0
  295. package/scripts/prompt-rules.cjs +156 -0
  296. package/scripts/run-tests.cjs +7 -1
  297. package/scripts/test-quality-lint.cjs +3 -3
  298. package/scripts/test-surface.cjs +9 -2
  299. package/agents/pan-research-synthesizer.md +0 -246
  300. package/commands/pan/audit-deployment.md +0 -386
  301. package/commands/pan/dashboard.md +0 -22
  302. package/commands/pan/discord.md +0 -19
  303. package/commands/pan/mcp-bridge.md +0 -143
  304. package/commands/pan/milestone-cleanup.md +0 -19
  305. package/commands/pan/milestone-gaps.md +0 -35
  306. package/commands/pan/optimize.md +0 -115
  307. package/commands/pan/profile.md +0 -76
  308. package/commands/pan/research-phase.md +0 -189
  309. package/pan-wizard-core/bin/lib/bridge.cjs +0 -269
  310. package/pan-wizard-core/templates/research-project/architecture.md +0 -210
  311. package/pan-wizard-core/templates/research-project/features.md +0 -153
  312. package/pan-wizard-core/templates/research-project/pitfalls.md +0 -206
  313. package/pan-wizard-core/templates/research-project/stack.md +0 -126
  314. package/pan-wizard-core/templates/research-project/summary.md +0 -170
@@ -0,0 +1,490 @@
1
+ # PAN Wizard Development Guide
2
+
3
+ ## Prerequisites
4
+ - Node.js >= 16.7.0 to run PAN (`engines` in `package.json`; `websearch` with a Brave key needs Node 18+ for the global `fetch` it calls); CI runs the test suite on Node 18, 20 and 22, and the coverage gate needs Node 22
5
+ - No other dependencies (zero runtime deps)
6
+
7
+ ## Project Structure
8
+
9
+ ```text
10
+ pan-wizard/
11
+ bin/
12
+ install.js # Interactive installer (npx pan-wizard entry point)
13
+ install-lib.cjs # Installer functions — no filesystem writes (verifyInstall()/verifyHookEntrypoints()/dirDigest() read the filesystem; the merge and strip helpers stripPanHookEntries()/mergeCodexHooksConfig()/removeCodexPanHooks()/mergeMcpRegistration()/stripMcpRegistration()/addOpencodePermissions()/stripOpencodePermissions() edit the object they are given): converters, parsers, MCP_REGISTRATION, HOOK_EVENT_MAP
14
+ package.json # Zero runtime deps; devDependencies are the VS Code e2e harness only
15
+ commands/pan/ # Command .md files (Claude Code format; converted per runtime at install)
16
+ agents/ # Agent .md files (specialized AI roles)
17
+ pan-wizard-core/
18
+ bin/
19
+ pan-tools.cjs # CLI dispatcher — all commands/agents call this
20
+ lib/ # Core CJS modules (responsibilities and the dependency graph: ARCHITECTURE.md)
21
+ constants.cjs # Shared path constants, file patterns, regex, FOREIGN_PLANNING_MARKERS
22
+ core.cjs # Model profiles, output()/error() exit-code contract, toPosix(), loadConfig(), toLf()/dominantEol()/withEol()
23
+ utils.cjs # readJsonFile, planningPath()/planningRel() (built on planning-root), listPhaseDirs
24
+ planning-root.cjs # Which .planning tree a command acts on: --track / --planning-dir + provenance (ADR-0043)
25
+ lock.cjs # Advisory file locking + atomic writes for .planning/ concurrency (ADR-0030)
26
+ config.cjs # Config CRUD (dot-notation get/set), standards catalog
27
+ state.cjs # state.md operations + frontmatter sync
28
+ state-compact.cjs # state compact — archive settled history to state-history.md (ADR-0044)
29
+ init.cjs # Compound init commands (bootstrap context per workflow)
30
+ phase.cjs # Phase CRUD facade; phase-remove.cjs — removal + renumbering cascade
31
+ roadmap.cjs # roadmap.md parsing (get-phase, analyze, update-plan-progress) and `roadmap slice` — one phase's slice of roadmap.md + requirements.md
32
+ roadmap-compact.cjs # roadmap compact — move shipped phases' sections to roadmap-history.md, leaving a stub (ADR-0044)
33
+ verify.cjs # Verification + health facade; verify-{drift,retro,deploy,preflight,scope}.cjs re-exported
34
+ verify-plan-set.cjs # `verify plan-set`: requirement coverage, same-wave file overlap and dependency checks in code; plan-check hashes and drift
35
+ verify-integrity.cjs # `verify test-integrity`: a phase's plan commits checked for deleted, skipped or weakened tests
36
+ phase-gate.cjs # `phase gate`: may a phase be marked complete; `phase complete`, exec-waves and the MCP merge request call it (`workflow.phase_gate`)
37
+ foreign-planning.cjs # Is this .planning/ another tool's? (gsd-core markers; planning-with-files markers make it shared, not foreign) — hygiene, health and init consult it
38
+ milestone.cjs # Milestone lifecycle (archive, milestones.md)
39
+ frontmatter.cjs # YAML-like frontmatter CRUD
40
+ commands.cjs # Misc facade: history-digest, scaffold, progress, todo, commit; commands-learnings.cjs re-exported
41
+ template.cjs # template select (picks a summary template) + template fill (built-in generators); reads nothing in templates/
42
+ context-budget.cjs # Context window utilization, cache block classification, cache.ttl recommendation
43
+ focus.cjs # Strategic project management: scan, plan, sync, exec, design, auto
44
+ codebase.cjs # Codebase analysis: language detection, imports, best practices
45
+ memory.cjs # Agent memory store: cited, expiring entries, not loaded into agents (ADR-0036); memory-optimize.cjs and memory-rebuild.cjs (ADR-0040)
46
+ agents-md.cjs # AGENTS.md PAN section + CLAUDE.md block: the @AGENTS.md import and a Compact instructions section (shared by the installer and memory rebuild)
47
+ cost.cjs # Token ledger, dated rate table, managed modelPricing (Y-6); models check; the p10/p50/p90 cost forecast `preview phase` reports
48
+ cost-rebuild.cjs # `cost rebuild`: the ledger regenerated from Claude Code transcripts
49
+ bus.cjs # Agent message channels (Y-7)
50
+ preview.cjs # Foresight: phase blast radius, dependency graph (Y-1)
51
+ review-deep.cjs # Deep review merge (reviewer + hardener + meta) (Y-2)
52
+ verdict.cjs # The pan-verdict contract: parses and validates a judge's block, or the verifier's verification.md frontmatter (ADR-0049)
53
+ findings.cjs # Findings ledger .planning/findings.jsonl: findings record/list/dispose/debt, and the suppressions a dismissal teaches until its file changes (ADR-0049)
54
+ test-gate.cjs # The test gate: `test run` / `test detect` — runs the project's own tests and parses the runner's output
55
+ verify-red.cjs # `verify red`: each phase test must fail at the phase's base and pass at HEAD; mutate.cjs — the `verify mutate` report
56
+ plan-lint.cjs # `verify review-focus` and `verify decisions`: a plan's Review Focus and its design-decision citations, checked in code
57
+ research-lint.cjs # `research lint`: research claims carry a source and a checked date, and go stale by type
58
+ usage.cjs # `usage`: local census of installed commands and agents (used, never used, unfinished) from the cost ledger and traces
59
+ knowledge.cjs # Grounded Q&A / discuss / playbook (Y-3)
60
+ whatif.cjs # Counterfactual phase replay in worktree (Y-4)
61
+ optimize.cjs # Circular optimization loop (trace, learn, apply, revert)
62
+ git.cjs # /pan:git command family
63
+ distill.cjs # AI code-bloat 5-pass optimizer
64
+ doc-lint.cjs # Markdown frontmatter+structure linter; `doc-lint counts` is release Gate 4
65
+ links.cjs # Doc–code link graph: `links validate` (ADR-0027); release Gate 5
66
+ suggest.cjs # "Did you mean" for unknown commands — error path only
67
+ experiment.cjs # Self-improvement loop scaffolding; runner.cjs — external agent runner
68
+ learn-lint.cjs # Learnings-store integrity linter (L-001..L-007)
69
+ learn-index.cjs # Learnings index + topics-for queries (per-agent relevance, or matched to the task with --cue)
70
+ squads.cjs # Squad registry — army roles architecture/build/quality/release (ADR-0032)
71
+ worktree.cjs # Branch-per-agent git worktree isolation for parallel builders (ADR-0033)
72
+ campaign.cjs # Scheduled self-resuming army campaigns ("dreaming") (ADR-0034)
73
+ hud.cjs # Single self-contained HTML dashboard of project + bot army (ADR-0035)
74
+ phase-report.cjs # Per-phase HTML report + timeline index
75
+ skill-align.cjs # Skill-Aligned Decomposition pass for the planner (ADR-0038)
76
+ hygiene.cjs # Project cleanup + version alignment (scan/clean)
77
+ sizing.cjs # Right-sized ceremony: lean or full per phase / quick task, the engine-written lean plans and their check (`size`)
78
+ autodev.cjs # The autonomous outer loop (`autodev run/resume/status`); a lean phase runs in one session through workflows/exec-lean.md
79
+ mcp/ # MCP bridge — the SERVER side: zero-dep JSON-RPC stdio server over pan-tools (ADR-0041)
80
+ workflows/ # Workflow .md files (multi-step procedures); the native Claude Code workflow scripts are generated by buildNativeWorkflowScripts() in bin/install-lib.cjs at install and plugin-build time, not stored here
81
+ references/ # Reference .md files (loaded by agents)
82
+ templates/ # Template files (scaffolding)
83
+ learnings/ # Learnings store (universal/ ships; internal/ is stripped by the installer)
84
+ opencode/ # pan-wizard.js — OpenCode plugin, installed as <opencode dir>/plugins/pan-wizard.js; keeps PAN's position through a compaction
85
+ hooks/
86
+ pan-*.js # Hook sources (pure Node.js)
87
+ dist/ # Build output — copied, not bundled; gitignored
88
+ pan-statusline.js # Writes context metrics bridge file
89
+ pan-context-monitor.js # PostToolUse hook — injects a context note before the host compacts (bridge file, else the session transcript)
90
+ pan-check-update.js # Periodic update check (spawns `npm view pan-wizard version`)
91
+ pan-cost-logger.js # SubagentStop hook — appends cost record to tokens.jsonl
92
+ pan-trace-logger.js # SubagentStop hook — circular optimization tracing
93
+ pan-guard.js # PreToolUse hook (BeforeTool on Gemini CLI, preToolUse on Copilot CLI) — reports credential writes, direct state writes, judge writes outside the planning tree and undeclared test edits; under hooks.guard: enforce denies the first three (A7, A7b)
94
+ pan-stop-guard.js # Stop hook (AfterAgent on Gemini CLI, agentStop on Copilot CLI) — blocks the auto-advance boundary drop once
95
+ pan-state-reinject.js # SessionStart hook, matcher compact (Claude Code, Codex); PreCompress then AfterTool on Gemini CLI, preCompact then postToolUse on Copilot CLI — re-injects the planning position after a compaction
96
+ scripts/
97
+ build-hooks.js # Copy hooks/ → hooks/dist/ (no bundling)
98
+ build-plugin.js # Claude Code plugin → dist/pan-wizard-plugin/
99
+ build-agent-plugin.js # Agent Plugins 1.0 bundle → dist/pan-agent-plugin/ (ADR-0045)
100
+ plugin-path.js # Rebuilds the plugin and prints its path as one stdout line (command-source marketplace contract)
101
+ release-check.js # The release gates — `npm run release:check`, also `prepublishOnly`
102
+ deprecate-old-versions.js # Post-publish housekeeping; dry-run by default, `--apply` to act; never unpublishes
103
+ npm-dist-tag.js # Prints the npm dist-tag a version publishes under (next for a prerelease, latest otherwise)
104
+ run-tests.cjs # Glob-free test runner (the CI matrix shells do not expand test globs)
105
+ install-git-hooks.js # `prepare` script — points core.hooksPath at scripts/git-hooks/ (the gitleaks pre-commit scan)
106
+ local-ci.cjs # The CI gates on this machine (`npm run ci:local`); see Local CI
107
+ install-pre-push.cjs # Opt-in switch for the pre-push hook (`npm run hooks:pre-push`, `-- --off`)
108
+ land.cjs # Squash-land a branch on main after a passing ci:local (`npm run land -- <branch>`)
109
+ local-schedule.cjs # Weekly Task Scheduler checks: code scan, npm outdated, market watch (`npm run ci:schedule`)
110
+ generate-skills-docs.py # Regenerates docs/SKILLS-REFERENCE.md and docs/SKILLS-FULL-TEXT.md
111
+ test-surface.cjs # Shipped-surface registry → tests/fixtures/surface.json (--write/--check/--map/--scaffold); also the liveness registry (--liveness)
112
+ coverage-gate.cjs # Suite under Node coverage: dispatcher arms + floors (release Gate 9)
113
+ test-quality-lint.cjs # Vacuous-assertion lint rules applied by tests/test-quality.test.cjs
114
+ prompt-lint.cjs # Prompt-contract lint over shipped prompts, applied by tests/prompt-lint.test.cjs
115
+ prompt-rules.cjs # Prompt-rule registry: every normative line in a shipped prompt gets an id in tests/fixtures/prompt-rules.json (--write, --check); harness scenarios claim the rules they cover
116
+ build-help.cjs # Writes /pan:help's command index from command frontmatter (--write, --check); tests/help-generated.test.cjs fails when stale
117
+ mutation-probe.cjs # Report-only mutation probe (npm run test:mutate)
118
+ git-hooks/ # Tracked hooks: pre-commit (gitleaks), pre-push (local CI fast subset; inert until opted in)
119
+ harness/ # PAN Harness — behavioural scenarios against installs built from a packed artifact (ADR-0047); not shipped
120
+ marketplace/ # Local command-source Claude plugin marketplace for the dev loop; not shipped
121
+ .agents/plugins/marketplace.json # Codex marketplace → ./dist/pan-agent-plugin (build first)
122
+ .github/plugin/marketplace.json # Copilot marketplace → ./dist/pan-agent-plugin (its version is pinned to package.json by a test)
123
+ pan-zcode/ # Experimental: ZCode subsystem — a consumer of the shared MCP bridge, with its own installer
124
+ tests/ # Test suite (node:test + node:assert)
125
+ helpers.cjs # runPanTools(), createTempProject(), cleanup(), buildPluginInto(), buildAgentPluginInto()
126
+ *.test.cjs # Unit test files
127
+ scenarios/ # Scenario test files (installer + integration + workflow)
128
+ fixtures/ # Pinned fixtures (module export surfaces, Agent Plugins schemas, …)
129
+ docs/ # User and contributor docs; decisions/ (ADRs), specs/, audits/
130
+ assets/ # README images (hero, terminal SVG, avatar)
131
+ ```
132
+
133
+ ## Development Setup
134
+
135
+ ```bash
136
+ git clone https://github.com/oharms/PanWizard.git
137
+ cd PanWizard
138
+ npm install # Installs devDependencies only (zero runtime deps)
139
+ npm test # Run unit tests
140
+ npm run test:scenarios # Run scenario tests (install + integration)
141
+ npm run test:all # Run all tests (unit + scenario)
142
+ npm run build:hooks # Copy hooks from hooks/ to hooks/dist/ (no bundling — pure Node.js)
143
+ npm run release:check # The release gates — what `npm publish` runs via prepublishOnly (see Release Process)
144
+ npm run harness # Tier 0 of the behavioural harness: model-free, free (see Behavioural Harness)
145
+ npm run ci:local # Every CI gate on this machine, in parallel (see Local CI)
146
+ ```
147
+
148
+ ### Local Testing
149
+
150
+ Never install into the clone itself — `bin/install.js` has a hard `PAN_SOURCE_ROOT` guard that refuses to run from the source repo. Install into a separate scratch directory instead:
151
+
152
+ ```bash
153
+ # From a scratch dir alongside the clone, install to test changes
154
+ cd ../pan-test && node ../PanWizard/bin/install.js --claude --local # → ./.claude/
155
+ cd ../pan-test && node ../PanWizard/bin/install.js --claude --global # → ~/.claude/
156
+ ```
157
+
158
+ ## How to Add a New Command
159
+
160
+ 1. Create `commands/pan/your-command.md`
161
+ 2. The filename becomes the slash command: `/pan:your-command`
162
+ 3. Commands should be thin orchestrators — read state, spawn agents, route results
163
+ 4. Call pan-tools for state operations: `node ~/.claude/pan-wizard-core/bin/pan-tools.cjs <cmd> [args]`
164
+ 5. Reference a workflow if multi-step logic is needed
165
+ 6. No installer edit is needed — the installer copies `commands/pan/` recursively, so new command files ship automatically. Give the file frontmatter that `pan-tools doc-lint commands/pan` accepts, with a `group` and a `description` (the `/pan:help` index is generated from them), run `node scripts/build-help.cjs --write` and `node scripts/test-surface.cjs --write` (the surface registry lists every command file), name the command in a harness scenario or give it a reason in `tests/fixtures/liveness-allowlist.json`, and refresh the Commands row of the counts table in `CLAUDE.md`, or `npm test` fails (`tests/doc-lint.test.cjs`, `tests/help-generated.test.cjs`, `tests/surface-map.test.cjs`, `tests/claude-md-counts.test.cjs`)
166
+
167
+ ## How to Add a New Agent
168
+
169
+ 1. Create `agents/pan-your-agent.md`
170
+ 2. Define role, context requirements, constraints, output format using XML structure
171
+ 3. Add the agent to `MODEL_PROFILES` and `AGENT_BASE_EFFORT` in `core.cjs`, and set the agent's `effort:` frontmatter to that base effort (`tests/core.test.cjs` pins all three)
172
+ 4. Reference from workflow .md that spawns it via Task tool
173
+ 5. No installer edit is needed — the installer copies every top-level `agents/*.md` file (subdirectories are not scanned), so new agent files ship automatically. Run `node scripts/test-surface.cjs --write` (the surface registry lists every agent file), name the agent in a harness scenario or give it a reason in `tests/fixtures/liveness-allowlist.json`, and refresh the Agents row of the counts table in `CLAUDE.md`, and place the agent in a squad or the worker list in `pan-wizard-core/bin/lib/squads.cjs`, or `npm test` fails (`tests/surface-map.test.cjs`, `tests/claude-md-counts.test.cjs`, `tests/squads.test.cjs`)
174
+
175
+ ## How to Add a Core Module Function
176
+
177
+ 1. Add function to the appropriate `.cjs` file in `pan-wizard-core/bin/lib/`
178
+ 2. Export via `module.exports`, then regenerate `tests/fixtures/module-surface.json` with the one-liner in the header of `tests/module-surface.test.cjs`, which pins every module's exports
179
+ 3. Wire into `pan-tools.cjs` command routing (add case in the main switch) and name the new verb in the usage line's `Commands:` list, or the new subcommand in its group's `Unknown … subcommand. Available:` string — the surface registry and `tests/doc-command-surface.test.cjs` read them from there — then run `node scripts/test-surface.cjs --write` — `npm run test:surface` fails until the registry is refreshed, `tests/surface-map.test.cjs` until a test names the new verb (quoted, or after `pan-tools`) or the new subcommand (`<verb> <sub>`, quoted or not), and the coverage gate (`npm run test:coverage`) until a test dispatches the new arm
180
+ 4. Write tests in `tests/` using `node:test` and `node:assert`
181
+
182
+ ## How to Add a Hook
183
+
184
+ 1. Create source in `hooks/your-hook.js`
185
+ 2. Add the file to `HOOKS_TO_COPY` in `scripts/build-hooks.js`, then run `npm run build:hooks` (copy-only; no bundling — they're pure Node.js)
186
+ 3. Register it in `bin/install.js` (its `buildHookCommand` call, a row in the settings.json `registrations` table, its command in the `verifyHookEntrypoints` list and in the Codex and Copilot builder calls, and the uninstall `panHooks` list), in `bin/install-lib.cjs` (`PAN_SETTINGS_HOOKS`, a `HOOK_EVENT_MAP` slot carrying each runtime's own event name or `null` — `tests/hook-vocabulary.test.cjs` rejects names a runtime does not document — the Codex and Copilot builders `mergeCodexHooksConfig` / `buildCopilotHooksConfig`, which hard-code their event names, the plugin hooks builders, and the name regex in the Codex uninstall filter `removeCodexPanHooks`), in `hookCommands()` in `scripts/build-agent-plugin.js`, and in `EVENT_HOOKS` in `scripts/test-surface.cjs`. Then run `node scripts/test-surface.cjs --write`, name the hook together with each runtime it registers on in a test, give it a driver in `DRIVERS` in `tests/hooks-e2e.test.cjs`, and refresh the Hooks row of the counts table in `CLAUDE.md`, or `npm test` fails (`tests/surface-map.test.cjs`, `tests/hooks-e2e.test.cjs`, `tests/claude-md-counts.test.cjs`). A hook Copilot registers must also carry the shared `deferToClaudeRegistration()` copy (the `.github` copy steps aside when the project's Claude settings register the same script) and be added to the `HOOKS` list in `tests/copilot-hook-dedupe.test.cjs`, unless Claude's registration of the script can never fire under Copilot, as with `pan-state-reinject.js` (its header says why)
187
+
188
+ ## Writing Tests
189
+
190
+ Tests use Node.js built-in `node:test` and `node:assert`. No external framework — the one exception is the opt-in VS Code e2e harness in `tests/e2e/` (`npm run test:vscode`), which runs on Playwright.
191
+
192
+ ```javascript
193
+ const { describe, test } = require('node:test');
194
+ const assert = require('node:assert/strict');
195
+ const { runPanTools, createTempProject, cleanup } = require('./helpers.cjs');
196
+
197
+ describe('your feature', () => {
198
+ test('does the thing', () => {
199
+ const tmp = createTempProject(); // Temp dir with an empty .planning/phases/
200
+ try {
201
+ const result = runPanTools('your-command arg', tmp); // one argument string, not an array
202
+ const data = JSON.parse(result.output);
203
+ assert.strictEqual(data.field, 'expected');
204
+ } finally {
205
+ cleanup(tmp); // Always clean up
206
+ }
207
+ });
208
+ });
209
+ ```
210
+
211
+ ### Test Helpers (tests/helpers.cjs)
212
+
213
+ - `runPanTools(argsString, cwd)` — runs `pan-tools.cjs` with a pre-joined argument string; returns `{ success, output, error? }` where `output` is the raw stdout (`JSON.parse` it yourself)
214
+ - `createTempProject()` — creates a temp directory containing an empty `.planning/phases/` scaffold (no options)
215
+ - `cleanup(dir)` — Recursively removes temp directory
216
+ - `createScenarioRunner(runtime)` — installs PAN for `'claude'|'opencode'|'gemini'|'codex'|'copilot'` into a temp dir; returns `{ tmpDir, installedToolsPath, configDir, run(args, cwd?), cleanup() }`
217
+ - `buildPluginInto()` / `buildAgentPluginInto()` — build the two distribution bundles into a fresh private temp directory and return its path (never into `dist/`); the caller owns `cleanup(dir)`
218
+ - `TOOLS_PATH`, `INSTALLER_PATH` — absolute paths to `pan-tools.cjs` and `bin/install.js`; `RUNTIME_DIR` — the runtime → config-directory-name map (`claude` → `.claude`, …, `copilot` → `.github`) mirroring the installer's `getDirName`
219
+ - `withFakeHome(fn)` — runs `fn(fakeHome)` with `HOME`, `USERPROFILE` and `CLAUDE_CONFIG_DIR` pointed at a fresh temp directory, then restores them; tests never read the developer's real home
220
+ - `readLedger(cwd)` — the project's parsed cost-ledger rows (`[]` without a ledger)
221
+ - `spawnHook(hookFile, payload, cwd, extraEnv?)` — spawns a hook as its host would (JSON payload on stdin, the project as cwd; a file name in `hooks/` or an absolute installed path); returns `{ status, stdout, stderr }`
222
+ - `installInto(cwd, flags)` — runs the installer into `cwd` with the given flags and refuses the source repository
223
+
224
+ ### What the suite must cover, and what an assertion must be
225
+
226
+ The checks below decide this from the code rather than from the tests — the registry and the two lints run with the rest of the suite, the coverage gate as a run of its own (the plan is `docs/specs/testing-system-redesign-2026-09.md`):
227
+
228
+ - **The surface registry.** `node scripts/test-surface.cjs --write` derives every shipped surface — verbs from the dispatcher's usage line, subcommands from its `Unknown … subcommand. Available:` strings, dispatcher `case` arms, installer flag literals, hook × runtime registrations from `HOOK_EVENT_MAP`, MCP tools and resources, config default keys, the content directories — into `tests/fixtures/surface.json`, which is committed and reviewed like code. `tests/surface-map.test.cjs` fails when the registry drifts from the code (`npm run test:surface`) and when a row is named by no test: a verb quoted or after `pan-tools`, a subcommand as `<verb> <sub>` (a comment counts), a flag as a literal, a hook together with its runtime, an MCP tool by name, a config key as a key. A row without a test goes in `tests/fixtures/surface-allowlist.json` **with a reason**, and the entry fails once a test names it. `node scripts/test-surface.cjs --scaffold <dir>` writes one todo stub per unreferenced row; that is how a suite rebuilt from an empty directory starts.
229
+ - **The coverage gate.** `npm run test:coverage` runs the suite under Node's own instrumentation (Node 22+; the processes tests spawn are captured through the inherited `NODE_V8_COVERAGE`) and fails when a dispatcher `case` arm never executed, or when overall line or function coverage, or a module group's line coverage, falls below its floor in `tests/fixtures/coverage-policy.json` (set a point below the measured baseline). An arm no test dispatches yet is allowlisted there with a reason, and the entry fails once a test dispatches it. Release-check Gate 9 runs it, and so does the `coverage` gate of `npm run ci:local`.
230
+ - **The quality lint.** `tests/test-quality.test.cjs` applies `scripts/test-quality-lint.cjs` to every test file and fails on the shapes that have passed while the feature they named was broken: an OR between result-status fields (`output || error` — a crash satisfies it), an in-process call to a lib module's `cmd*` function (they end in `output()`/`error()`, which exit the process, so the test child dies and `node --test` reports the file as one passing test — always go through `runPanTools`), `assert(true)`, CLI output asserted only by its length, a platform conditional that bare-returns instead of `t.skip(reason)`, a wall-clock bound of two seconds or less, a read of the real home directory, a committed `test.todo`, and an `assert.ok(a.x || a.y)` that only asks whether one of several fields exists. Exceptions live in `tests/fixtures/test-quality-allowlist.json` per file and rule with a count and a reason; an entry that allows more than the file has is stale and fails too.
231
+ - **The prompt-contract lint.** `tests/prompt-lint.test.cjs` applies `scripts/prompt-lint.cjs` to `commands/pan`, `agents` and `pan-wizard-core/workflows` and fails when a `pan-tools` call names a verb or subcommand the engine does not have, an agent is told to use a tool it is not granted, a prompt @-includes engine source, an AskUserQuestion offers more than four options, a spawn names no model (or a role spawn no agent type), or a shipped prompt sends the user to a dev-only skill. Exceptions live in `tests/fixtures/prompt-lint-allowlist.json` with a reason; a stale entry fails.
232
+
233
+ The allowlists are the debt register: seeded from the suite as it stood on 2026-09-17 and burned down in the spec's phase 2 — the never-dispatched CLI arms and verbs and every "Unknown <group> subcommand" arm are now covered by `tests/dispatcher-arms.test.cjs`, which is driven from the dispatcher's own source rather than a hand-kept list.
234
+
235
+ One more check is **not** part of the gate and is run by hand: `npm run test:mutate` breaks the code on purpose — one small mutation at a time, inside a throwaway `git worktree` so your checkout is never touched — and reports the mutations the suite did not notice. Coverage says a line executed; a surviving mutant says no assertion constrained it. Some survivors are correct (equivalent mutants, defensive `|| 0` defaults, log strings), which is exactly why it reports and never fails: a survivor is a question about whether a behaviour is worth pinning.
236
+
237
+ ### Running Tests
238
+
239
+ ```bash
240
+ npm test # Unit tests (npm run test:all adds the scenarios)
241
+ node --test tests/phase.test.cjs # Single file
242
+ node scripts/run-tests.cjs tests # Cross-platform runner; a tests/*.test.cjs glob only expands on bash or Node 22+
243
+ npm run test:surface # The committed surface registry still matches the code
244
+ npm run test:coverage # The suite under coverage: dispatcher arms + per-group floors (Node 22+)
245
+ npm run harness # Tier 0 of the PAN Harness: behavioural, model-free, free
246
+ npm run test:mutate # Report-only: which deliberate breakages the suite fails to notice
247
+ ```
248
+
249
+ ## Local CI
250
+
251
+ `npm run ci:local` (`scripts/local-ci.cjs`) runs the gates GitHub CI used to run, on this machine and in parallel, so a change can be verified without a pull request. Each gate writes its log to `.ci-local/logs/<gate>.log`; the run writes `.ci-local/report.json` (gitignored) and prints a one-screen summary.
252
+
253
+ | Gate | What it runs | Needs |
254
+ |---|---|---|
255
+ | `build-hooks` | `scripts/build-hooks.js`, first, whenever a host suite, harness or coverage gate will run (they read the gitignored `hooks/dist/`); reported only when it fails | — |
256
+ | `host-node18`, `-20`, `-22` | The unit and scenario suite on the host, once per Node version | fnm with those versions; without fnm, the suite runs once on the current Node (`host-node<current>`) and the others are reported skipped |
257
+ | `linux-node18`, `-20`, `-22` | The suite in `node:<N>-bookworm` containers: the checkout is mounted read-only, copied in without `node_modules` and `.git`, given its own one-commit repo, then `npm ci`, `build:hooks` and `test:all` as the unprivileged `node` user (as root, the tests that force a failed write on a read-only file cannot fail the write) | Docker running |
258
+ | `harness` | The PAN Harness at tier 0 with `--no-ledger`, requiring the double-backed scenarios to run (`--require-run`), so a missing Claude Code CLI fails instead of skipping | the Claude Code CLI |
259
+ | `gitleaks` | `gitleaks detect` over the history with `.gitleaks.toml` | gitleaks |
260
+ | `audit` | `npm audit --omit=dev --audit-level=high` | network |
261
+ | `links` | `pan-tools links validate` | — |
262
+ | `surface` | `scripts/test-surface.cjs --check` (the suite checks it too; this gate names the failure) | — |
263
+ | `coverage` | `scripts/coverage-gate.cjs` | Node 22+ |
264
+ | `codescan` | Only with `--codescan`: the CodeQL CLI's `security-extended` suite over the whole tree when it is installed, failing on a result at error level or with a security severity of high or above (what GitHub's code-scanning check blocked on) unless its rule and file are accepted, with a reason, in `.codeql-accepted.json` (seeded from the alerts dismissed on GitHub; an acceptance that no longer matches is reported stale); else Semgrep in Docker (`p/javascript`, `p/nodejs`) on the JavaScript files changed against `main` (`--codescan-all` for the whole tree). `--codescan=codeql` or `=semgrep` picks one | the CodeQL CLI, or Docker |
265
+ | `clean-tree` | After every other gate: the working tree is as it was when the run started. Work you had not committed is fine; a gate that writes into the checkout is not | git |
266
+
267
+ Whole-suite runs are scheduled so they do not starve each other: the three containers run first, together, then the host suite runs (one per Node version, then the coverage gate, which runs the suite again under instrumentation) one at a time. A host suite run beside another one, or beside the containers, times its 30-second setup hooks out. The harness and the light gates run beside all of it. Each host suite run also caps how many test files run at once (`PAN_TEST_CONCURRENCY`, read by `scripts/run-tests.cjs`; half the cores, at most 16): Node's default of one file per core but one made the Node 22 suite's wall-clock checks miss their bounds on a 40-core machine even alone, which GitHub's 4-core runners never saw. Each gate gets its own temp directory, so a test that uses a fixed name under the OS temp directory never meets another gate's copy of itself; a failed gate's temp directory is kept. One run per checkout: `.ci-local/run.lock` refuses a second.
268
+
269
+ A tool that is not installed is reported **SKIP** with how to install it, never PASS, and the summary says skipped gates did not run. Any FAIL exits 1; `--strict` makes a skip fail too. Other flags: `--only host,gitleaks` (gates whose id starts with a listed name), `--no-docker`, `--jobs N` (light gates at once, default 6), `--root <dir>`, `--out <dir>` (report, logs and lock somewhere other than `.ci-local/`), `--json`.
270
+
271
+ A full run (no `--only`, no `--fast`) also records its verdict for the commit it ran on in the git directory (`pan-ci-local/<sha>.json`, shared by every worktree). That record is what `npm run land` checks.
272
+
273
+ What stays on GitHub: the macOS jobs in `.github/workflows/ci.yml` (no Mac here; they caught the 8 KB stdout truncation in PR #52) and the npm release (`release.yml`), which publishes with provenance through OIDC trusted publishing.
274
+
275
+ **Tools.** Install once (`winget` on Windows):
276
+
277
+ ```bash
278
+ winget install --id Gitleaks.Gitleaks -e
279
+ ```
280
+
281
+ ```bash
282
+ winget install --id Schniz.fnm -e
283
+ ```
284
+
285
+ then, in a new shell, `fnm install 18`, `fnm install 20` and `fnm install 22`. The pre-commit hook starts scanning as soon as gitleaks is on `PATH`. For CodeQL (free for this public repository), download `codeql-bundle-win64.tar.gz` from the latest `codeql-bundle-v*` release of `github/codeql-action`, check it against the `.checksum.txt` beside it, and unpack it to `%USERPROFILE%\.codeql-cli`, where `local-ci.cjs` finds `codeql\codeql.exe` without a `PATH` entry. Keep tool data out of `AppData` when installing from a packaged app's terminal (the Claude desktop app's included): its writes there go to a private, virtualised copy that your own shells and Task Scheduler never see. That is why the bundle goes under `%USERPROFILE%`, and why `FNM_DIR` is set to `%USERPROFILE%\.fnm` (`setx FNM_DIR %USERPROFILE%\.fnm`) before `fnm install`. The CodeQL download:
286
+
287
+ ```bash
288
+ gh release download -R github/codeql-action -p "codeql-bundle-win64.tar.gz*"
289
+ ```
290
+
291
+ ### Landing a change
292
+
293
+ With no pull request, a change goes branch → `ci:local` → `land`:
294
+
295
+ 1. Work on a branch. Keep it up to date with `origin/main` (merge or rebase).
296
+ 2. Commit everything, then run the full `npm run ci:local` on that commit. It has to start from a clean tree: uncommitted work means the gates did not test the commit alone, and `land` refuses that verdict.
297
+ 3. `npm run land -- <branch>` (`scripts/land.cjs`). It refuses unless the full run passed on the branch's current HEAD with no gate skipped (`--allow-skips` overrides that one) and the branch contains `origin/main`. Then it fetches, fast-forwards `main` to `origin/main` in the checkout that has `main` (or a temporary worktree), squash-merges the branch, checks that the result is exactly the tree `ci:local` passed, commits it with the branch's summary (the first commit's subject, or `--title`; the body lists every commit), and pushes `main` to `origin`. It never force-pushes; a rejected push leaves the commit on the local `main` and says so. `--dry-run` shows the commit without making it, `--no-push` stops before the push.
298
+
299
+ GitHub is the mirror and the publisher. Since `2026-10-22`, branch protection on `main` requires only the three macOS `test` jobs, and no pull request, so `land` can push; a required check GitHub no longer runs would reject every push. The first changes landed this way were the H10 pairs (`0bb48b7`, `45323c9`).
300
+
301
+ ### Scheduled checks
302
+
303
+ `npm run ci:schedule -- --install` (`scripts/local-schedule.cjs`) registers three weekly Windows Task Scheduler tasks for the current user (no admin), in place of GitHub's scheduled workflows and Dependabot:
304
+
305
+ | Task | When | Runs |
306
+ |---|---|---|
307
+ | `PanWizard-codescan` | Sunday 03:00 | `local-ci.cjs --only codescan --codescan-all`: CodeQL over the whole tree when installed, else Semgrep in Docker |
308
+ | `PanWizard-outdated` | Monday 09:00 | `npm outdated`, as a table of current, wanted and latest versions |
309
+ | `PanWizard-market-watch` | Monday 09:10 | `harness/autopilot/market-watch.cjs` |
310
+
311
+ A run missed while the machine was off starts when it is next on. The tasks run in the repository's main worktree (`--root` picks another checkout; `--node` another `node.exe`) and write to `.ci-local/scheduled/<task>/` there: a dated `.md` summary, its `.log`, and `last-run.json`, which the weekly State of PAN (`harness/autopilot/state-of-pan.cjs`) links. `--list` shows the tasks, their last result and the latest reports; `--uninstall` removes exactly the tasks `--install` added; `--run <codescan|outdated|market-watch>` runs one by hand. Off Windows, `--install` prints the equivalent crontab lines.
312
+
313
+ **Pre-push hook.** `scripts/git-hooks/pre-push` runs `local-ci.cjs --fast` (`npm run ci:local:fast`): the suite on the current Node, the harness at tier 0 and gitleaks. It is tracked, but does nothing until you opt in for your clone with `npm run hooks:pre-push` (sets `git config pan.prePush true`; `npm run hooks:pre-push -- --off` clears it). Bypass once with `SKIP_PREPUSH=1 git push` or `git push --no-verify`.
314
+
315
+ ## Cross-Platform Considerations
316
+
317
+ ### Path Separators (EP-001)
318
+ Windows uses `\`, macOS/Linux use `/`. All JSON output must use forward slashes.
319
+
320
+ **Fix:** Use `toPosix()` from `core.cjs` when outputting file paths.
321
+
322
+ ```javascript
323
+ const { toPosix } = require('./core.cjs');
324
+ // path.join('.planning', 'state.md') → '.planning\state.md' on Windows
325
+ // toPosix(relPath) → '.planning/state.md' always
326
+ ```
327
+
328
+ ### Dollar Sign Shell Expansion (EP-002)
329
+ Bash expands `$` in strings. If content contains `$100`, it gets mangled.
330
+
331
+ **Fix:** Write content to a temp file and pass it with the verb's file flag (`state add-blocker --text-file`, `state add-decision --summary-file`/`--rationale-file`, `findings record --file`) instead of inline strings.
332
+
333
+ ### CommonJS Format (EP-003)
334
+ All modules are CommonJS (`require()`/`module.exports`): the core modules use the `.cjs` extension, and hooks, `bin/install.js` and several scripts are CommonJS `.js`. Do NOT use ESM (`import`/`export`). The exceptions are the opt-in Playwright harness in `tests/e2e/` and the native workflow scripts that `buildNativeWorkflowScripts()` in `bin/install-lib.cjs` emits for `.claude/workflows/`, which must open with `export const meta`.
335
+
336
+ ### node:test Not Jest (EP-004)
337
+ Tests use `node:test` and `node:assert/strict`. Do NOT use `describe`/`it` from Jest or Mocha.
338
+
339
+ ### Line Endings
340
+ A Windows checkout (`core.autocrlf=true`) holds `.planning/` with CRLF endings. A parser that matches `\n` only finds nothing there, and says nothing.
341
+
342
+ **Fix:** Parse planning files on LF and write them back in the file's own ending, with `toLf()`, `dominantEol()` and `withEol()` from `core.cjs`. Give a new parser a case in `tests/crlf-parity.test.cjs`, which runs each parser on LF and CRLF copies of the same fixture.
343
+
344
+ ## How to Write a Workflow
345
+
346
+ Workflows are the Layer 2 orchestration files in `pan-wizard-core/workflows/`. They define multi-step procedures that commands execute.
347
+
348
+ 1. Create `pan-wizard-core/workflows/your-workflow.md`
349
+ 2. Structure it with XML steps that load state, spawn agents, and route results
350
+ 3. Reference it from your command .md file via `@~/.claude/pan-wizard-core/workflows/your-workflow.md`
351
+ 4. No installer edit is needed — the installer copies `pan-wizard-core/workflows/` recursively, so new workflows ship automatically. Run `node scripts/test-surface.cjs --write` (the surface registry lists every workflow file) and refresh the Workflows row of the counts table in `CLAUDE.md`, or `npm test` fails (`tests/surface-map.test.cjs`, `tests/claude-md-counts.test.cjs`)
352
+
353
+ **Workflow structure:**
354
+ ```markdown
355
+ <purpose>What this workflow accomplishes.</purpose>
356
+
357
+ <step name="load_state">
358
+ Load context via pan-tools init command:
359
+ INIT=$(node ~/.claude/pan-wizard-core/bin/pan-tools.cjs init your-command "$PHASE")
360
+ Extract fields from JSON output.
361
+ </step>
362
+
363
+ <step name="execute">
364
+ Spawn agents via Task tool or perform direct operations.
365
+ </step>
366
+
367
+ <step name="route">
368
+ Present results and suggest next command.
369
+ </step>
370
+ ```
371
+
372
+ **Naming convention:** Workflow filenames may differ from command filenames (see [ARCHITECTURE.md](ARCHITECTURE.md) for the mapping table). This allows one workflow to serve multiple commands, or internal workflows to have clearer descriptive names.
373
+
374
+ ## How to Write a Reference
375
+
376
+ References are knowledge documents in `pan-wizard-core/references/` that agents load via `@`-syntax in their prompts.
377
+
378
+ 1. Create `pan-wizard-core/references/your-reference.md`
379
+ 2. Use XML tags for structured sections: `<overview>`, `<rules>`, `<examples>`, `<anti_patterns>`
380
+ 3. Reference from agent .md files: `@~/.claude/pan-wizard-core/references/your-reference.md`
381
+ 4. No installer edit is needed — the installer copies `pan-wizard-core/references/` recursively, so new references ship automatically. Refresh the References row of the counts table in `CLAUDE.md` (`tests/claude-md-counts.test.cjs` fails until you do) and add the file to the table below
382
+
383
+ **Current references:**
384
+
385
+ | Reference | Purpose |
386
+ |-----------|---------|
387
+ | `checkpoints.md` | Checkpoint types, automation patterns, auth gates |
388
+ | `continuation-format.md` | "Next Up" block format for workflow transitions |
389
+ | `decimal-phase-calculation.md` | Phase numbering logic for inserted phases |
390
+ | `design-methodology.md` | Shared design method — depth tiers and the quality bar that `pan-designer` (via `/pan:design-phase`) and `focus-design` both hold design artifacts to, and that `pan-design-checker` verifies against |
391
+ | `git-integration.md` | Commit points, commit message formats, why per-task commits |
392
+ | `git-planning-commit.md` | How pan-tools commits planning docs |
393
+ | `guardrails.md` | Behavioral guardrails — anti-patterns, Code Preservation Principle, Stop-the-Line Rule |
394
+ | `handoff-decisions.md` | Planner→executor decision-trace handoff (locked/open/rejected decisions) |
395
+ | `model-profile-resolution.md` | Agent → model mapping with inherit logic |
396
+ | `model-profiles.md` | quality/balanced/budget profile definitions |
397
+ | `phase-argument-parsing.md` | Normalize phase numbers for lookups |
398
+ | `planning-config.md` | Config schema, branching strategies, commit_docs |
399
+ | `questioning.md` | Discussion methodology for new-project/discuss-phase |
400
+ | `tdd.md` | TDD workflow (RED/GREEN/REFACTOR) in plan execution |
401
+ | `ui-brand.md` | Status banners, checkpoint boxes, progress display |
402
+ | `verdict-contract.md` | The `pan-verdict` block judges end their reports with: fields, verdict → outcome per judge, finding classes, severities |
403
+ | `verification-patterns.md` | Stub detection, wiring checks, verification checklists |
404
+
405
+ ## How to Customize Templates
406
+
407
+ Templates in `pan-wizard-core/templates/` scaffold new project files. Agents read these files and fill them in; `template.cjs` never loads them — it selects a summary template and writes pre-filled phase files from its own generators.
408
+
409
+ 1. Templates are plain Markdown files with `{placeholder}` or `[Placeholder]` fields
410
+ 2. `cmdTemplateFill()` (`template fill summary|plan|verification --phase N`) writes a pre-filled file into the phase directory from built-in generators, not from `templates/`
411
+ 3. `cmdTemplateSelect()` auto-selects summary template based on plan complexity:
412
+ - **minimal** — ≤2 tasks, ≤3 files, no decisions
413
+ - **standard** — typical plans
414
+ - **complex** — 7+ files, 6+ tasks, or decisions present
415
+
416
+ **Template categories:**
417
+
418
+ | Category | Templates | Used by |
419
+ |----------|-----------|---------|
420
+ | Project | project.md, requirements.md, roadmap.md, state.md | `/pan:new-project` |
421
+ | Phase | context.md, phase-prompt.md, discovery.md (research.md is unreferenced by shipped content) | `/pan:discuss-phase`, `/pan:plan-phase` (pan-planner follows discovery.md for Level 2 research) |
422
+ | Codebase | architecture.md, stack.md, conventions.md, concerns.md, integrations.md, structure.md, testing.md, relationships.md, best-practices.md | `/pan:map-codebase` |
423
+ | Summary | summary.md (summary-minimal.md, summary-standard.md and summary-complex.md are named only by `pan-tools template select`, which no shipped prompt runs) | pan-executor |
424
+ | Verification | validation.md, verification-report.md (uat.md is unreferenced by shipped content) | the `plan-phase` workflow (validation.md); pan-verifier through the `verify-phase` workflow (verification-report.md) |
425
+ | Debug | debug-subagent-prompt.md (debug.md is named only by `/pan:debug`, as the format of the debug file its continuation agent parses) | the `diagnose-issues` workflow (the native `/pan-diagnose-issues` script carries its own inline prompt) |
426
+ | Planning / execution | user-setup.md (planner-subagent-prompt.md and standards.md are unreferenced by shipped content) | `execute-plan.md` writes `{phase}-USER-SETUP.md` from user-setup.md |
427
+ | Lifecycle | milestone-archive.md, milestone.md (retrospective.md is unreferenced by shipped content; continue-here.md is named only by `/pan:pause`, which writes `.continue-here.md` from its own `<handoff_schema>` in place of both that template and the `pause.md` workflow's inline format) | `/pan:milestone-done` |
428
+ | Spec B v2 | playbook.md (knowledge system), preview-report.md (foresight/preview) | `/pan:knowledge`, `/pan:preview` |
429
+ | Design & experiments | design.md, idea.md | `/pan:design-phase` (pan-designer), `/pan:experiment` |
430
+ | Config | config.json | Unreferenced by shipped content — `config-ensure-section` writes `buildConfigDefaults()` from `config.cjs`, not this file |
431
+
432
+ To customize: edit templates in `pan-wizard-core/templates/` directly. Changes take effect on next use. After PAN updates, check for template changes in the changelog.
433
+
434
+ ## Architecture Overview
435
+
436
+ See [ARCHITECTURE.md](ARCHITECTURE.md) for the full internal architecture guide.
437
+
438
+ Quick summary: Commands -> Workflows -> Agents -> Core Library -> .planning/ state files
439
+
440
+ ### Bot Army subsystem
441
+
442
+ The army turns PAN's agents into a coordinated, role-scoped army. The substrate lives in core modules — `squads.cjs` (the role registry: architecture / build / quality / release), `worktree.cjs` (branch-per-agent git-worktree isolation so parallel builders never collide), `campaign.cjs` (scheduled, self-resuming "dreaming" campaigns), and `hud.cjs` (the single-file HTML dashboard) — driven by the `/pan:army` command, the `pan-conductor` agent (Mission Control — instructed to delegate rather than implement; its `tools:` grant is not narrowed to enforce that), and the `pan-release` agent (the human merge gate). The design rationale is recorded in [ADR-0032 (squad model)](decisions/ADR-0032-squad-model.md), [ADR-0033 (army campaign)](decisions/ADR-0033-army-campaign.md), [ADR-0034 (scheduled campaigns)](decisions/ADR-0034-scheduled-campaigns.md), and [ADR-0035 (army HUD dashboard)](decisions/ADR-0035-army-hud-dashboard.md).
443
+
444
+ ## Distribution Bundles
445
+
446
+ Besides the loose-file installer, two builders package PAN as a plugin. Neither output is committed (`dist/` is ignored) and neither is published yet; both are built and validated by the test suite.
447
+
448
+ | Command | Output | Consumed by | Layout |
449
+ |---|---|---|---|
450
+ | `npm run build:plugin` | `dist/pan-wizard-plugin/` | Claude Code (plugin marketplaces; the local `command`-source test bed in `marketplace/`) | `.claude-plugin/plugin.json`, `commands/`, `agents/`, `hooks/`, `workflows/`, `.mcp.json`, `pan-wizard-core/`, `evals/` (from `harness/plugin-evals/`, checkout builds only) |
451
+ | `npm run build:agent-plugin` | `dist/pan-agent-plugin/` | Copilot CLI / VS Code, Codex, Cursor, Kiro — the vendor-neutral **Agent Plugins 1.0** format (ADR-0045) | `plugin.json`, `skills/`, `mcp.json`, `pan-wizard-core/`, `hooks/` (scripts + Codex `hooks.json`), `com.github.copilot/` (agents + hooks) |
452
+
453
+ Two marketplace files in the repository point at the Agent Plugins build so a checkout can install it without publishing: `.agents/plugins/marketplace.json` (Codex, repo-scoped, discovered automatically inside the repo) and `.github/plugin/marketplace.json` (Copilot, added with `copilot plugin marketplace add`). Both reference `./dist/pan-agent-plugin`, so run the builder first. The release gate (`scripts/release-check.js`, gate 8) builds both bundles into temp directories and fails the release if either does not produce its manifest — and, since `2026-09-10`, digests the local `dist/pan-agent-plugin` (untracked — `dist/` is gitignored) against the fresh build whenever it exists, so a stale bundle behind those two marketplaces fails the release with the fix named.
454
+
455
+ The vendor directories carry their own verification status, recorded in ADR-0045: the Codex hooks shape and `${PLUGIN_ROOT}` expansion come from Codex's plugin reference, but Codex loads no hooks from this bundle, because its root `plugin.json` makes Codex treat it as an Agent Plugin and Codex skips hooks for those (Codex source, read `2026-10-19`). Codex users get PAN's hooks from a `--codex` install; the Copilot namespace and its flat PascalCase hooks come from VS Code's documentation, and a live `copilot plugin install` from a local path has since passed on Copilot CLI 1.0.88 (the harness scenario `live-gate-copilot`; the bundle lists as `pan-wizard`). No Antigravity variant is emitted — its manifest schema is closed and different.
456
+
457
+ Both builders take an output override (`PAN_PLUGIN_OUT`, `PAN_AGENT_PLUGIN_OUT`) and refuse to wipe a directory that is not a previous build of theirs. Tests never build into `dist/`: they go through `buildPluginInto()` / `buildAgentPluginInto()` in `tests/helpers.cjs`, which build into private temp directories, because `node --test` runs files in parallel and two files rebuilding one directory raced.
458
+
459
+ The skills in the Agent Plugins bundle come from the same unified-skills compiler the installer's `--unified-skills` path uses (`rewriteUnifiedSkillCommandContent`, `convertClaudeCommandToUnifiedSkill` in `bin/install-lib.cjs`). Do not add a second converter: `tests/unified-skills-install.test.cjs` pins the installer's output and `tests/agent-plugin-build.test.cjs` pins the bundle's, including that the Claude plugin build carries no bundle token or Agent Plugins artefact.
460
+
461
+ ## Behavioural Harness
462
+
463
+ `harness/` is the PAN Harness (ADR-0047): JSON scenarios run against installs built from a **packed** artifact. A run packs the repository, extracts the tarball (never `npx`), installs from the package into seeded workspaces, and asserts on what the installed PAN does — the install matrix across the five runtimes, the bridge answering for another project through the per-call `cwd`, the deployed native workflow scripts, the Agent Plugins bundle, live gates on CLIs that are present, and (with a spend cap) whole execution chains. It succeeds the external PanLoop harness and lives in-repo so it cannot be lost separately from the contracts it asserts. Not shipped — `harness/` is outside the package `files` allowlist.
464
+
465
+ ```bash
466
+ npm run harness # tier 0 — model-free, free, about a minute
467
+ npm run harness:model -- --max-usd 50 --repeat 5 --scenario native-exec-waves-chain --scenario markdown-exec-phase-chain # tier 2 — the chain pair; without --max-usd the cap is $15
468
+ ```
469
+
470
+ Tier 0 is the one to run before a release; it includes `model` and scripted-`user` steps answered by the local model double (`harness/src/model-double.cjs`) or a committed cassette, which reach no real model and spend nothing. Model tiers spend your Claude usage (or, for a `cli` step marked `paid: true`, that CLI's credits) and are capped at $15 per run unless `--max-usd` (or `PAN_HARNESS_MAX_USD`) gives another figure; the cap is split across the model-tier scenarios in the run. Run state goes outside the checkout (`<test dir>\harness-runs\<run-id>\` on Windows, the first of `C:\Project\pantesting` and `D:\pantesting` that exists, else the OS temp directory; `PAN_HARNESS_STATE` or `--state-dir` overrides it); `harness/ledger.jsonl` is the tracked findings history, deduped by signature. A scenario's `requires` (`cli`, `minVersion`) **skips** it with the reason when the environment cannot run it — never a pass — and a model step that never ran is a harness error, not a finding. Every assertion kind has a both-direction test in `tests/harness.test.cjs` (the double's `wire:` and `drift:` kinds in `tests/model-double.test.cjs`); add a kind there first. `harness/corpus/` holds seeded-defect projects (a clean twin, a defective twin and a held-out catching test each, every entry proven with `verify red` by `tests/harness-corpus.test.cjs`), and `harness/scripts/catch-rate.cjs` scores judge runs against them: catch rate and false-alarm rate with Wilson intervals. `harness/README.md` has the scenario schema, the tiers, and the headless background-wait ceiling the runner lifts.
471
+
472
+ ## Release Process
473
+
474
+ Releases are published by CI from a tag; nothing is published from a laptop. The flow, as run for recent releases:
475
+
476
+ 1. **Gate locally:** `npm run release:check`. It is the same script `prepublishOnly` runs in CI, so a red gate here is a red publish there. In order: hook build; `test:all`; `npm audit --omit=dev`; `doc-lint counts` over `docs/` (no filesystem-derived counts outside `CLAUDE.md`); `links validate` (the doc↔code link graph resolves); `npm pack` size sanity **and zero runtime dependencies**; a smoke install of the packed tarball into a temp directory; both distribution bundles building, with `dist/pan-agent-plugin` digested against the fresh build; and the coverage gate (every dispatcher arm executed plus per-group floors; skipped below Node 22). Run `npm run harness` (tier 0) as well.
477
+ 2. **Refresh the counts table** in `CLAUDE.md` with the snippet it carries — the only place counts live — and, if any command or dev skill changed, regenerate the skills docs: `python scripts/generate-skills-docs.py`.
478
+ 3. **Bump the version** in `package.json` and `package-lock.json` — and the `version` of the `pan-wizard` entry in `.github/plugin/marketplace.json`, which a test pins to it.
479
+ 4. **Turn `## [Unreleased]` into `## [x.y.z] - YYYY-MM-DD`** in `CHANGELOG.md`.
480
+ 5. **Commit as `release(x.y.z): …`** on a `release/vx.y.z` branch, run the full `npm run ci:local` on it, and land it with `npm run land -- release/vx.y.z` (see Landing a change). The macOS jobs in `ci.yml` run on the push to `main`.
481
+ 6. **Tag the merge commit and push the tag by explicit refspec:**
482
+
483
+ ```bash
484
+ git tag vx.y.z && git push origin refs/tags/vx.y.z
485
+ ```
486
+
487
+ A `v*` tag triggers `.github/workflows/release.yml`, which reruns the gates through `prepublishOnly`, publishes with npm provenance, and **creates the GitHub Release** from the `CHANGELOG.md` section for that version. The npm dist-tag comes from the version (`scripts/npm-dist-tag.js`): a prerelease such as `x.y.z-rc.1` publishes under `next` and its GitHub Release is marked as a prerelease, never Latest, so `npm install pan-wizard` keeps resolving to the newest stable release; a plain version publishes under `latest`. Do not rely on `git push --follow-tags` — it has silently dropped the tag before, and then nothing publishes.
488
+
489
+ The Release step landed after 3.29.0 was tagged (that release object was created by hand). Before it, the workflow published to npm and stopped, so every tagged version from 3.15.0 to 3.28.0 carries a tag and an npm release but no release object. The step is `continue-on-error` — the package is already published by the time it runs, so a failure there is a cosmetic omission rather than a failed release — and the run summary states plainly whether the release exists, so an omission is visible instead of silent. A re-run never clobbers an existing release.
490
+ 7. **After a successful publish:** the workflow already ran `deprecate-old-versions.js --apply` and created the Release. The run summary says whether the Release exists; the deprecations appear only in the `Deprecate superseded versions` step log, which stays green even when npm refuses every one. Then upgrade the installs you maintain with the installer. When sweeping a drive for installs to upgrade, exclude **everything** under the test directory (`C:\Project\pantesting\`, or `D:\pantesting\`) except the root — its subdirectories are audit fixtures pinned to the version they were made on, and a name-based denylist has missed them before.