@pareto4/pp-core 1.18.0 → 1.20.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 (194) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/agents/pp-code-fixer.md +9 -5
  3. package/agents/pp-code-reviewer.md +1 -0
  4. package/agents/pp-codebase-mapper.md +3 -0
  5. package/agents/pp-debugger.md +3 -2
  6. package/agents/pp-executor.md +16 -7
  7. package/agents/pp-integration-checker.md +1 -0
  8. package/agents/pp-phase-researcher.md +13 -1
  9. package/agents/pp-plan-checker.md +3 -0
  10. package/agents/pp-planner.md +20 -1
  11. package/agents/pp-research-synthesizer.md +1 -1
  12. package/agents/pp-ui-auditor.md +1 -0
  13. package/agents/pp-ui-researcher.md +3 -1
  14. package/agents/pp-vault-reviewer.md +2 -0
  15. package/agents/pp-verifier.md +22 -10
  16. package/commands/pp-add-tests.md +1 -1
  17. package/commands/pp-debug.md +1 -0
  18. package/commands/pp-discovery.md +3 -2
  19. package/commands/pp-init.md +4 -3
  20. package/commands/pp-quick.md +3 -0
  21. package/commands/pp-review-backlog.md +2 -1
  22. package/gemini-extension.json +1 -1
  23. package/package.json +6 -3
  24. package/pareto-skills/_shared/pp-claude-md-protocol.md +1 -1
  25. package/pareto-skills/pp-project-setup/SKILL.md +18 -343
  26. package/pp-core/bin/lib/capability-registry.cjs +3 -3
  27. package/pp-core/bin/lib/check-command-router.cjs +60 -20
  28. package/pp-core/bin/lib/commands.cjs +79 -4
  29. package/pp-core/bin/lib/compose-bindings.cjs +97 -14
  30. package/pp-core/bin/lib/discovery-access.cjs +276 -0
  31. package/pp-core/bin/lib/discovery-charter.cjs +664 -0
  32. package/pp-core/bin/lib/discovery-deviations.cjs +264 -0
  33. package/pp-core/bin/lib/discovery-entities.cjs +323 -0
  34. package/pp-core/bin/lib/discovery-for-phase.cjs +628 -0
  35. package/pp-core/bin/lib/discovery-integrations.cjs +286 -0
  36. package/pp-core/bin/lib/discovery-migration.cjs +246 -0
  37. package/pp-core/bin/lib/discovery-phases.cjs +233 -0
  38. package/pp-core/bin/lib/discovery-processes.cjs +355 -0
  39. package/pp-core/bin/lib/discovery-research-track.cjs +5 -4
  40. package/pp-core/bin/lib/discovery-rollup.cjs +12 -8
  41. package/pp-core/bin/lib/discovery-rules.cjs +216 -0
  42. package/pp-core/bin/lib/discovery-screens.cjs +21 -3
  43. package/pp-core/bin/lib/discovery-session-check.cjs +264 -0
  44. package/pp-core/bin/lib/discovery-stories.cjs +273 -0
  45. package/pp-core/bin/lib/discovery-sweep.cjs +13 -4
  46. package/pp-core/bin/lib/discovery-table.cjs +55 -0
  47. package/pp-core/bin/lib/discovery-vault-check.cjs +37 -3
  48. package/pp-core/bin/lib/init-contract.cjs +48 -7
  49. package/pp-core/bin/lib/io.cjs +22 -0
  50. package/pp-core/bin/lib/vault-coordinates.cjs +1 -1
  51. package/pp-core/bin/lib/vault-index.cjs +18 -5
  52. package/pp-core/bin/lib/vault-standards-review.cjs +50 -2
  53. package/pp-core/bin/lib/vault-update.cjs +4 -0
  54. package/pp-core/bin/lib/vault.cjs +2 -2
  55. package/pp-core/bin/pp-tools.cjs +153 -5
  56. package/pp-core/org-profile.json +1 -1
  57. package/pp-core/references/autonomous-best-effort.md +3 -2
  58. package/pp-core/references/autonomous-lifecycle.md +1 -0
  59. package/pp-core/references/autonomous-smart-discuss.md +5 -1
  60. package/pp-core/references/discovery-access.md +112 -0
  61. package/pp-core/references/discovery-build-consumption.md +256 -0
  62. package/pp-core/references/discovery-charter.md +127 -0
  63. package/pp-core/references/discovery-data-model.md +145 -0
  64. package/pp-core/references/discovery-id-conventions.md +77 -8
  65. package/pp-core/references/discovery-integrations.md +151 -0
  66. package/pp-core/references/discovery-processes.md +190 -0
  67. package/pp-core/references/discovery-rebaseline.md +2 -2
  68. package/pp-core/references/discovery-research-track.md +5 -6
  69. package/pp-core/references/discovery-session-output.md +70 -0
  70. package/pp-core/references/discovery-standards.md +107 -0
  71. package/pp-core/references/discovery-traceability.md +2 -2
  72. package/pp-core/references/execute-mvp-tdd.md +3 -3
  73. package/pp-core/references/git-integration.md +57 -33
  74. package/pp-core/references/git-planning-commit.md +31 -9
  75. package/pp-core/references/phase-argument-parsing.md +1 -0
  76. package/pp-core/references/planner-discovery-extract.md +35 -0
  77. package/pp-core/references/planner-gap-closure.md +1 -0
  78. package/pp-core/references/planner-revision.md +3 -1
  79. package/pp-core/references/planner-tdd.md +4 -4
  80. package/pp-core/references/planning-config.md +3 -3
  81. package/pp-core/references/shell-portability.md +28 -0
  82. package/pp-core/references/tdd.md +20 -16
  83. package/pp-core/references/verifier-discovery-conformance.md +36 -0
  84. package/pp-core/references/worktree-path-safety.md +1 -0
  85. package/pp-core/templates/milestone.md +5 -5
  86. package/pp-core/templates/project-charter.md +161 -100
  87. package/pp-core/templates/project.md +3 -3
  88. package/pp-core/templates/requirements.md +18 -0
  89. package/pp-core/templates/verification-report.md +16 -0
  90. package/pp-core/workflows/add-backlog.md +1 -1
  91. package/pp-core/workflows/add-tests.md +5 -2
  92. package/pp-core/workflows/add-todo.md +3 -1
  93. package/pp-core/workflows/ai-integration-phase.md +2 -1
  94. package/pp-core/workflows/audit-fix.md +4 -3
  95. package/pp-core/workflows/audit-milestone.md +1 -0
  96. package/pp-core/workflows/autonomous.md +6 -0
  97. package/pp-core/workflows/check-todos.md +2 -1
  98. package/pp-core/workflows/cleanup.md +3 -1
  99. package/pp-core/workflows/code-review-fix.md +12 -5
  100. package/pp-core/workflows/code-review.md +15 -1
  101. package/pp-core/workflows/complete-milestone.md +13 -3
  102. package/pp-core/workflows/debug.md +2 -0
  103. package/pp-core/workflows/diagnose-issues.md +1 -1
  104. package/pp-core/workflows/discovery-sprint/charter.md +114 -0
  105. package/pp-core/workflows/discovery-sprint/prefill.md +1 -1
  106. package/pp-core/workflows/discovery-sprint/prototype.md +4 -4
  107. package/pp-core/workflows/discovery-sprint/session-13-gates.md +11 -1
  108. package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +54 -7
  109. package/pp-core/workflows/discovery-sprint/sessions/02-as-is.md +31 -7
  110. package/pp-core/workflows/discovery-sprint/sessions/03-to-be.md +64 -37
  111. package/pp-core/workflows/discovery-sprint/sessions/04-ux-design.md +12 -3
  112. package/pp-core/workflows/discovery-sprint/sessions/05-architecture.md +45 -22
  113. package/pp-core/workflows/discovery-sprint/sessions/06-security.md +30 -15
  114. package/pp-core/workflows/discovery-sprint/sessions/07-identity.md +43 -25
  115. package/pp-core/workflows/discovery-sprint/sessions/08-integration.md +63 -24
  116. package/pp-core/workflows/discovery-sprint/sessions/09-qa.md +28 -13
  117. package/pp-core/workflows/discovery-sprint/sessions/10-infrastructure.md +35 -16
  118. package/pp-core/workflows/discovery-sprint/sessions/11-roadmap.md +32 -8
  119. package/pp-core/workflows/discovery-sprint/sessions/12-delivery-model.md +21 -18
  120. package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +29 -12
  121. package/pp-core/workflows/discovery-sprint/vault-context.md +14 -3
  122. package/pp-core/workflows/discovery-sprint.md +23 -23
  123. package/pp-core/workflows/discovery-to-build/steps/architecture-deliverables.md +81 -29
  124. package/pp-core/workflows/discovery-to-build/steps/{screen-inventory-gate.md → handoff-gates.md} +111 -3
  125. package/pp-core/workflows/discovery-to-build/templates/discovery-references.md +12 -9
  126. package/pp-core/workflows/discovery-to-build/templates/pp-handoff.md +27 -26
  127. package/pp-core/workflows/discovery-to-build.md +70 -34
  128. package/pp-core/workflows/discuss-phase/discovery.md +83 -0
  129. package/pp-core/workflows/discuss-phase/templates/context.md +4 -0
  130. package/pp-core/workflows/discuss-phase-assumptions.md +5 -3
  131. package/pp-core/workflows/discuss-phase.md +18 -10
  132. package/pp-core/workflows/docs-update.md +1 -0
  133. package/pp-core/workflows/eval-review.md +2 -1
  134. package/pp-core/workflows/execute-phase/steps/check-query-gate.md +7 -6
  135. package/pp-core/workflows/execute-phase/steps/cross-ai-delegation.md +1 -0
  136. package/pp-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +1 -0
  137. package/pp-core/workflows/execute-phase/steps/vault-fetch.md +12 -0
  138. package/pp-core/workflows/execute-phase.md +19 -7
  139. package/pp-core/workflows/execute-plan.md +18 -7
  140. package/pp-core/workflows/explore.md +1 -1
  141. package/pp-core/workflows/forensics.md +4 -2
  142. package/pp-core/workflows/health.md +1 -0
  143. package/pp-core/workflows/import.md +2 -1
  144. package/pp-core/workflows/ingest-docs.md +1 -0
  145. package/pp-core/workflows/init/steps/client-context-capture.md +1 -0
  146. package/pp-core/workflows/init/steps/github-provisioning.md +145 -0
  147. package/pp-core/workflows/init/steps/gitlab-provisioning.md +18 -4
  148. package/pp-core/workflows/init/steps/reachability-outcome.md +3 -1
  149. package/pp-core/workflows/init.md +56 -66
  150. package/pp-core/workflows/map-codebase.md +5 -1
  151. package/pp-core/workflows/milestone-summary.md +2 -1
  152. package/pp-core/workflows/mvp-phase.md +1 -0
  153. package/pp-core/workflows/new-milestone.md +9 -5
  154. package/pp-core/workflows/new-project.md +12 -11
  155. package/pp-core/workflows/new-workspace.md +1 -0
  156. package/pp-core/workflows/next.md +2 -1
  157. package/pp-core/workflows/pause-work.md +6 -4
  158. package/pp-core/workflows/plan-milestone-gaps.md +3 -1
  159. package/pp-core/workflows/plan-phase/steps/chunked-planning.md +1 -1
  160. package/pp-core/workflows/plan-phase/steps/discovery-extract.md +41 -0
  161. package/pp-core/workflows/plan-phase.md +36 -16
  162. package/pp-core/workflows/plan-review-convergence.md +2 -0
  163. package/pp-core/workflows/plant-seed.md +4 -2
  164. package/pp-core/workflows/pr-branch.md +2 -0
  165. package/pp-core/workflows/progress.md +5 -0
  166. package/pp-core/workflows/quick.md +11 -4
  167. package/pp-core/workflows/reapply-patches.md +3 -0
  168. package/pp-core/workflows/remove-phase.md +1 -1
  169. package/pp-core/workflows/resume-project.md +3 -0
  170. package/pp-core/workflows/review.md +7 -1
  171. package/pp-core/workflows/secure-phase.md +2 -1
  172. package/pp-core/workflows/session-report.md +1 -0
  173. package/pp-core/workflows/ship.md +8 -1
  174. package/pp-core/workflows/sketch-wrap-up.md +1 -1
  175. package/pp-core/workflows/sketch.md +3 -2
  176. package/pp-core/workflows/spec-phase.md +2 -1
  177. package/pp-core/workflows/spike-wrap-up.md +1 -1
  178. package/pp-core/workflows/spike.md +4 -3
  179. package/pp-core/workflows/sync-skills.md +5 -2
  180. package/pp-core/workflows/thread.md +3 -2
  181. package/pp-core/workflows/transition.md +6 -0
  182. package/pp-core/workflows/ui-phase.md +3 -1
  183. package/pp-core/workflows/ui-review.md +2 -1
  184. package/pp-core/workflows/ultraplan-phase.md +1 -0
  185. package/pp-core/workflows/undo.md +14 -10
  186. package/pp-core/workflows/update.md +5 -0
  187. package/pp-core/workflows/validate-phase.md +6 -3
  188. package/pp-core/workflows/vault-review.md +7 -1
  189. package/pp-core/workflows/vault-write-back.md +5 -0
  190. package/pp-core/workflows/verify-phase.md +5 -0
  191. package/pp-core/workflows/verify-work.md +8 -1
  192. package/scripts/prompt-injection-scan.sh +1 -1
  193. package/scripts/sync-runtime-launcher.cjs +115 -5
  194. package/pp-core/workflows/discovery-sprint/templates/context-template.md +0 -266
@@ -0,0 +1,41 @@
1
+ # Plan-phase step — Discovery extract (R1)
2
+
3
+ > Read and executed from `workflows/plan-phase.md` §7 after the context paths are extracted and
4
+ > before the researcher (§5.1) and planner (§8) prompts are built. Inert on a project without
5
+ > `.planning/discovery/`. Contract: `references/discovery-build-consumption.md`.
6
+
7
+ Render the phase's discovery rows fresh — the registers may have been amended since
8
+ `/pp-discuss-phase` wrote CONTEXT.md — into one file the researcher and the planner read:
9
+
10
+ ```bash
11
+ _PP_SHIM_NAME="pp-tools.cjs"; _pp_root() { ( for _v in $(env | sed -n 's/^\(GIT_[A-Za-z0-9_]*\)=.*/\1/p'); do unset "$_v"; done; _c=$(git rev-parse --git-common-dir 2>/dev/null); if [ "${_c##*/}" = .git ] && cd "$_c/.." 2>/dev/null; then pwd -P; else git rev-parse --show-toplevel 2>/dev/null || pwd; fi ); }; pp_run() { case "$PP_TOOLS" in *.cjs) node "$PP_TOOLS" "$@";; *) "$PP_TOOLS" "$@";; esac; }; _PP_RUNTIME_ROOT="${RUNTIME_DIR:-$(_pp_root)}"; PP_TOOLS="${_PP_RUNTIME_ROOT}/pp-core/bin/${_PP_SHIM_NAME}"; if [ -f "$PP_TOOLS" ]; then :; elif [ -f "${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}"; elif command -v pp-tools >/dev/null 2>&1; then PP_TOOLS="$(command -v pp-tools)"; else echo "ERROR: pp-tools.cjs not found at $PP_TOOLS and pp-tools is not on PATH. Run: npx -y @pareto4/pp-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${PP_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${PP_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
12
+ DISCOVERY_EXTRACT_PATH=""
13
+ _DX_JSON=$(pp_run query discovery.for-phase "${PHASE_NUMBER}" 2>/dev/null || true)
14
+ if [[ "$_DX_JSON" == @file:* ]]; then _DX_JSON=$(cat "${_DX_JSON#@file:}"); fi
15
+ _DX_PRESENT=$(printf '%s' "$_DX_JSON" | node -e "let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{try{const o=JSON.parse(s);console.log(o.present===true&&o.ok===true?'true':'false')}catch{console.log('false')}})")
16
+ if [ "$_DX_PRESENT" = true ]; then
17
+ DISCOVERY_EXTRACT_PATH="${PHASE_DIR}/${PADDED_PHASE}-DISCOVERY-EXTRACT.md"
18
+ pp_run query discovery.for-phase "${PHASE_NUMBER}" --markdown > "${DISCOVERY_EXTRACT_PATH}"
19
+ echo "DISCOVERY_EXTRACT_PATH=${DISCOVERY_EXTRACT_PATH}"
20
+ else
21
+ rm -f "${PHASE_DIR}/${PADDED_PHASE}-DISCOVERY-EXTRACT.md"
22
+ fi
23
+ ```
24
+
25
+ A non-zero exit from the first command is a structural fault in a discovery artifact
26
+ (`discovery_for_phase_failed`): print the fault list and stop. Planning on a malformed register
27
+ copies the malformation into the build; the sprint's own check names the row to fix.
28
+
29
+ When `DISCOVERY_EXTRACT_PATH` is non-empty:
30
+
31
+ - add `- {DISCOVERY_EXTRACT_PATH} (Discovery extract — register rows citing this phase's
32
+ requirement IDs; required reading, never open a session-NN.md)` to the `<files_to_read>` of
33
+ the researcher prompt (§5.1) and the planner prompt (§8);
34
+ - the planner embeds the file's content verbatim — markers included — as the `<discovery_extract>`
35
+ block of every PLAN.md it writes, after `<context>` (and after `<vault_standards>` when present)
36
+ and before `<tasks>`;
37
+ - the file is a render and is never committed: it is regenerated on every planning run and
38
+ `*-DISCOVERY-EXTRACT.md` is not a phase artifact.
39
+
40
+ The name is deliberate: `{padded}-DISCOVERY.md` already belongs to the planner's library
41
+ discovery protocol and is a different thing.
@@ -63,7 +63,7 @@ for the plan-checker gate to be meaningful.
63
63
 
64
64
  ## 0. Git Branch Invariant
65
65
 
66
- **Do not create, rename, or switch git branches during plan-phase.** Branch identity is established at discuss-phase and is owned by the user's git workflow. A phase rename in ROADMAP.md is a plan-level change only — it does not mutate git branch names. If `phase_slug` in the init JSON differs from the current branch name, that is expected and correct; leave the branch unchanged.
66
+ **Do not create, rename, or switch git branches during plan-phase.** Branch identity is established at discuss-phase and owned by the user's git workflow. A phase rename in ROADMAP.md is a plan-level change only — it never mutates branch names. A `phase_slug` differing from the current branch name is expected; leave the branch unchanged.
67
67
 
68
68
  ## 1. Initialize
69
69
 
@@ -71,6 +71,7 @@ Load all context in one call (paths only to minimize orchestrator context):
71
71
 
72
72
  ```bash
73
73
  _PP_SHIM_NAME="pp-tools.cjs"; _pp_root() { ( for _v in $(env | sed -n 's/^\(GIT_[A-Za-z0-9_]*\)=.*/\1/p'); do unset "$_v"; done; _c=$(git rev-parse --git-common-dir 2>/dev/null); if [ "${_c##*/}" = .git ] && cd "$_c/.." 2>/dev/null; then pwd -P; else git rev-parse --show-toplevel 2>/dev/null || pwd; fi ); }; pp_run() { case "$PP_TOOLS" in *.cjs) node "$PP_TOOLS" "$@";; *) "$PP_TOOLS" "$@";; esac; }; _PP_RUNTIME_ROOT="${RUNTIME_DIR:-$(_pp_root)}"; PP_TOOLS="${_PP_RUNTIME_ROOT}/pp-core/bin/${_PP_SHIM_NAME}"; if [ -f "$PP_TOOLS" ]; then :; elif [ -f "${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}"; elif command -v pp-tools >/dev/null 2>&1; then PP_TOOLS="$(command -v pp-tools)"; else echo "ERROR: pp-tools.cjs not found at $PP_TOOLS and pp-tools is not on PATH. Run: npx -y @pareto4/pp-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${PP_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${PP_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
74
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
74
75
  GRAN_PARAM=""; if [[ "$ARGUMENTS" =~ (^|[[:space:]])--granularity[[:space:]]+([^[:space:]-][^[:space:]]*) ]]; then GRAN_PARAM="--granularity ${BASH_REMATCH[2]}"; fi
75
76
  INIT=$(pp_run query init.plan-phase "$PHASE" $GRAN_PARAM)
76
77
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
@@ -83,7 +84,7 @@ MVP_MODE_CFG=$(pp_run query config-get workflow.mvp_mode 2>/dev/null || echo "fa
83
84
 
84
85
  When the tdd capability's `workflow.tdd_mode` is active (resolved via the plan:pre render-hooks), the planner agent is instructed to apply `type: tdd` to eligible tasks using heuristics from `references/tdd.md`. The TDD guidance is injected via the tdd capability's contribution hook at §5.6; no inline config-get is needed.
85
86
 
86
- When `CONTEXT_WINDOW >= 500000`, the planner prompt includes the 3 most recent prior phase CONTEXT.md and SUMMARY.md files PLUS any phases explicitly listed in the current phase's `Depends on:` field in ROADMAP.md. Explicit dependencies always load regardless of recency (e.g., Phase 7 declaring `Depends on: Phase 2` always sees Phase 2's context). Bounded recency keeps the planner's context budget focused on recent work.
87
+ When `CONTEXT_WINDOW >= 500000`, the planner prompt includes the 3 most recent prior phase CONTEXT.md and SUMMARY.md files PLUS any phases explicitly listed in the current phase's `Depends on:` field in ROADMAP.md. Explicit dependencies always load regardless of recency (e.g., Phase 7 declaring `Depends on: Phase 2` always sees Phase 2's context).
87
88
 
88
89
  Parse JSON for: `researcher_model`, `planner_model`, `checker_model`, `research_enabled`, `plan_checker_enabled`, `nyquist_validation_enabled`, `commit_docs`, `text_mode`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `has_research`, `has_context`, `has_reviews`, `has_plans`, `plan_count`, `phase_status` (#3569), `planning_exists`, `roadmap_exists`, `phase_req_ids`, `response_language`, `granularity`.
89
90
 
@@ -95,11 +96,12 @@ Parse JSON for: `researcher_model`, `planner_model`, `checker_model`, `research_
95
96
 
96
97
  ## 1.5. Closed-Phase Gate (#3569)
97
98
 
98
- The init JSON includes `phase_status` — one of `Pending | Planned | In Progress | Executed | Complete | Needs Review`. `Complete` means the phase has all summaries AND a `VERIFICATION.md` with `status: passed`. Replanning a closed phase silently rewrites plan docs that no longer match the shipped code, so the workflow must hard-stop here unless the operator explicitly overrides.
99
+ The init JSON includes `phase_status` — one of `Pending | Planned | In Progress | Executed | Complete | Needs Review`. `Complete` means all summaries exist AND a `VERIFICATION.md` with `status: passed`. Replanning a closed phase silently rewrites plan docs that no longer match the shipped code; the workflow hard-stops here unless the operator overrides.
99
100
 
100
101
  Parse `phase_status` from the init JSON, then:
101
102
 
102
103
  ```bash
104
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
103
105
  FORCE_REPLAN=false
104
106
  if [[ "$ARGUMENTS" =~ (^|[[:space:]])--force([[:space:]]|$) ]]; then
105
107
  FORCE_REPLAN=true
@@ -140,7 +142,7 @@ The gate fires only on `Complete`. `Executed` and `Needs Review` are not gated
140
142
 
141
143
  Extract from $ARGUMENTS: phase number (integer or decimal like `2.1`), flags (`--research`, `--skip-research`, `--research-phase <N>`, `--gaps`, `--skip-verify`, `--skip-ui`, `--prd <filepath>`, `--ingest <path-or-glob>`, `--ingest-format <auto|nygard|madr|narrative>`, `--reviews`, `--text`, `--bounce`, `--skip-bounce`, `--chunked`, `--mvp`, `--tdd`, `--granularity <coarse|standard|fine>`, `--force` (override closed-phase gate, see §1.5), `--unattended`).
142
144
 
143
- **`--research-phase <N>` — research-only mode (#3042 + #3044).** When this flag is present, parse `<N>` as the phase number (overrides any positional phase argument), set `RESEARCH_ONLY=true`, and treat the rest of this workflow as a research-dispatch only — the planner spawn (step 8), plan-checker, verification, gaps, bounce, and post-planning-gaps blocks all skip on `RESEARCH_ONLY`. Use this for cross-phase research, doc review before committing to a planning approach, and correction-without-replanning loops. Replaces the deleted `/pp-research-phase` command.
145
+ **`--research-phase <N>` — research-only mode (#3042 + #3044).** When present, parse `<N>` as the phase number (overrides any positional phase argument), set `RESEARCH_ONLY=true`, and treat the rest of this workflow as a research dispatch only — the planner spawn (step 8), plan-checker, verification, gaps, bounce and post-planning-gaps blocks all skip on `RESEARCH_ONLY`. Use it for cross-phase research, doc review before committing to an approach, and correction-without-replanning loops. Replaces the deleted `/pp-research-phase` command.
144
146
 
145
147
  In research-only mode, two modifiers control behavior when `RESEARCH.md` already exists:
146
148
 
@@ -148,6 +150,7 @@ In research-only mode, two modifiers control behavior when `RESEARCH.md` already
148
150
  - **`--view`** — view-only: print existing `RESEARCH.md` to stdout, do **not** spawn the researcher. Sets `VIEW_ONLY=true`. Cheapest mode for the correction-without-replanning loop. If `RESEARCH.md` does not exist, error with a hint to drop `--view`.
149
151
 
150
152
  ```bash
153
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
151
154
  RESEARCH_ONLY=false
152
155
  VIEW_ONLY=false
153
156
  if [[ "$ARGUMENTS" =~ --research-phase[[:space:]]+([0-9]+(\.[0-9]+)?) ]]; then
@@ -159,9 +162,9 @@ if $RESEARCH_ONLY && [[ "$ARGUMENTS" =~ (^|[[:space:]])--view([[:space:]]|$) ]];
159
162
  fi
160
163
  ```
161
164
 
162
- **`--granularity <coarse|standard|fine>` — CLI override (#703).** When present, this value is the resolved granularity passed to the planner — it wins over any per-phase `granularities.<type>` config, top-level `granularity` config, or project defaults. The init JSON always includes a `granularity` field reflecting the resolved value; read it from there. Invalid values (anything other than `coarse`, `standard`, `fine`) cause an error at the CLI boundary.
165
+ **`--granularity <coarse|standard|fine>` — CLI override (#703).** When present, this is the resolved granularity passed to the planner — it wins over per-phase `granularities.<type>` config, top-level `granularity` config and project defaults. The init JSON always carries the resolved `granularity` field; read it from there. Any other value (not `coarse`, `standard`, `fine`) errors at the CLI boundary.
163
166
 
164
- **`--unattended`** — set by `/pp:autonomous` (never `--auto`, which would auto-advance into execute-phase). At each prompt site marked `U-Pn` below, do not prompt: apply rule `U-Pn` from `pp-core/references/autonomous-best-effort.md` (Read it at the first such site) and append the record it names to the phase's AUTONOMOUS-REPORT. It does not touch `workflow._auto_chain_active`.
167
+ **`--unattended`** — set by `/pp:autonomous` (never `--auto`, which would auto-advance into execute-phase). At each prompt site marked `U-Pn` below, do not prompt: apply rule `U-Pn` from `pp-core/references/autonomous-best-effort.md` (Read at first use) and append the record it names to the phase's AUTONOMOUS-REPORT. It does not touch `workflow._auto_chain_active`.
165
168
 
166
169
  Set `TEXT_MODE=true` if `--text` is present in $ARGUMENTS OR `text_mode` from init JSON is `true`. When `TEXT_MODE` is active, replace every `AskUserQuestion` call with a plain-text numbered list and ask the user to type their choice number. This is required for Claude Code remote sessions (`/rc` mode) where TUI menus don't work through the Claude App.
167
170
 
@@ -191,7 +194,7 @@ When `WALKING_SKELETON=true`:
191
194
  - Planner is instructed to produce `SKELETON.md` in the phase directory alongside `PLAN.md`. The template lives at `~/.claude/pp-core/references/skeleton-template.md` — the planner reads it when producing SKELETON.md (lazy; not loaded on non-skeleton runs).
192
195
  - The plan must scaffold project + routing + one real DB read/write + one real UI interaction + dev deployment — the thinnest possible end-to-end working slice.
193
196
 
194
- **Interaction with `--prd <filepath>`.** `--mvp` and `--prd` compose. The PRD express path (Step 3.5) creates `CONTEXT.md` from the PRD file and continues to research; the Walking Skeleton gate fires independently from the conditions above. When both are active on Phase 1 of a new project, the planner receives `WALKING_SKELETON=true` and PRD-derived context simultaneously — the PRD informs *what the skeleton should prove*. No precedence is needed; the two signals are orthogonal. See [`references/mvp-concepts.md`](../references/mvp-concepts.md) for the broader interaction map.
197
+ **Interaction with `--prd <filepath>`.** `--mvp` and `--prd` compose: the PRD express path (Step 3.5) creates `CONTEXT.md` from the PRD file and continues to research; the Walking Skeleton gate fires independently. On Phase 1 of a new project the planner receives `WALKING_SKELETON=true` and PRD-derived context together — the PRD informs *what the skeleton should prove*; the two signals are orthogonal. See [`references/mvp-concepts.md`](../references/mvp-concepts.md).
195
198
 
196
199
  Extract express-path args from $ARGUMENTS: `PRD_FILE` (`--prd <filepath>`), `INGEST_PATH` (`--ingest <path-or-glob>`), and optional `INGEST_FORMAT` (`--ingest-format <auto|nygard|madr|narrative>`, default `auto`).
197
200
 
@@ -246,6 +249,7 @@ PHASE_INFO=$(pp_run query roadmap.get-phase "${PHASE}")
246
249
 
247
250
  Now that `PHASE` is finalized, resolve MVP mode:
248
251
  ```bash
252
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
249
253
  MVP_MODE=$(pp_run query phase.mvp-mode "${PHASE}" $MVP_FLAG_ARG --pick active)
250
254
  ```
251
255
 
@@ -346,7 +350,7 @@ Use full relative paths. Group by topic area.]
346
350
 
347
351
  5. Commit:
348
352
  ```bash
349
- pp_run query commit "docs(${padded_phase}): generate context from PRD" --files "${phase_dir}/${padded_phase}-CONTEXT.md"
353
+ pp_run query commit "docs(planning): generate context from PRD" --phase "${padded_phase}" --files "${phase_dir}/${padded_phase}-CONTEXT.md"
350
354
  ```
351
355
 
352
356
  6. Set `context_content` to the generated CONTEXT.md content and continue to step 5 (Handle Research).
@@ -364,7 +368,7 @@ pp_run query commit "docs(${padded_phase}): generate context from PRD" --files "
364
368
  3. Status gate: reject `superseded`/`rejected`/`deprecated`; warn on `proposed`; missing status defaults to `accepted`.
365
369
  4. Empty-decisions fallback: if all parsed ADRs have zero `decisions[]`, emit `ADR ingest produced no locked decisions; fall back to discuss-phase for this phase.` and exit with `/pp:discuss-phase {N}` guidance.
366
370
  5. Generate CONTEXT.md using `<domain>`, `<decisions>`, `<canonical_refs>`, `<specifics>`, `<deferred>`, `<scope_fence>`, map `consequences_positive[]` to Success Criteria and `consequences_negative[]` to Risk Summary, and include `**Source:** ADR Ingest Express Path ({INGEST_PATH})`.
367
- 6. Commit with `pp-tools.cjs query commit "docs(${padded_phase}): generate context from ADR ingest" --files "${phase_dir}/${padded_phase}-CONTEXT.md"` and set `context_content`; continue to step 5.
371
+ 6. Commit with `pp-tools.cjs query commit "docs(planning): generate context from ADR ingest" --phase "${padded_phase}" --files "${phase_dir}/${padded_phase}-CONTEXT.md"` and set `context_content`; continue to step 5.
368
372
 
369
373
  **Effect:** This bypasses step 4 (Load CONTEXT.md) since CONTEXT.md was synthesized from ADR input.
370
374
 
@@ -415,6 +419,7 @@ If "Run discuss-phase first":
415
419
  AI integration activation is owned by the `ai-integration` capability's `plan:pre` step hook. The plan-phase host only discovers existing artifacts here so the planner can consume them; it must not read the capability's config key directly.
416
420
 
417
421
  ```bash
422
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
418
423
  AI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-AI-SPEC.md 2>/dev/null | head -1)
419
424
  AI_SPEC_PATH="${AI_SPEC_FILE}"
420
425
  FRAMEWORK_LINE=""
@@ -522,7 +527,9 @@ Read and execute `pp-core/workflows/execute-phase/steps/vault-fetch.md` — the
522
527
 
523
528
  ### into:researcher contributions
524
529
 
525
- In `PLAN_PRE_HOOKS_JSON`, read active plan:pre entries where `kind == "contribution"` and `into == "researcher"` (in array order). If none, inject nothing. If present, append each entry's `fragment.inline` verbatim to `filled_research_hook_fragment` (or add it as a `<files_to_read>`/context line in the researcher prompt) — typically a pointer to `.planning/vault/SUMMARY.md` (the bounded vault index). Inject verbatim — do not paraphrase.
530
+ In `PLAN_PRE_HOOKS_JSON`, read active plan:pre entries where `kind == "contribution"` and `into == "researcher"` (in array order). If none, inject nothing. If present, append each entry's `fragment.inline` verbatim to `filled_research_hook_fragment` (or as a `<files_to_read>` line in the researcher prompt) — typically a pointer to `.planning/vault/SUMMARY.md`. Inject verbatim — do not paraphrase.
531
+
532
+ When `DISCOVERY_EXTRACT_PATH` (§7) is set, add `- {DISCOVERY_EXTRACT_PATH} (Discovery extract — required reading)` to the researcher `<files_to_read>`.
526
533
 
527
534
  Find the active `research` step hook in `PLAN_PRE_HOOKS_JSON`. Use the hook's `fragment.inline` as the prompt template and substitute the phase fields below before spawning its declared `ref.agent`.
528
535
 
@@ -578,6 +585,7 @@ If `research_enabled` is false and `nyquist_validation_enabled` is true: warn "N
578
585
  In that case: **skip validation-strategy creation entirely**. Do **not** expect `RESEARCH.md` or `VALIDATION.md` for this run, and continue to Step 6.
579
586
 
580
587
  ```bash
588
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
581
589
  grep -l "## Validation Architecture" "${PHASE_DIR}"/*-RESEARCH.md 2>/dev/null || true
582
590
  ```
583
591
 
@@ -590,7 +598,7 @@ grep -l "## Validation Architecture" "${PHASE_DIR}"/*-RESEARCH.md 2>/dev/null ||
590
598
  test -f "${PHASE_DIR}/${PADDED_PHASE}-VALIDATION.md" && echo "VALIDATION_CREATED=true" || echo "VALIDATION_CREATED=false"
591
599
  ```
592
600
  5. If `VALIDATION_CREATED=false`: STOP — do not proceed to Step 6
593
- 6. If `commit_docs`: `commit "docs(phase-${PHASE}): add validation strategy"`
601
+ 6. If `commit_docs`: `commit "docs(planning): add validation strategy" --phase "${PADDED_PHASE}"`
594
602
 
595
603
  **If not found:** Warn and continue — plans may fail Dimension 8.
596
604
 
@@ -606,7 +614,7 @@ Resolve active contribution hooks from `PLAN_PRE_HOOKS_JSON` where `kind == "con
606
614
 
607
615
  **If no active security contribution hook exists:** Skip to step 5.6.
608
616
 
609
- **If an active security contribution hook exists:** Read `SECURITY_ASVS` from the active hook's `configValues.security_asvs_level` (default: `1`) and `SECURITY_BLOCK` from `configValues.security_block_on` (default: `"high"`). These values are resolved by the capability registry from user config using the same four-level precedence as hook activation — no inline `config-get` is needed.
617
+ **If an active security contribution hook exists:** Read `SECURITY_ASVS` from the active hook's `configValues.security_asvs_level` (default: `1`) and `SECURITY_BLOCK` from `configValues.security_block_on` (default: `"high"`). The registry resolves them from user config with the same four-level precedence as hook activation — no inline `config-get` is needed.
610
618
 
611
619
  Display banner:
612
620
 
@@ -660,6 +668,7 @@ Read `frontend`, `hasUiSpec`, and `block` from `GATE`.
660
668
  **Branch 3 — UI-SPEC already exists (`hasUiSpec` is `true`):**
661
669
 
662
670
  ```bash
671
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
663
672
  UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1)
664
673
  UI_SPEC_PATH="${UI_SPEC_FILE}"
665
674
  ```
@@ -685,6 +694,7 @@ Skill(skill="pp-${ref.skill}", args="${PHASE} --auto ${GSD_WS}")
685
694
  After all UI step hooks return, re-read:
686
695
 
687
696
  ```bash
697
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
688
698
  UI_SPEC_FILE=$(ls "${PHASE_DIR}"/*-UI-SPEC.md 2>/dev/null | head -1)
689
699
  UI_SPEC_PATH="${UI_SPEC_FILE}"
690
700
  ```
@@ -729,6 +739,7 @@ In `PLAN_PRE_HOOKS_JSON` (already loaded), find active plan:pre entries where `k
729
739
  ## 6. Check Existing Plans
730
740
 
731
741
  ```bash
742
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
732
743
  ls "${PHASE_DIR}"/*-PLAN.md 2>/dev/null || true
733
744
  ```
734
745
 
@@ -741,6 +752,7 @@ ls "${PHASE_DIR}"/*-PLAN.md 2>/dev/null || true
741
752
  Extract from INIT JSON:
742
753
 
743
754
  ```bash
755
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
744
756
  _gsd_field() { node -e "const o=JSON.parse(process.argv[1]); const v=o[process.argv[2]]; process.stdout.write(v==null?'':String(v))" "$1" "$2"; }
745
757
  STATE_PATH=$(_gsd_field "$INIT" state_path)
746
758
  ROADMAP_PATH=$(_gsd_field "$INIT" roadmap_path)
@@ -765,6 +777,8 @@ SPEC_FILE=$(ls "${PHASE_DIR_FOR_SPEC}"/*-SPEC.md 2>/dev/null | grep -Ev -- '-(AI
765
777
  SPEC_PATH="${SPEC_FILE}"
766
778
  ```
767
779
 
780
+ Then Read and execute `pp-core/workflows/plan-phase/steps/discovery-extract.md` (sets `DISCOVERY_EXTRACT_PATH`; inert without `.planning/discovery/`).
781
+
768
782
  ## 7.5. Verify Nyquist Artifacts
769
783
 
770
784
  Skip if `nyquist_validation_enabled` is false OR `research_enabled` is false.
@@ -777,6 +791,7 @@ Also skip if all of the following are true:
777
791
  In that no-research path, Nyquist artifacts are **not required** for this run.
778
792
 
779
793
  ```bash
794
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
780
795
  VALIDATION_EXISTS=$(ls "${PHASE_DIR}"/*-VALIDATION.md 2>/dev/null | head -1)
781
796
  ```
782
797
 
@@ -879,6 +894,7 @@ Planner prompt:
879
894
  - {AI_SPEC_PATH} (AI Design Contract — framework and evaluation strategy, if exists)
880
895
  - {UI_SPEC_PATH} (UI Design Contract — visual/interaction specs, if exists)
881
896
  - {SPEC_PATH} (Phase SPEC — carries the ## Edge Coverage section to lift covered/backstop edges from, if exists)
897
+ - {DISCOVERY_EXTRACT_PATH} (Discovery extract — required reading, embed verbatim as <discovery_extract>; if exists)
882
898
  - {SPIKE_FINDINGS_PATH} (Spike Findings — validated patterns, constraints, landmines from experiments, if exists)
883
899
  - {SKETCH_FINDINGS_PATH} (Sketch Findings — validated design decisions, CSS patterns, visual direction, if exists)
884
900
  - {API_SURFACE_PATH} (API Surface — HINT ONLY, when intel capability is active; see <intel_surface_hint> below)
@@ -893,7 +909,7 @@ ${CONTEXT_WINDOW >= 500000 ? `
893
909
  </files_to_read>
894
910
  ${API_SURFACE_PATH ? `
895
911
  <intel_surface_hint>
896
- **API Surface (HINT — may be incomplete):** When \`intel.enabled\` is true, \`.planning/intel/API-SURFACE.md\` lists symbols extracted from the codebase by regex/JS analysis. Prefer symbols listed there when referencing existing code. This surface is regex/JS-derived and MAY BE INCOMPLETE — a symbol's absence means *unknown*, not *nonexistent*. Never treat the surface as exhaustive. If you reference a symbol that is not in the surface and this phase creates it, list it under "Artifacts this phase produces".
912
+ **API Surface (HINT — may be incomplete):** When \`intel.enabled\` is true, \`.planning/intel/API-SURFACE.md\` lists symbols extracted from the codebase by regex/JS analysis. Prefer its symbols when referencing existing code. The surface is regex/JS-derived and MAY BE INCOMPLETE — a symbol's absence means *unknown*, not *nonexistent*; never treat it as exhaustive. If you reference a symbol not in the surface that this phase creates, list it under "Artifacts this phase produces".
897
913
  </intel_surface_hint>
898
914
  ` : ''}
899
915
  ${AGENT_SKILLS_PLANNER}
@@ -933,7 +949,7 @@ Output consumed by /pp:execute-phase. Plans need:
933
949
  - Verification criteria
934
950
  - must_haves for goal-backward verification
935
951
  - If the SPEC has an `## Edge Coverage` section, lift every `covered` edge's acceptance criterion into `must_haves.truths`, and every `backstop` edge into `must_haves.truths` as a non-inferable check (note it needs a held-out/property-based test). `unresolved` edges are explicit assumptions — surface them in the plan, do not silently drop them.
936
- - If the SPEC has a `## Prohibitions` section, lift every resolved prohibition into the `must_haves.prohibitions:` sibling block (NOT `truths` — ADR-550 D3) carrying `statement` + `status` + `verification`; unresolved prohibitions are explicit assumptions — surface them in the plan, do not silently drop them. A prohibition is a must-NOT (negative) check that belongs in its own `must_haves.prohibitions` block. Never place a must-NOT under `must_haves.truths` — that block keeps positive-observable semantics only.
952
+ - If the SPEC has a `## Prohibitions` section, lift every resolved prohibition into the `must_haves.prohibitions:` sibling block (NOT `truths` — ADR-550 D3) carrying `statement` + `status` + `verification`; unresolved prohibitions are explicit assumptions — surface them in the plan, do not silently drop them. A prohibition is a must-NOT (negative) check with its own `must_haves.prohibitions` block. Never place one under `must_haves.truths`, which keeps positive-observable semantics only.
937
953
  - **"Artifacts this phase produces" section (MANDATORY)** — list every symbol this phase creates: decorators, classes, functions, CLI flags, struct/dataclass fields, new file paths. The plan-review-convergence source-grounding pass reads this section to exclude newly-created symbols from drift verification; omitting it causes new symbols to be flagged for acknowledgement.
938
954
  </downstream_consumer>
939
955
 
@@ -1017,6 +1033,7 @@ Read and execute `pp-core/workflows/plan-phase/steps/chunked-planning.md` — th
1017
1033
  **Triggered when:** Agent() returns but the return contains no recognized marker (`## PLANNING COMPLETE`, `## PHASE SPLIT RECOMMENDED`, `## ⚠ Source Audit`, `## CHECKPOINT REACHED`, `## PLANNING INCONCLUSIVE`).
1018
1034
 
1019
1035
  ```bash
1036
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
1020
1037
  DISK_PLANS=$(ls "${PHASE_DIR}"/*-PLAN.md 2>/dev/null | wc -l | tr -d ' ')
1021
1038
  ```
1022
1039
 
@@ -1216,6 +1233,7 @@ If thinking_partner disabled: skip this block entirely.
1216
1233
  **Triggered when:** Checker Agent() returns but the return contains neither `## VERIFICATION PASSED` nor `## ISSUES FOUND`.
1217
1234
 
1218
1235
  ```bash
1236
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
1219
1237
  DISK_PLANS=$(ls "${PHASE_DIR}"/*-PLAN.md 2>/dev/null | wc -l | tr -d ' ')
1220
1238
  ```
1221
1239
 
@@ -1370,7 +1388,7 @@ After the script returns, check that the bounced file still has valid YAML front
1370
1388
 
1371
1389
  6. **Commit surviving bounced plans:** If at least one plan survived both the frontmatter validation and the checker re-run, commit the changes:
1372
1390
  ```bash
1373
- pp_run query commit "refactor(${padded_phase}): bounce plans through external refinement" --files "${PHASE_DIR}/*-PLAN.md"
1391
+ pp_run query commit "docs(planning): bounce plans through external refinement" --phase "${padded_phase}" --files "${PHASE_DIR}/*-PLAN.md"
1374
1392
  ```
1375
1393
 
1376
1394
  Display summary:
@@ -1388,6 +1406,7 @@ After plans pass the checker (or checker is skipped), verify that all phase requ
1388
1406
 
1389
1407
  **Step 1: Extract requirement IDs claimed by plans**
1390
1408
  ```bash
1409
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
1391
1410
  # Collect all requirement IDs from plan frontmatter
1392
1411
  PLAN_REQS=$(grep -h "^requirements_addressed\|^requirements:" ${PHASE_DIR}/*-PLAN.md 2>/dev/null | tr -d '[]' | tr ',' '\n' | sed 's/^[[:space:]]*//' | sort -u)
1393
1412
  ```
@@ -1526,7 +1545,8 @@ This operation is idempotent: if wave headers or cross-cutting constraints alrea
1526
1545
  If `commit_docs` is true (from the init JSON parsed in step 1), commit the generated plan artifacts (including any ROADMAP.md annotations from step 13c):
1527
1546
 
1528
1547
  ```bash
1529
- pp_run query commit "docs(${PADDED_PHASE}): create phase plan" --files "${PHASE_DIR}"/*-PLAN.md .planning/STATE.md .planning/ROADMAP.md
1548
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
1549
+ pp_run query commit "docs(planning): create phase plan" --phase "${PADDED_PHASE}" --files "${PHASE_DIR}"/*-PLAN.md .planning/STATE.md .planning/ROADMAP.md
1530
1550
  ```
1531
1551
 
1532
1552
  This commits all PLAN.md files for the phase plus the updated STATE.md and ROADMAP.md to version-control the planning artifacts. Skip this step if `commit_docs` is false.
@@ -109,6 +109,7 @@ Run plan-phase **inline** (do NOT wrap it in Agent()). The convergence orchestra
109
109
 
110
110
  After plan-phase completes, verify plans were created:
111
111
  ```bash
112
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
112
113
  PLAN_COUNT=$(ls ${phase_dir}/${padded_phase}-*-PLAN.md 2>/dev/null | wc -l)
113
114
  ```
114
115
 
@@ -207,6 +208,7 @@ Run this pass unless `plan_review.source_grounding` is `false`. It verifies ever
207
208
 
208
209
  After agent returns, verify REVIEWS.md exists:
209
210
  ```bash
211
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
210
212
  REVIEWS_FILE=$(ls ${phase_dir}/${padded_phase}-REVIEWS.md 2>/dev/null)
211
213
  ```
212
214
 
@@ -22,6 +22,7 @@ Parse `$ARGUMENTS` for the idea summary.
22
22
  First, check for an enrich flag:
23
23
 
24
24
  ```bash
25
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
25
26
  if echo "$ARGUMENTS" | grep -qE '\-\-enrich[[:space:]]+SEED-[0-9]+'; then
26
27
  ENRICH_TARGET=$(echo "$ARGUMENTS" | grep -oE 'SEED-[0-9]+')
27
28
  SEED_FILE=$(ls .planning/seeds/${ENRICH_TARGET}-*.md 2>/dev/null | head -1)
@@ -52,6 +53,7 @@ mkdir -p .planning/seeds
52
53
 
53
54
  <step name="generate-seed-id">
54
55
  ```bash
56
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
55
57
  # Find next seed number
56
58
  EXISTING=$( (ls .planning/seeds/SEED-*.md 2>/dev/null || true) | wc -l )
57
59
  NEXT=$((EXISTING + 1))
@@ -136,7 +138,7 @@ Store relevant file paths as `$BREADCRUMBS`.
136
138
  <step name="commit-seed">
137
139
  ```bash
138
140
  _PP_SHIM_NAME="pp-tools.cjs"; _pp_root() { ( for _v in $(env | sed -n 's/^\(GIT_[A-Za-z0-9_]*\)=.*/\1/p'); do unset "$_v"; done; _c=$(git rev-parse --git-common-dir 2>/dev/null); if [ "${_c##*/}" = .git ] && cd "$_c/.." 2>/dev/null; then pwd -P; else git rev-parse --show-toplevel 2>/dev/null || pwd; fi ); }; pp_run() { case "$PP_TOOLS" in *.cjs) node "$PP_TOOLS" "$@";; *) "$PP_TOOLS" "$@";; esac; }; _PP_RUNTIME_ROOT="${RUNTIME_DIR:-$(_pp_root)}"; PP_TOOLS="${_PP_RUNTIME_ROOT}/pp-core/bin/${_PP_SHIM_NAME}"; if [ -f "$PP_TOOLS" ]; then :; elif [ -f "${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${_PP_RUNTIME_ROOT}/.codex/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="$HOME/.claude/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${HERMES_HOME:-$HOME/.hermes}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CURSOR_CONFIG_DIR:-$HOME/.cursor}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEX_HOME:-$HOME/.codex}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GEMINI_CONFIG_DIR:-$HOME/.gemini}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${COPILOT_CONFIG_DIR:-$HOME/.copilot}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${WINDSURF_CONFIG_DIR:-$HOME/.codeium/windsurf}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${AUGMENT_CONFIG_DIR:-$HOME/.augment}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${TRAE_CONFIG_DIR:-$HOME/.trae}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${QWEN_CONFIG_DIR:-$HOME/.qwen}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CODEBUDDY_CONFIG_DIR:-$HOME/.codebuddy}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${CLINE_CONFIG_DIR:-$HOME/.cline}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${GROK_AGENTS_HOME:-$HOME/.agents}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${ANTIGRAVITY_CONFIG_DIR:-$HOME/.gemini/antigravity}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${OPENCODE_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/opencode}/pp-core/bin/${_PP_SHIM_NAME}"; elif [ -f "${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}" ]; then PP_TOOLS="${KILO_CONFIG_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/kilo}/pp-core/bin/${_PP_SHIM_NAME}"; elif command -v pp-tools >/dev/null 2>&1; then PP_TOOLS="$(command -v pp-tools)"; else echo "ERROR: pp-tools.cjs not found at $PP_TOOLS and pp-tools is not on PATH. Run: npx -y @pareto4/pp-core@latest --claude --local" >&2; exit 1; fi; if [ -n "${CLAUDE_ENV_FILE:-}" ] && [ -n "${PP_TOOLS:-}" ]; then printf "export PATH='%s':\"\$PATH\"\n" "${PP_TOOLS%/*}" >> "$CLAUDE_ENV_FILE" 2>/dev/null || true; fi
139
- pp_run query commit "docs: plant seed — {$IDEA}" --files .planning/seeds/SEED-{PADDED}-{slug}.md
141
+ pp_run query commit "docs(planning): plant seed — {$IDEA}" --files .planning/seeds/SEED-{PADDED}-{slug}.md
140
142
  ```
141
143
  </step>
142
144
 
@@ -207,7 +209,7 @@ Update the seed file's frontmatter and sections with the gathered values:
207
209
 
208
210
  Commit the update:
209
211
  ```bash
210
- pp_run query commit "docs: enrich seed ${SEED_ID} — trigger + why + scope" --files "$SEED_FILE"
212
+ pp_run query commit "docs(planning): enrich seed ${SEED_ID} — trigger + why + scope" --files "$SEED_FILE"
211
213
  ```
212
214
 
213
215
  Confirm:
@@ -74,6 +74,7 @@ git log --oneline "$TARGET".."$CURRENT_BRANCH" --no-merges
74
74
  For each commit, check what it touches:
75
75
 
76
76
  ```bash
77
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
77
78
  # For each commit hash
78
79
  FILES=$(git diff-tree --no-commit-id --name-only -r $HASH)
79
80
  NON_PLANNING=$(echo "$FILES" | grep -v "^\.planning/" | wc -l)
@@ -107,6 +108,7 @@ git checkout -b "$PR_BRANCH" "$TARGET"
107
108
  Cherry-pick code commits and structural planning commits (in order):
108
109
 
109
110
  ```bash
111
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
110
112
  for HASH in $CODE_AND_STRUCTURAL_COMMITS; do
111
113
  git cherry-pick "$HASH" --no-commit
112
114
  # Remove only transient .planning/ subdirectories that came along in mixed commits.
@@ -227,6 +227,7 @@ Then exit the route step. Do NOT run Steps 1 through Routes A-F.
227
227
  List files in the current phase directory:
228
228
 
229
229
  ```bash
230
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
230
231
  (ls -1 .planning/phases/[current-phase-dir]/*-PLAN.md 2>/dev/null || true) | wc -l
231
232
  (ls -1 .planning/phases/[current-phase-dir]/*-SUMMARY.md 2>/dev/null || true) | wc -l
232
233
  (ls -1 .planning/phases/[current-phase-dir]/*-UAT.md 2>/dev/null || true) | wc -l
@@ -239,6 +240,7 @@ State: "This phase has {X} plans, {Y} summaries."
239
240
  Check for UAT.md files with status "diagnosed" (has gaps needing fixes).
240
241
 
241
242
  ```bash
243
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
242
244
  # Check for diagnosed UAT with gaps or partial (incomplete) testing
243
245
  grep -l "status: diagnosed\|status: partial" .planning/phases/[current-phase-dir]/*-UAT.md 2>/dev/null || true
244
246
  ```
@@ -660,6 +662,7 @@ Read STATE.md `status` / `stopped_at` fields (from the STATE snapshot already lo
660
662
 
661
663
  Check for existence of:
662
664
  ```bash
665
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
663
666
  ls .planning/HANDOFF.json .planning/phases/*/.continue-here.md .planning/phases/*/*HANDOFF*.md 2>/dev/null || true
664
667
  ```
665
668
  Also check `.planning/continue-here.md`.
@@ -685,6 +688,7 @@ Emit:
685
688
 
686
689
  Check if `.planning/MEMORY.md` or `.planning/memory/` exists:
687
690
  ```bash
691
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
688
692
  ls .planning/MEMORY.md .planning/memory/*.md 2>/dev/null || true
689
693
  ```
690
694
 
@@ -698,6 +702,7 @@ Emit:
698
702
 
699
703
  Check for pending todos:
700
704
  ```bash
705
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
701
706
  ls .planning/todos/pending/*.md 2>/dev/null || true
702
707
  ```
703
708
 
@@ -208,6 +208,7 @@ workflow byte-identically to how it ran before this gate existed (GATE-04).
208
208
  **Otherwise, fetch and load-gate at `plan:pre`:**
209
209
 
210
210
  ```bash
211
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
211
212
  QUICK_PLAN_PRE_HOOKS_JSON=$(pp_run loop render-hooks plan:pre --raw | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const j=JSON.parse(d);j.activeHooks=(j.activeHooks||[]).filter((x)=>x&&x.capId==='vault');process.stdout.write(JSON.stringify(j));}catch{process.stdout.write('');}")
212
213
  printf '%s' "$QUICK_PLAN_PRE_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('QUICK_PLAN_PRE_HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
213
214
  ```
@@ -513,6 +514,7 @@ Step 2.4 printed `VAULT_ADMIT=on`. The fence prints the fragments; put that prin
513
514
  the prompt says `${QUICK_PLANNER_HOOK_FRAGMENTS}` (nothing when it printed nothing).
514
515
 
515
516
  ```bash
517
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
516
518
  QUICK_PLANNER_HOOK_FRAGMENTS=$(pp_run loop render-hooks plan:pre --raw | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const j=JSON.parse(d);j.activeHooks=(j.activeHooks||[]).filter((x)=>x&&x.capId==='vault');process.stdout.write(JSON.stringify(j));}catch{process.stdout.write('');}" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const h=(JSON.parse(d).activeHooks||[]).filter((x)=>x&&x.kind==='contribution'&&x.into==='planner'&&x.fragment&&typeof x.fragment.inline==='string');process.stdout.write(h.map((x)=>x.fragment.inline).join('\n\n'));}catch{process.stdout.write('');}")
517
519
  if [ -n "$QUICK_PLANNER_HOOK_FRAGMENTS" ]; then printf '%s\n' "$QUICK_PLANNER_HOOK_FRAGMENTS"; fi
518
520
  ```
@@ -696,6 +698,7 @@ Skip silently unless Step 2.4 printed `VAULT_ADMIT=on`. Runs after the planner (
696
698
  committed and no executor spawned (D-02, D-34).
697
699
 
698
700
  ```bash
701
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
699
702
  QUICK_PLAN_POST_HOOKS_JSON=$(pp_run loop render-hooks plan:post --raw | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const j=JSON.parse(d);j.activeHooks=(j.activeHooks||[]).filter((x)=>x&&x.capId==='vault');process.stdout.write(JSON.stringify(j));}catch{process.stdout.write('');}")
700
703
  printf '%s' "$QUICK_PLAN_POST_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('QUICK_PLAN_POST_HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
701
704
  ```
@@ -731,10 +734,10 @@ if [ "${USE_WORKTREES}" != "false" ]; then
731
734
  # workflow.worktree_skip_hooks=true, honor that opt-in only.
732
735
  SKIP_HOOKS=$(pp_run query config-get workflow.worktree_skip_hooks 2>/dev/null || echo "false")
733
736
  if [ "$SKIP_HOOKS" = "true" ]; then
734
- git commit --no-verify -m "docs(${quick_id}): pre-dispatch plan for ${DESCRIPTION}" -- "${QUICK_DIR}/${quick_id}-PLAN.md" \
737
+ git commit --no-verify -m "docs(planning): pre-dispatch plan for ${DESCRIPTION}" -m "Quick: ${quick_id}" -- "${QUICK_DIR}/${quick_id}-PLAN.md" \
735
738
  || { echo "ERROR: pre-dispatch PLAN.md commit failed (--no-verify path). Aborting before executor dispatch." >&2; exit 1; }
736
739
  else
737
- git commit -m "docs(${quick_id}): pre-dispatch plan for ${DESCRIPTION}" -- "${QUICK_DIR}/${quick_id}-PLAN.md" \
740
+ git commit -m "docs(planning): pre-dispatch plan for ${DESCRIPTION}" -m "Quick: ${quick_id}" -- "${QUICK_DIR}/${quick_id}-PLAN.md" \
738
741
  || { echo "ERROR: pre-dispatch PLAN.md commit failed — likely a pre-commit hook failure. Fix the hook output above (or set workflow.worktree_skip_hooks=true to bypass) and re-run." >&2; exit 1; }
739
742
  fi
740
743
  QUICK_PLAN_COMMIT=$(git rev-parse HEAD)
@@ -771,6 +774,7 @@ Step 2.4 printed `VAULT_ADMIT=on`. The fence prints the fragments; put that prin
771
774
  prompt says `${QUICK_EXECUTOR_HOOK_FRAGMENTS}` (nothing when it printed nothing).
772
775
 
773
776
  ```bash
777
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
774
778
  QUICK_EXECUTOR_HOOK_FRAGMENTS=$(pp_run loop render-hooks execute:pre --raw | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const j=JSON.parse(d);j.activeHooks=(j.activeHooks||[]).filter((x)=>x&&x.capId==='vault');process.stdout.write(JSON.stringify(j));}catch{process.stdout.write('');}" | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const h=(JSON.parse(d).activeHooks||[]).filter((x)=>x&&x.kind==='contribution'&&x.into==='executor'&&x.fragment&&typeof x.fragment.inline==='string');process.stdout.write(h.map((x)=>x.fragment.inline).join('\n\n'));}catch{process.stdout.write('');}")
775
779
  if [ -n "$QUICK_EXECUTOR_HOOK_FRAGMENTS" ]; then printf '%s\n' "$QUICK_EXECUTOR_HOOK_FRAGMENTS"; fi
776
780
  ```
@@ -851,7 +855,7 @@ SUMMARY.md and stop — the user must rerun with worktrees disabled.
851
855
 
852
856
  <constraints>
853
857
  - Execute all tasks in the plan
854
- - Commit each task atomically (code changes only)
858
+ - Commit each task atomically (code changes only); the scope names the part of the codebase (e.g. `fix(auth)`), and each message ends with the trailer `Quick: ${quick_id}` (after a blank line) in place of the `Phase:` trailer
855
859
  - Run the <submodule_commit_guard> bash block before every \`git commit\` if SUBMODULE_PATHS is non-empty
856
860
  - Create summary at: ${QUICK_DIR}/${quick_id}-SUMMARY.md with `status: complete` in SUMMARY frontmatter (required so the audit-open milestone-close scanner recognises the task as done, not [unknown])
857
861
  - Do NOT commit docs artifacts (SUMMARY.md, STATE.md, PLAN.md) — the orchestrator handles the docs commit in Step 8
@@ -872,6 +876,7 @@ If the executor ran with `isolation="worktree"`, append its returned `{agent_id,
872
876
  After executor returns:
873
877
  1. **Worktree cleanup:** If the executor ran with `isolation="worktree"`, merge the worktree branch back and clean up:
874
878
  ```bash
879
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
875
880
  QUICK_WORKTREE_MANIFEST=${QUICK_WORKTREE_MANIFEST:-$WAVE_WORKTREE_MANIFEST}
876
881
  [ -n "${QUICK_WORKTREE_MANIFEST:-}" ] && [ -f "$QUICK_WORKTREE_MANIFEST" ] || {
877
882
  echo "BLOCKED: missing QUICK_WORKTREE_MANIFEST; refusing broad worktree cleanup (#3384)." >&2
@@ -908,6 +913,7 @@ so a blocked task never gets a STATE.md row and never reaches the final commit (
908
913
  the executor already made stay in history, and the SEAL-01 check names them (D-02).
909
914
 
910
915
  ```bash
916
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
911
917
  QUICK_EXECUTE_POST_HOOKS_JSON=$(pp_run loop render-hooks execute:post --raw | node -e "const d=require('fs').readFileSync(0,'utf-8');try{const j=JSON.parse(d);j.activeHooks=(j.activeHooks||[]).filter((x)=>x&&x.capId==='vault');process.stdout.write(JSON.stringify(j));}catch{process.stdout.write('');}")
912
918
  printf '%s' "$QUICK_EXECUTE_POST_HOOKS_JSON" | node -e "let h=[];try{h=JSON.parse(require('fs').readFileSync(0,'utf-8')).activeHooks||[]}catch{}console.log('QUICK_EXECUTE_POST_HOOKS_JSON='+JSON.stringify({activeHooks:h}))"
913
919
  ```
@@ -1093,6 +1099,7 @@ Build file list:
1093
1099
  - If `${QUICK_DIR}/${quick_id}-deferred-items.md` exists: `${QUICK_DIR}/${quick_id}-deferred-items.md`
1094
1100
 
1095
1101
  ```bash
1102
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
1096
1103
  # Explicitly stage all artifacts before commit — PLAN.md may be untracked
1097
1104
  # if the executor ran without worktree isolation and committed docs early
1098
1105
  # Filter .planning/ files from staging if commit_docs is disabled (#1783)
@@ -1103,7 +1110,7 @@ if [ "$COMMIT_DOCS" = "false" ]; then
1103
1110
  else
1104
1111
  git add ${file_list} 2>/dev/null
1105
1112
  fi
1106
- pp_run query commit "docs(quick-${quick_id}): ${DESCRIPTION}" --files ${file_list}
1113
+ pp_run query commit "docs(planning): record quick task — ${DESCRIPTION}" --quick "${quick_id}" --files ${file_list}
1107
1114
  ```
1108
1115
 
1109
1116
  Get final commit hash:
@@ -13,6 +13,7 @@ After a pp-core update wipes and reinstalls files, this workflow merges user's p
13
13
  Check for local patches directory:
14
14
 
15
15
  ```bash
16
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
16
17
  expand_home() {
17
18
  case "$1" in
18
19
  "~/"*) printf '%s/%s\n' "$HOME" "${1#~/}" ;;
@@ -278,6 +279,7 @@ Run the deterministic verifier script. Do NOT rely solely on the free-text `veri
278
279
  Run the verifier as a child process (the pp-tools binary directory is not required — the script ships under 'pp-core/bin/' in the source repo and is installed to '/pp-core/bin/'; it is also exposed via the SDK at `sdk/dist/cli.js verify-reapply` when present):
279
280
 
280
281
  ```bash
282
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
281
283
  PRISTINE_DIR="${CONFIG_DIR}/pp-pristine"
282
284
 
283
285
  # Build args as a bash array so paths with spaces survive expansion intact
@@ -302,6 +304,7 @@ VERIFY_STATUS=$?
302
304
  **Step 5a: drift check** — even when `VERIFY_STATUS` is 0, the report may signal that one or more files were skipped due to pristine-snapshot drift (Bug #3657) or a missing baseline (Bug #934). Parse the JSON and check:
303
305
 
304
306
  ```bash
307
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
305
308
  DRIFTED_COUNT="$(echo "$VERIFY_OUTPUT" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));process.stdout.write(String(d.drifted||0))")"
306
309
  DRIFTED_FILES="$(echo "$VERIFY_OUTPUT" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));(d.drifted_files||[]).forEach(f=>process.stdout.write(f+'\n'))")"
307
310
  NO_BASELINE_COUNT="$(echo "$VERIFY_OUTPUT" | node -e "const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));process.stdout.write(String(d.no_baseline||0))")"
@@ -104,7 +104,7 @@ Extract from result: `removed`, `directory_deleted`, `renamed_directories`, `ren
104
104
  Stage and commit the removal:
105
105
 
106
106
  ```bash
107
- pp_run query commit "chore: remove phase {target} ({original-phase-name})" --files .planning/
107
+ pp_run query commit "chore(planning): remove phase {target} ({original-phase-name})" --files .planning/
108
108
  ```
109
109
 
110
110
  The commit message preserves the historical record of what was removed.
@@ -68,6 +68,7 @@ cat .planning/PROJECT.md
68
68
  Look for incomplete work that needs attention:
69
69
 
70
70
  ```bash
71
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
71
72
  # Check for structured handoff (preferred — machine-readable)
72
73
  cat .planning/HANDOFF.json 2>/dev/null || true
73
74
 
@@ -244,6 +245,7 @@ What would you like to do?
244
245
  **Note:** When offering phase planning, check for CONTEXT.md existence first:
245
246
 
246
247
  ```bash
248
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
247
249
  ls .planning/phases/XX-name/*-CONTEXT.md 2>/dev/null || true
248
250
  ```
249
251
 
@@ -297,6 +299,7 @@ Resume-specific exception: do **not** emit `/clear then:` here. Resume is alread
297
299
  Before proceeding to routed workflow, record session continuity through the state verb, never by hand (a hand edit leaves the stored `stopped_at` behind, so `state json` and `state-snapshot` keep the older value):
298
300
 
299
301
  ```bash
302
+ [ -z "${ZSH_VERSION:-}" ] || emulate -R sh
300
303
  pp_run query state.record-session --stopped-at "Session resumed, proceeding to [action]" ${GSD_WS}
301
304
  ```
302
305