@pareto4/pp-core 1.22.0 → 1.23.1

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 (119) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/bin/install.js +205 -28
  3. package/commands/pp-help.md +2 -1
  4. package/gemini-extension.json +1 -1
  5. package/hooks/dist/pp-check-update-worker.js +1 -1
  6. package/hooks/dist/pp-context-monitor.js +3 -3
  7. package/hooks/dist/pp-statusline.js +88 -14
  8. package/hooks/dist/pp-update-banner.js +44 -4
  9. package/hooks/dist/pp-workflow-guard.js +3 -3
  10. package/hooks/pp-check-update-worker.js +1 -1
  11. package/hooks/pp-context-monitor.js +3 -3
  12. package/hooks/pp-statusline.js +88 -14
  13. package/hooks/pp-update-banner.js +44 -4
  14. package/hooks/pp-workflow-guard.js +3 -3
  15. package/package.json +1 -1
  16. package/pp-core/bin/lib/audience-command.cjs +271 -0
  17. package/pp-core/bin/lib/audience.cjs +293 -0
  18. package/pp-core/bin/lib/commands.cjs +26 -17
  19. package/pp-core/bin/lib/discovery-charter.cjs +13 -1
  20. package/pp-core/bin/lib/discovery-input-check.cjs +11 -11
  21. package/pp-core/bin/lib/discovery-session-check.cjs +7 -7
  22. package/pp-core/bin/lib/discovery-status.cjs +419 -0
  23. package/pp-core/bin/lib/explain-command.cjs +48 -0
  24. package/pp-core/bin/lib/gate-card.cjs +97 -0
  25. package/pp-core/bin/lib/hook-messages.cjs +132 -0
  26. package/pp-core/bin/lib/init-contract.cjs +116 -76
  27. package/pp-core/bin/lib/init-interactive.cjs +110 -49
  28. package/pp-core/bin/lib/init.cjs +44 -3
  29. package/pp-core/bin/lib/io.cjs +33 -0
  30. package/pp-core/bin/lib/message-labels.cjs +75 -0
  31. package/pp-core/bin/lib/messages/core.cjs +20 -0
  32. package/pp-core/bin/lib/messages/discovery.cjs +267 -0
  33. package/pp-core/bin/lib/messages/gate.cjs +257 -0
  34. package/pp-core/bin/lib/messages/hook.cjs +114 -0
  35. package/pp-core/bin/lib/messages/init.cjs +513 -0
  36. package/pp-core/bin/lib/messages/progress.cjs +110 -0
  37. package/pp-core/bin/lib/messages.cjs +208 -0
  38. package/pp-core/bin/lib/vault-command-router.cjs +16 -3
  39. package/pp-core/bin/lib/violation-render.cjs +78 -0
  40. package/pp-core/bin/pp-tools.cjs +68 -23
  41. package/pp-core/bin/shared/config-schema.manifest.json +1 -0
  42. package/pp-core/references/audience-moments.md +119 -0
  43. package/pp-core/references/audience.md +114 -0
  44. package/pp-core/references/discovery-charter.md +2 -2
  45. package/pp-core/templates/project-charter.md +3 -4
  46. package/pp-core/workflows/add-phase.md +2 -0
  47. package/pp-core/workflows/add-tests.md +2 -0
  48. package/pp-core/workflows/add-todo.md +2 -0
  49. package/pp-core/workflows/ai-integration-phase.md +2 -0
  50. package/pp-core/workflows/audit-milestone.md +2 -0
  51. package/pp-core/workflows/autonomous.md +2 -0
  52. package/pp-core/workflows/check-todos.md +2 -0
  53. package/pp-core/workflows/code-review-fix.md +2 -0
  54. package/pp-core/workflows/code-review.md +2 -0
  55. package/pp-core/workflows/complete-milestone.md +10 -1
  56. package/pp-core/workflows/discovery-sprint/charter.md +3 -2
  57. package/pp-core/workflows/discovery-sprint/prefill.md +3 -0
  58. package/pp-core/workflows/discovery-sprint/prototype.md +14 -0
  59. package/pp-core/workflows/discovery-sprint/sessions/01-kick-off.md +4 -1
  60. package/pp-core/workflows/discovery-sprint/sessions/13-wrap-up.md +1 -1
  61. package/pp-core/workflows/discovery-sprint/vault-context.md +15 -0
  62. package/pp-core/workflows/discovery-sprint.md +14 -0
  63. package/pp-core/workflows/discovery-to-build.md +8 -2
  64. package/pp-core/workflows/discuss-phase-assumptions.md +2 -0
  65. package/pp-core/workflows/discuss-phase.md +1 -1
  66. package/pp-core/workflows/edit-phase.md +2 -0
  67. package/pp-core/workflows/eval-review.md +2 -0
  68. package/pp-core/workflows/execute-phase/steps/check-query-gate.md +25 -1
  69. package/pp-core/workflows/execute-phase/steps/vault-fetch.md +1 -0
  70. package/pp-core/workflows/execute-phase/steps/vault-load-gate.md +2 -0
  71. package/pp-core/workflows/execute-phase.md +1 -1
  72. package/pp-core/workflows/execute-plan.md +2 -0
  73. package/pp-core/workflows/extract-learnings.md +2 -0
  74. package/pp-core/workflows/help/modes/business.md +56 -0
  75. package/pp-core/workflows/help.md +12 -2
  76. package/pp-core/workflows/import.md +10 -1
  77. package/pp-core/workflows/ingest-docs.md +2 -0
  78. package/pp-core/workflows/init.md +17 -1
  79. package/pp-core/workflows/insert-phase.md +2 -0
  80. package/pp-core/workflows/list-workspaces.md +2 -0
  81. package/pp-core/workflows/manager.md +2 -0
  82. package/pp-core/workflows/map-codebase.md +2 -0
  83. package/pp-core/workflows/milestone-summary.md +2 -0
  84. package/pp-core/workflows/new-milestone.md +10 -1
  85. package/pp-core/workflows/new-project.md +12 -2
  86. package/pp-core/workflows/new-workspace.md +2 -0
  87. package/pp-core/workflows/next.md +8 -0
  88. package/pp-core/workflows/plan-milestone-gaps.md +10 -1
  89. package/pp-core/workflows/plan-phase.md +2 -1
  90. package/pp-core/workflows/plan-review-convergence.md +1 -1
  91. package/pp-core/workflows/progress.md +10 -0
  92. package/pp-core/workflows/quick.md +11 -1
  93. package/pp-core/workflows/remove-phase.md +2 -0
  94. package/pp-core/workflows/remove-workspace.md +2 -0
  95. package/pp-core/workflows/resume-project.md +25 -0
  96. package/pp-core/workflows/review.md +2 -0
  97. package/pp-core/workflows/scan.md +2 -0
  98. package/pp-core/workflows/secure-phase.md +2 -0
  99. package/pp-core/workflows/settings.md +41 -0
  100. package/pp-core/workflows/ship.md +2 -0
  101. package/pp-core/workflows/spec-phase.md +1 -1
  102. package/pp-core/workflows/ui-phase.md +2 -0
  103. package/pp-core/workflows/ui-review.md +2 -0
  104. package/pp-core/workflows/ultraplan-phase.md +2 -0
  105. package/pp-core/workflows/validate-phase.md +2 -0
  106. package/pp-core/workflows/vault-review.md +2 -0
  107. package/pp-core/workflows/verify-phase.md +2 -0
  108. package/pp-core/workflows/verify-work.md +2 -0
  109. package/scripts/affected-tests-lib.cjs +26 -12
  110. package/scripts/ci-release-only.cjs +158 -0
  111. package/scripts/live-runs/driver.cjs +326 -0
  112. package/scripts/live-runs/run.cjs +906 -0
  113. package/scripts/live-runs/scenarios.cjs +326 -0
  114. package/scripts/live-runs/scratch-project.cjs +132 -0
  115. package/scripts/live-runs/scrub.cjs +291 -0
  116. package/scripts/live-runs/turn-guard.cjs +107 -0
  117. package/scripts/live-runs/walk-setup.cjs +198 -0
  118. package/scripts/run-tests.cjs +151 -135
  119. package/scripts/test-env.cjs +64 -0
@@ -0,0 +1,114 @@
1
+ # Audience reference
2
+
3
+ How pp-core talks to business users and business engineers. Tables below are parsed by `tests/jargon-denylist.test.cjs`; this file is the only copy of these lists.
4
+
5
+ ## When to read this
6
+
7
+ Read this file only when the `init.*` payload carries `audience` (`business` or `engineer`). The workflow's pointer line sends you here with a Read, never an `@`-include, so a developer run never loads it.
8
+
9
+ Follow the section for that audience in every message the person sees. That includes what a subagent returned: agents' own prompts stay as they are, and you reword their results when you pass them on. Reply in `response_language`. Keep everything on the Never reword list exactly as written.
10
+
11
+ At five moments, also Read `audience-moments.md` in this folder and use its form for this audience: a Next Up block, a stopped check, a verification result, the vault fallback question and a confirmation before an irreversible action. In a discovery session, follow its Discovery narration rule as well.
12
+
13
+ ## Business users
14
+
15
+ Write for someone who runs the work and decides, but does not read code.
16
+
17
+ - Short sentences. Everyday words. Say what happened, then what to do.
18
+ - Name a thing plus its number: "decision 3", "screen 7", "requirement 4". Never a bare code.
19
+ - Use the Business user column of the glossary for every internal word. Never show anything on the hide list.
20
+ - Keep the words sprint and MVP as they are.
21
+ - Steer away from version-control topics. Do not explain saving, sharing or reviewing code; say pp-core takes care of it.
22
+ - Leave out how files work inside, such as front matter or a change's hash. Say what the file or change is for.
23
+ - Show commands, file names, paths and IDs in backticks, unchanged, next to a plain description.
24
+ - When something fails, use two short sentences: what happened, what to do next.
25
+
26
+ ## Business engineers
27
+
28
+ Plain English. The person knows the technology.
29
+
30
+ - Real external terms stay as they are. Explain each once, the first time it comes up in a conversation, with its line from the Explain once table. Never replace one.
31
+ - pp-core's own words use the Business engineer column of the glossary.
32
+ - Keep a code next to its meaning: "decision D-03: use one database".
33
+ - Never show a term the hide list marks both. Terms marked business are hidden from business users only.
34
+ - Say what happened, what it means, what to do next.
35
+
36
+ ## Glossary
37
+
38
+ `(hide)` means the term is also on the hide list for that audience. `(keep)` means the word stays as it is.
39
+
40
+ | Internal term | Business user | Business engineer |
41
+ |---|---|---|
42
+ | vault | your organisation's standards | standards vault (the client's coding standards) |
43
+ | milestone | release | milestone (one release) |
44
+ | phase | stage of the work | phase |
45
+ | wave | (hide) | build round |
46
+ | worktree | (hide) | (hide) |
47
+ | agent, subagent, spawn, orchestrator | (hide) | (hide) |
48
+ | gate | the {name} check | the {name} check |
49
+ | checkpoint | needs you | needs you (check, choose or do) |
50
+ | must-haves, must_haves, truths | what must be true when this is done | required outcomes |
51
+ | gaps_found | not finished yet | missing outcome |
52
+ | verify-work | your acceptance test | UAT (you try the feature yourself) |
53
+ | drift | out of date | out of date |
54
+ | binding | platform connection | platform connection |
55
+ | slug | short name | short name (URL-safe) |
56
+ | Nyquist, Dimension 8 | (hide) | test coverage plan |
57
+ | threat model | security risks | security risks |
58
+ | model profile | (hide) | quality and cost level |
59
+ | YOLO | run on its own | run automatically |
60
+ | deviation | change from the standard | change from the plan |
61
+ | accession | document number | document number |
62
+ | artifact | document | document or output |
63
+ | entity | core data | (keep) |
64
+ | register | list | (keep) |
65
+ | persona | user profile | (keep) |
66
+ | Pre-Filled | prepared from your documents | pre-filled from documents |
67
+
68
+ ## Hide list
69
+
70
+ | Term | Hidden from |
71
+ |---|---|
72
+ | wave | business |
73
+ | worktree | both |
74
+ | agent | both |
75
+ | subagent | both |
76
+ | spawn | both |
77
+ | orchestrator | both |
78
+ | Nyquist | business |
79
+ | Dimension 8 | business |
80
+ | model profile | business |
81
+ | `.planning` | both |
82
+ | `pp_run` | both |
83
+ | Mermaid | business |
84
+
85
+ A hidden thing is not shown. If it must be shown, show it unchanged in backticks.
86
+
87
+ ## Never reword
88
+
89
+ | Kind | Examples |
90
+ |---|---|
91
+ | IDs | `D-03`, `REACH-01`, `03-02` |
92
+ | File names | `ROADMAP.md`, `session-04.md` |
93
+ | Commands | `/pp-discovery 4`, `/pp-plan-phase 3` |
94
+ | Paths | `docs/discovery/PROJECT-CHARTER.md` |
95
+ | Config keys | `workflow.research` |
96
+
97
+ ## Explain once
98
+
99
+ | Term | Aliases | One-line explanation |
100
+ |---|---|---|
101
+ | branch | — | A named line of work, kept apart from the main one until it is ready. |
102
+ | commit | — | A saved set of changes with a short note about why. |
103
+ | pull request | PR, MR, merge request | A request for others to review changes before they join the main line. |
104
+ | merge | — | Bringing the changes from one line of work into another. |
105
+ | repository | repo | The folder of project files together with its full history. |
106
+ | push | — | Sending saved changes to the shared copy of the repository. |
107
+ | SHA | commit hash, sha | The unique code that names one commit. |
108
+ | front matter | frontmatter | The settings block at the top of a document, between two `---` lines. |
109
+ | CI | continuous integration | Automatic checks that run on every change. |
110
+ | TDD | test-driven development, test-first | Writing the test first, then the code that makes it pass. |
111
+ | UAT | user acceptance test | You try the feature yourself and say whether it does what you need. |
112
+ | NFR | non-functional requirement | A quality the system must have, such as speed or security. |
113
+ | MoSCoW | — | Sorting requirements into must, should, could and won't have now. |
114
+ | ASVS | — | A security checklist with three levels of depth. |
@@ -63,7 +63,7 @@ Column order is fixed; column headings may be translated.
63
63
 
64
64
  1. Session 1 § Sprint Logistics, row **Charter language** — a BCP-47 code (`nl`, `en`, `nl-BE`).
65
65
  2. Else `discovery.language` in `.planning/config.json` (`pp_run query config-get discovery.language --default "" --raw`).
66
- 3. Else the language the sprint was facilitated in (Flow 2 Step 5's rule).
66
+ 3. Else English (`en`). A Dutch conversation does not make the charter Dutch; only rung 1 or 2 does.
67
67
 
68
68
  The resolved code is written to the frontmatter `language` field. `und` is the template's placeholder
69
69
  and is replaced at draft time.
@@ -100,7 +100,7 @@ fault code emitted; a rule that is **not** mechanically checked says so.
100
100
  | `_requirements.md` present but unparseable | the rollup grammar is owned by `discovery rollup` | `requirements_unparseable`, once — run `discovery rollup --check` for the detail; requirement IDs and counts are then not resolved |
101
101
  | any source under `.planning/discovery/` that exists but cannot be read | present-and-readable | `artifact_unreadable` naming the path — an unreadable source is a fault, never a silent skip |
102
102
  | `--require-signed` | `status` is `Signed` or `Signed with conditions` | `charter_unsigned`; when it is the only fault the exit identity is `discovery_charter_unsigned`, so the handoff can tell "unsigned" from "malformed" |
103
- | prose, table cells other than IDs and enums | free text in the sprint language | **not mechanically checked** — never validated, never echoed |
103
+ | prose, table cells other than IDs and enums | free text in the charter language | **not mechanically checked** — never validated, never echoed |
104
104
 
105
105
  **Posture (D-43 / D-53).** At Session 13 the check reports: an unsigned charter is not a fault, and a
106
106
  `Draft` with `Pending` is the expected state before topic 3. The hard block lives at
@@ -20,9 +20,8 @@ table columns. A section with nothing to report stays in place and says so; it i
20
20
  or renumbered. That is what lets a reader compare two charters side by side, and what lets
21
21
  `pp_run query discovery.charter-check` verify one.
22
22
 
23
- **Language.** The charter is written in the sprint language — the `Charter language` row of Session 1's
24
- Sprint Logistics, else `discovery.language` in `.planning/config.json`, else the language the sprint
25
- was facilitated in. Headings, labels and prose are translated; the `<!-- charter:<key> -->` heading
23
+ **Language.** The charter is written in the charter language — the `Charter language` row of Session 1's
24
+ Sprint Logistics, else `discovery.language` in `.planning/config.json`, else English. Headings, labels and prose are translated; the `<!-- charter:<key> -->` heading
26
25
  keys, the frontmatter fields and every enum cell (`status`, `go_no_go`, `Green / Amber / Red`,
27
26
  `Approve / Approve with conditions / Reject`, `Yes / No`) stay in English, because the check reads them.
28
27
  Column order is fixed; column headings may be translated.
@@ -273,7 +272,7 @@ source of truth; the charter only condenses them.
273
272
  Aim for a charter that reads in about fifteen minutes.
274
273
  - **Fixed shape.** Keep all 20 sections, their keys, their order and their table columns. An empty table
275
274
  stays in place with no rows, and the section's prose says `None identified in Discovery.` (in the
276
- sprint language). The **Source files** footer names only the files that exist in this engagement.
275
+ charter language). The **Source files** footer names only the files that exist in this engagement.
277
276
  - **Go / No-Go is recorded, not re-judged.** § 17 copies Session 13's assessment verbatim and the
278
277
  frontmatter `go_no_go` equals its overall recommendation; `Pending` is allowed only while `status`
279
278
  is `Draft`.
@@ -34,6 +34,8 @@ INIT=$(pp_run query init.phase-op "0")
34
34
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
35
35
  ```
36
36
 
37
+ **Audience:** if `audience` is set, Read and follow `{audience_ref}`. Reply in any `response_language` and pass it to subagents; code and paths stay as is.
38
+
37
39
  Check `roadmap_exists` from init JSON. If false:
38
40
  ```
39
41
  ERROR: No roadmap found (.planning/ROADMAP.md)
@@ -38,6 +38,8 @@ INIT=$(pp_run query init.phase-op "${PHASE_ARG}")
38
38
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
39
39
  ```
40
40
 
41
+ **Audience:** if `audience` is set, Read and follow `{audience_ref}`. Reply in any `response_language` and pass it to subagents; code and paths stay as is.
42
+
41
43
  Extract from init JSON: `phase_dir`, `phase_number`, `phase_name`.
42
44
 
43
45
  Verify the phase directory exists. If not:
@@ -17,6 +17,8 @@ INIT=$(pp_run query init.todos)
17
17
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
18
18
  ```
19
19
 
20
+ **Audience:** if `audience` is set, Read and follow `{audience_ref}`. Reply in any `response_language` and pass it to subagents; code and paths stay as is.
21
+
20
22
  Extract from init JSON: `commit_docs`, `date`, `timestamp`, `todo_count`, `todos`, `pending_dir`, `todos_dir_exists`.
21
23
 
22
24
  Ensure directories exist:
@@ -25,6 +25,8 @@ INIT=$(pp_run query init.plan-phase "$PHASE")
25
25
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
26
26
  ```
27
27
 
28
+ **Audience:** if `audience` is set, Read and follow `{audience_ref}`. Reply in any `response_language` and pass it to subagents; code and paths stay as is.
29
+
28
30
  Parse JSON for: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `has_context`, `has_research`, `commit_docs`.
29
31
 
30
32
  **File paths:** `state_path`, `roadmap_path`, `requirements_path`, `context_path`.
@@ -22,6 +22,8 @@ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
22
22
  AGENT_SKILLS_CHECKER=$(pp_run query agent-skills pp-integration-checker)
23
23
  ```
24
24
 
25
+ **Audience:** if `audience` is set, Read and follow `{audience_ref}`. Reply in any `response_language` and pass it to subagents; code and paths stay as is.
26
+
25
27
  Extract from init JSON: `milestone_version`, `milestone_name`, `phase_count`, `completed_phases`, `commit_docs`.
26
28
 
27
29
  Resolve integration checker model:
@@ -81,6 +81,8 @@ INIT=$(pp_run query init.milestone-op)
81
81
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
82
82
  ```
83
83
 
84
+ **Audience:** if `audience` is set, Read and follow `{audience_ref}`. Reply in any `response_language` and pass it to subagents; code and paths stay as is.
85
+
84
86
  If `PLAN_STRATEGY` is `converge`, fail fast unless the existing convergence feature gate is enabled:
85
87
 
86
88
  ```bash
@@ -17,6 +17,8 @@ INIT=$(pp_run query init.todos)
17
17
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
18
18
  ```
19
19
 
20
+ **Audience:** if `audience` is set, Read and follow `{audience_ref}`. Reply in any `response_language` and pass it to subagents; code and paths stay as is.
21
+
20
22
  Extract from init JSON: `todo_count`, `todos`, `pending_dir`.
21
23
 
22
24
  If `todo_count` is 0:
@@ -25,6 +25,8 @@ AGENT_SKILLS_FIXER=$(pp_run query agent-skills pp-code-fixer)
25
25
  AGENT_SKILLS_REVIEWER=$(pp_run query agent-skills pp-code-reviewer)
26
26
  ```
27
27
 
28
+ **Audience:** if `audience` is set, Read and follow `{audience_ref}`. Reply in any `response_language` and pass it to subagents; code and paths stay as is.
29
+
28
30
  Parse from init JSON: `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `padded_phase`, `commit_docs`.
29
31
 
30
32
  **Input sanitization (defense-in-depth):**
@@ -27,6 +27,8 @@ AGENT_SKILLS_REVIEWER=$(pp_run query agent-skills pp-code-reviewer)
27
27
  echo "pp-core engine: ${PP_TOOLS} (VERSION: $(cat "${PP_TOOLS%/bin/*}/VERSION" 2>/dev/null || echo 'no VERSION file - running from a source tree'))"
28
28
  ```
29
29
 
30
+ **Audience:** if `audience` is set, Read and follow `{audience_ref}`. Reply in any `response_language` and pass it to subagents; code and paths stay as is.
31
+
30
32
  Parse from init JSON: `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `padded_phase`, `commit_docs`.
31
33
 
32
34
  **Input sanitization (defense-in-depth):**
@@ -41,11 +41,17 @@ When a milestone completes:
41
41
 
42
42
  <process>
43
43
 
44
+ ```bash
45
+ _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
46
+ pp_run query audience fields
47
+ ```
48
+
49
+ **Audience, before any question:** run the block above. If it prints `pp-tools.cjs not found`, show that error and stop. If it exits non-zero for any other reason, tell the person the audience setting could not be read (show the error) and continue; if it prints JSON, apply the **Audience** line below to it now.
50
+
44
51
  <step name="pre_close_artifact_audit">
45
52
  Before proceeding with milestone close, run the comprehensive open artifact audit.
46
53
 
47
54
  ```bash
48
- _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
49
55
  pp_run query audit-open
50
56
  ```
51
57
 
@@ -590,10 +596,13 @@ Check branching strategy and offer merge options.
590
596
  Use `init milestone-op` for context, or load config directly:
591
597
 
592
598
  ```bash
599
+ command -v pp_run >/dev/null 2>&1 || { echo "ERROR: pp_run is not on PATH; prepend the resolver line from the top block to this block and run it again" >&2; exit 1; }
593
600
  INIT=$(pp_run query init.execute-phase "1")
594
601
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
595
602
  ```
596
603
 
604
+ **Audience:** if `audience` is set, Read and follow `{audience_ref}`. Reply in any `response_language` and pass it to subagents; code and paths stay as is.
605
+
597
606
  Extract `branching_strategy`, `phase_branch_template`, `milestone_branch_template`, and `commit_docs` from init JSON.
598
607
 
599
608
  Detect base branch:
@@ -20,7 +20,7 @@ Resolve once, record in the frontmatter `language` field:
20
20
 
21
21
  1. Session 1 § Sprint Logistics, row **Charter language** (a BCP-47 code: `nl`, `en`, `nl-BE`).
22
22
  2. Else `pp_run query config-get discovery.language --default "" --raw`.
23
- 3. Else the language the sprint was facilitated in (Flow 2 Step 5).
23
+ 3. Else English (`en`). A Dutch conversation does not make the charter Dutch; only rung 1 or 2 does.
24
24
 
25
25
  Render headings, labels and prose in that language — the reference carries the English and Dutch
26
26
  headings; translate others yourself. Never translate the `<!-- charter:<key> -->` comments, the
@@ -49,7 +49,7 @@ Runs after the cross-reference (Step 0f) and before the topics, so topic 2 revie
49
49
  record them — and fill § 16 with what is already known: `⚠️ CONDITIONAL` sections (from each
50
50
  session's `conditional:` frontmatter), open `Gates-MVP` rows of `_research.md`, and every
51
51
  `Dropped (D-ss-n)` requirement. A section with nothing to report keeps its empty table and says
52
- `None identified in Discovery.` in the sprint language. **Redo of Session 13:** when `session-13.md`
52
+ `None identified in Discovery.` in the charter language. **Redo of Session 13:** when `session-13.md`
53
53
  already carries a filled Go / No-Go Assessment and Open Items Register from an earlier run, copy them
54
54
  now as § Finish steps 1–2 describe — the check compares against them once the overall cell is
55
55
  filled, and an empty § 17 would then be a fault, not a draft.
@@ -112,3 +112,4 @@ are renderings, regenerated every time the markdown changes and never edited by
112
112
  use the name it lists.
113
113
  2. When a skill is not installed, say so once, write `export: skipped (<skill> unavailable)` into the
114
114
  Change cell of the current § 20 row, and continue. A missing renderer never blocks the sprint.
115
+ 3. **What the rendering shows (every audience, D-13).** The .docx and .pdf differ from the markdown in three places, at render time only: the requirement counts line (the one carrying `<!-- charter:counts -->`) is written in words — "<n> <area> requirements" per registered prefix, using the area names from the prefix registry, then "<n> dropped" — never the prefix codes; the `**Source files:**` footer is left out; every open item ID `OI-<n>` is written "open item <n>". The markdown keeps all three as they are, because `charter-check` reads them; never edit the markdown to match the rendering.
@@ -93,6 +93,9 @@ Offer to pre-fill the next session mapped in the README (`AskUserQuestion`;
93
93
  **text mode fallback:** numbered list — 1) Pre-fill session M next / 2) Done
94
94
  for now). When done, tell the user that each pre-filled session is run live
95
95
  later as a confirmation walk (`/pp-discovery N`), and stop.
96
+ For a business user (D-14), close with this instead:
97
+
98
+ Business form: "I prepared session {N} from your documents. It still needs you: type `/pp-discovery {N}` and we will go through the answers together."
96
99
 
97
100
  Before drafting session M, re-enter § 4 of `vault-context.md` with `SESSION_ARG`
98
101
  set to M — the guards, the fetch and the gate already ran once for this
@@ -253,3 +253,17 @@ Gaps: <untagged elements / styling gaps, or "none">
253
253
  Next recommended session: Session 5 — Application & Integration Architecture
254
254
  Run /pp-discovery 5 to continue.
255
255
  ```
256
+
257
+ For a business user (D-14), show this instead — no paths and no element counts:
258
+
259
+ Business form:
260
+
261
+ ```
262
+ Prototype — round <k> done
263
+
264
+ Built: <n> screens and <m> clickable flows
265
+ On screen: <r> of the <t> planned requirements (<x> not yet)
266
+ Your feedback: <y> changes to requirements, <z> screen decisions
267
+
268
+ Next: session 5, how the application connects to other systems. Type /pp-discovery 5 to continue.
269
+ ```
@@ -52,6 +52,9 @@
52
52
  - Propose a prefix set derived from the stakeholder domains just mapped in topic 3: one prefix per stakeholder domain, plus `N-` (non-functional) and `T-` (technical) defaults; the user confirms or adjusts (D-09)
53
53
  - Create `.planning/discovery/_requirements.md` from the bootstrap template in the pp-core reference `references/discovery-id-conventions.md` — locate it under the installed pp-core root (`${PP_TOOLS%/bin/pp-tools.cjs}/references/discovery-id-conventions.md`) and Read it lazily; never `@`-import it. Fill the Prefix Registry header table with the confirmed set (the registry and the requirements table travel in one file — D-10)
54
54
  - Never register a reserved prefix: the proposed set must not include `D-`, `A-`, `SP-`, `DG-`, `RS-`, `SCR-`, `PRC-`, `MP-`, `BR-`, `IF-`, `MG-` or `DEV-` — they are owned by other ID families, and a row claiming one makes `discovery rollup --check` report `reserved_prefix` (D-44). Avoid the session-table row prefixes that reference lists too (`C-`, `R-`, `E-`, …), so a citation never reads two ways
55
+ - For a business user (`audience` is `business`, D-14): choose the prefix set yourself from topic 3's stakeholder domains plus the two defaults and check it against the reserved list above without showing that list, the check command or its code. Ask only:
56
+ Business form: "I will number the requirements by area: {areas}, plus quality needs and technical needs. Does that split work for you?"
57
+ Record the confirmed set exactly as the bullets above say.
55
58
  - Decisions are cited inline as `D-<ss>-<n>` per that same reference; record the chosen prefix set as a Key Decisions row in the Session 1 notes
56
59
 
57
60
  8. **Approval routes**
@@ -92,7 +95,7 @@ The business problem or opportunity, what was tried before and with what result,
92
95
  | Decision recording and communication | |
93
96
  | Charter language | |
94
97
 
95
- **Charter language** is a BCP-47 code (`nl`, `en`, `nl-BE`): the Project Charter Session 13 drafts is rendered in it (`references/discovery-charter.md` § Language resolution). Leave it empty to fall back to `discovery.language` in `.planning/config.json`, else the facilitation language.
98
+ **Charter language** is a BCP-47 code (`nl`, `en`, `nl-BE`): the Project Charter Session 13 drafts is rendered in it (`references/discovery-charter.md` § Language resolution). Leave it empty to fall back to `discovery.language` in `.planning/config.json`, else English.
96
99
 
97
100
  **Working Agreement**
98
101
 
@@ -216,6 +216,6 @@ Capture in `.planning/discovery/session-13.md` notes:
216
216
 
217
217
  #### 0.5. Draft the Project Charter
218
218
 
219
- Read `${PP_TOOLS%/bin/pp-tools.cjs}/workflows/discovery-sprint/charter.md` § **Draft** and follow it: the charter is written to `docs/discovery/PROJECT-CHARTER.md` from `templates/project-charter.md`, in the sprint language, every section from its source map, `status: Draft`, and `pp_run query discovery.charter-check` exits 0 before you go on. Topics 2 and 3 review and score that document, not a summary of the sessions.
219
+ Read `${PP_TOOLS%/bin/pp-tools.cjs}/workflows/discovery-sprint/charter.md` § **Draft** and follow it: the charter is written to `docs/discovery/PROJECT-CHARTER.md` from `templates/project-charter.md`, in the charter language, every section from its source map, `status: Draft`, and `pp_run query discovery.charter-check` exits 0 before you go on. Topics 2 and 3 review and score that document, not a summary of the sessions.
220
220
 
221
221
  Then proceed to Step 5 (Facilitate Session 13 topics).
@@ -89,6 +89,21 @@ These documents are the binding engineering standards for this work: build to th
89
89
  Paraphrase at point of use with a `[vault: <rel path>]` citation. Never inline raw vault content
90
90
  into the session notes.
91
91
 
92
+ **Business user (D-14).** When `audience` is `business`, print none of the `vault:` lines this file names. Once the selection is done, say one of these instead, and hand the record back unchanged:
93
+
94
+ Business form: "I have your organisation's standards for this session at hand."
95
+
96
+ Business form: "Your organisation's standards add nothing for this session."
97
+
98
+ Business form: "I could not load your organisation's standards for this session, so I am working without them. Ask your Pareto contact if they should be here."
99
+
100
+ Business form: "I could not check some of your organisation's standards for this session, so I am working without those. Ask your Pareto contact if they should be here."
101
+
102
+ Use the second only when the index was read and nothing in it bore on this session. Use the third
103
+ when there is no cache index (the stop arm below): the standards were not consulted, so never say
104
+ they add nothing. Use the fourth, after the first or on its own, when a selected document was not
105
+ read because the cache index is truncated or the document is not in the cache.
106
+
92
107
  **Read order.** Read `.planning/vault/SUMMARY.md` first. It is the engine-written bounded index —
93
108
  each cached path with its first heading, not full vault content — and it is what tells you which
94
109
  documents actually exist in this client's cache.
@@ -37,10 +37,14 @@ INIT=$(pp_run query init.phase-op "${SESSION_ARG:-}")
37
37
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
38
38
  ```
39
39
 
40
+ **Audience:** if `audience` is set, Read and follow `{audience_ref}`. Reply in any `response_language` and pass it to subagents; code and paths stay as is.
41
+
40
42
  `SESSION_ARG` is the optional session number 1–13, extracted from `$ARGUMENTS` in the block above (empty when no argument was passed).
41
43
 
42
44
  **Text mode:** 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 non-Claude runtimes (Codex, Gemini CLI, etc.) where `AskUserQuestion` is not available.
43
45
 
46
+ **First run — who you are (D-06):** before dispatching, run `pp_run query audience status --raw`. If `needs_choice` is `true`, show its `prompt` exactly as printed and wait for the reply. Then run `pp_run query audience answer '<reply>'` (the reply in single quotes, with any single quote in it removed) and show its output. If that fails, show the prompt once more, then continue either way. Once an answer is saved, re-run the init call above and apply the **Audience** line to the new `INIT`. Never write `~/.gsd/person.json` yourself. With nobody to answer (a headless run), skip this and save nothing.
47
+
44
48
  **Dispatch:**
45
49
  - If `FIRST_TOKEN` is `input` → Read `${PP_TOOLS%/bin/pp-tools.cjs}/workflows/discovery-sprint/input-package.md` and follow it. Stop — do not continue into the session flow.
46
50
  - Else if `FIRST_TOKEN` is `gap` → Read `${PP_TOOLS%/bin/pp-tools.cjs}/workflows/discovery-sprint/gap-analysis.md` and follow it. Stop. The numeric token is a document accession number, not a session number — the 1–13 range check and `SESSION_INVALID` do not apply here (the subfile re-derives the accession from `$ARGUMENTS` in its Step 0).
@@ -88,6 +92,8 @@ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
88
92
 
89
93
  ## Flow 1: Show Progress (no argument)
90
94
 
95
+ **Business user or business engineer (D-14):** when the init payload carries `audience`, run `pp_run query discovery.status` and show its output exactly as printed, with nothing before or after it, instead of steps 1-3 below; it gives the sprint's state and next step in the person's wording. If it exits non-zero or prints nothing, show none of its output and follow steps 1-3 instead, worded for this audience. A developer run follows steps 1-3 as written.
96
+
91
97
  1. Read `.planning/discovery/_progress.md`. If not found, tell the user no Discovery Sprint is set up for this project and suggest creating the artifacts first by running `/pp-discovery 1`.
92
98
 
93
99
  2. Parse the Session Progress table and display:
@@ -114,6 +120,8 @@ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
114
120
  > "Next recommended session: Session N — [Name]. Run `/pp-discovery N` to start."
115
121
  - If every session is "Completed", say the Discovery Sprint is complete and report the Project Charter: read the frontmatter of `docs/discovery/PROJECT-CHARTER.md` and state its `version`, `status` and `go_no_go` (`/pp-discovery charter` records signatures; `/pp-discovery-to-build` needs `Signed` or `Signed with conditions`). If the file does not exist, say so and point to `/pp-discovery 13` — its Step 0.5 drafts it.
116
122
 
123
+ `/pp-progress`, `/pp-progress --next` and `/pp-resume-work` show the same recommendation through `pp_run query discovery.status`, which applies the order above in code (`src/discovery-status.cts`); a change to this order must change it too. That command reports and checks nothing, so it has no Session 13 gate.
124
+
117
125
  ---
118
126
 
119
127
  ## Flow 2: Facilitate Session N (argument = 1–13)
@@ -137,6 +145,10 @@ For each session dependency, verify its status in `_progress.md`. If any depende
137
145
 
138
146
  **Text mode fallback:** present as numbered list: 1) Yes, continue anyway / 2) No, go back.
139
147
 
148
+ For a business user ask it in these words (D-14):
149
+
150
+ Business form: "This session builds on session {X} and {Y}, which are not finished yet. We can start now, but some answers may change later. Start anyway?"
151
+
140
152
  If the user confirms, proceed. Otherwise, stop and suggest the incomplete dependency.
141
153
 
142
154
  ### Step 3: Check for Resume
@@ -166,6 +178,8 @@ Update `.planning/discovery/_progress.md`: set session row status to "In Progres
166
178
 
167
179
  Facilitate in the language the user writes in. Prototypes and software are always English.
168
180
 
181
+ When `audience` is `business`, follow § Discovery narration of `audience-moments.md` (in the references folder, next to `audience.md`) in everything you say in this session (D-14); the session file is still written exactly as below.
182
+
169
183
  For each numbered topic in the session's "What We Cover" section:
170
184
 
171
185
  1. **Present the topic** conversationally: "Let's talk about [Topic Name]."
@@ -40,8 +40,12 @@ Valid pp-core subagent types (use exact names — do not fall back to 'general-p
40
40
  Resolve the `pp_run` helper before anything else. Every `pp_run` call below uses this shim.
41
41
 
42
42
  ```bash
43
+ _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
44
+ pp_run query audience fields
43
45
  ```
44
46
 
47
+ **Audience, before any question:** run the block above. If it prints `pp-tools.cjs not found`, show that error and stop. If it exits non-zero for any other reason, tell the person the audience setting could not be read (show the error) and continue; if it prints JSON, apply the **Audience** line below to it now.
48
+
45
49
  ---
46
50
 
47
51
  **Step 1: Validate environment**
@@ -291,13 +295,15 @@ workflow uses.
291
295
  ### 5a. Run init
292
296
 
293
297
  ```bash
294
- _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
298
+ command -v pp_run >/dev/null 2>&1 || { echo "ERROR: pp_run is not on PATH; prepend the resolver line from the top block to this block and run it again" >&2; exit 1; }
295
299
  mkdir -p .planning
296
- INIT=$(pp_run query init.new-project 2>/dev/null)
300
+ INIT=$(pp_run query init.new-project)
297
301
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
298
302
  echo "$INIT"
299
303
  ```
300
304
 
305
+ **Audience:** if `audience` is set, Read and follow `{audience_ref}`. Reply in any `response_language` and pass it to subagents; code and paths stay as is.
306
+
301
307
  ### 5b. Collect preferences
302
308
 
303
309
  Ask the pp-core configuration questions — identical to `/pp-new-project` Step 2a:
@@ -70,6 +70,8 @@ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
70
70
  AGENT_SKILLS_ANALYZER=$(pp_run query agent-skills pp-assumptions-analyzer)
71
71
  ```
72
72
 
73
+ **Audience:** if `audience` is set, Read and follow `{audience_ref}`. Reply in any `response_language` and pass it to subagents; code and paths stay as is.
74
+
73
75
  Parse JSON for: `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`,
74
76
  `phase_slug`, `padded_phase`, `has_research`, `has_context`, `has_plans`, `has_verification`,
75
77
  `plan_count`, `roadmap_exists`, `planning_exists`.
@@ -127,7 +127,7 @@ AGENT_SKILLS_ADVISOR=$(pp_run query agent-skills pp-advisor-researcher)
127
127
 
128
128
  Parse JSON for: `commit_docs`, `phase_found`, `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `has_research`, `has_context`, `has_plans`, `has_verification`, `plan_count`, `roadmap_exists`, `planning_exists`, `response_language`.
129
129
 
130
- **If `response_language` is set:** All user-facing questions, prompts, and explanations in this workflow MUST be presented in `{response_language}`. Technical terms, code, file paths, and subagent prompts stay in English — only user-facing output is translated.
130
+ **Audience:** if `audience` is set, Read and follow `{audience_ref}`. Reply in any `response_language` and pass it to subagents; code and paths stay as is.
131
131
 
132
132
  **If `phase_found` is false:**
133
133
  ```
@@ -39,6 +39,8 @@ INIT=$(pp_run query init.phase-op "${target}")
39
39
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
40
40
  ```
41
41
 
42
+ **Audience:** if `audience` is set, Read and follow `{audience_ref}`. Reply in any `response_language` and pass it to subagents; code and paths stay as is.
43
+
42
44
  Check `roadmap_exists` from init JSON. If false:
43
45
  ```
44
46
  ERROR: No roadmap found (.planning/ROADMAP.md)
@@ -18,6 +18,8 @@ INIT=$(pp_run query init.phase-op "${PHASE_ARG}")
18
18
  if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
19
19
  ```
20
20
 
21
+ **Audience:** if `audience` is set, Read and follow `{audience_ref}`. Reply in any `response_language` and pass it to subagents; code and paths stay as is.
22
+
21
23
  Parse: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`, `commit_docs`.
22
24
 
23
25
  ```bash