bmad-method 6.11.1-next.8 → 6.12.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 (153) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/AGENTS.md +12 -0
  3. package/CLAUDE.md +1 -0
  4. package/README.md +13 -19
  5. package/README_CN.md +0 -10
  6. package/README_KR.md +90 -0
  7. package/README_VN.md +0 -10
  8. package/greptile.json +52 -0
  9. package/package.json +6 -5
  10. package/src/bmm-skills/agents/bmad-agent-analyst/SKILL.md +1 -1
  11. package/src/bmm-skills/agents/bmad-agent-analyst/customize.toml +1 -3
  12. package/src/bmm-skills/agents/bmad-agent-architect/SKILL.md +1 -1
  13. package/src/bmm-skills/agents/bmad-agent-architect/customize.toml +1 -3
  14. package/src/bmm-skills/agents/bmad-agent-dev/SKILL.md +1 -1
  15. package/src/bmm-skills/agents/bmad-agent-dev/customize.toml +1 -3
  16. package/src/bmm-skills/agents/bmad-agent-pm/SKILL.md +1 -1
  17. package/src/bmm-skills/agents/bmad-agent-pm/customize.toml +1 -3
  18. package/src/bmm-skills/agents/bmad-agent-ux-designer/SKILL.md +1 -1
  19. package/src/bmm-skills/agents/bmad-agent-ux-designer/customize.toml +1 -3
  20. package/src/bmm-skills/module-help.csv +2 -2
  21. package/src/bmm-skills/plan/bmad-architecture/SKILL.md +1 -1
  22. package/src/bmm-skills/plan/bmad-architecture/customize.toml +5 -6
  23. package/src/bmm-skills/plan/bmad-create-epics-and-stories/SKILL.md +1 -1
  24. package/src/bmm-skills/plan/bmad-create-epics-and-stories/customize.toml +1 -3
  25. package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-04-final-validation.md +1 -1
  26. package/src/bmm-skills/plan/bmad-prd/SKILL.md +1 -1
  27. package/src/bmm-skills/plan/bmad-prd/customize.toml +5 -6
  28. package/src/bmm-skills/plan/bmad-prfaq/SKILL.md +1 -1
  29. package/src/bmm-skills/plan/bmad-prfaq/customize.toml +1 -3
  30. package/src/bmm-skills/plan/bmad-prfaq/references/verdict.md +1 -1
  31. package/src/bmm-skills/plan/bmad-product-brief/SKILL.md +1 -1
  32. package/src/bmm-skills/plan/bmad-product-brief/customize.toml +5 -6
  33. package/src/bmm-skills/plan/bmad-project-context/SKILL.md +7 -6
  34. package/src/bmm-skills/plan/bmad-project-context/references/best-practices.md +2 -2
  35. package/src/bmm-skills/plan/bmad-spec/SKILL.md +1 -1
  36. package/src/bmm-skills/plan/bmad-spec/customize.toml +5 -5
  37. package/src/bmm-skills/plan/bmad-sprint-planning/SKILL.md +1 -1
  38. package/src/bmm-skills/plan/bmad-sprint-planning/customize.toml +1 -3
  39. package/src/bmm-skills/plan/bmad-sprint-planning/scripts/__pycache__/sprint_plan.cpython-311.pyc +0 -0
  40. package/src/bmm-skills/plan/bmad-sprint-planning/scripts/tests/__pycache__/test_sprint_plan.cpython-311-pytest-9.1.1.pyc +0 -0
  41. package/src/bmm-skills/plan/bmad-ux/SKILL.md +1 -1
  42. package/src/bmm-skills/plan/bmad-ux/customize.toml +1 -3
  43. package/src/bmm-skills/ship/bmad-build/SKILL.md +1 -1
  44. package/src/bmm-skills/ship/bmad-build/customize.toml +21 -33
  45. package/src/bmm-skills/ship/bmad-build/references/claims-check.md +14 -0
  46. package/src/bmm-skills/ship/bmad-build/review-prompts/edge-case-hunter.md +31 -7
  47. package/src/bmm-skills/ship/bmad-build/review-prompts/verification-gap.md +4 -4
  48. package/src/bmm-skills/ship/bmad-build/spec-template.md +26 -4
  49. package/src/bmm-skills/ship/bmad-build/step-01-clarify-and-route.md +21 -26
  50. package/src/bmm-skills/ship/bmad-build/step-02-plan.md +31 -16
  51. package/src/bmm-skills/ship/bmad-build/step-03-implement.md +5 -3
  52. package/src/bmm-skills/ship/bmad-build/step-04-review.md +49 -19
  53. package/src/bmm-skills/ship/bmad-build/step-05-present.md +9 -41
  54. package/src/bmm-skills/ship/bmad-build/step-oneshot.md +60 -29
  55. package/src/bmm-skills/ship/bmad-build/sync-sprint-status.md +5 -19
  56. package/src/bmm-skills/ship/bmad-build-auto/customize.toml +17 -19
  57. package/src/bmm-skills/ship/bmad-build-auto/references/claims-check.md +14 -0
  58. package/src/bmm-skills/ship/bmad-build-auto/review-prompts/edge-case-hunter.md +31 -7
  59. package/src/bmm-skills/ship/bmad-build-auto/review-prompts/verification-gap.md +4 -4
  60. package/src/bmm-skills/ship/bmad-build-auto/spec-template.md +4 -7
  61. package/src/bmm-skills/ship/bmad-build-auto/step-01-clarify-and-route.md +3 -2
  62. package/src/bmm-skills/ship/bmad-build-auto/step-03-implement.md +5 -1
  63. package/src/bmm-skills/ship/bmad-build-auto/step-04-review.md +58 -38
  64. package/src/bmm-skills/ship/bmad-build-auto/workflow.md +1 -1
  65. package/src/bmm-skills/ship/bmad-code-review/SKILL.md +1 -1
  66. package/src/bmm-skills/ship/bmad-code-review/customize.toml +15 -18
  67. package/src/bmm-skills/ship/bmad-code-review/references/claims-check.md +14 -0
  68. package/src/bmm-skills/ship/bmad-code-review/review-prompts/edge-case-hunter.md +31 -7
  69. package/src/bmm-skills/ship/bmad-code-review/review-prompts/verification-gap.md +4 -4
  70. package/src/bmm-skills/ship/bmad-code-review/steps/step-01-gather-context.md +30 -23
  71. package/src/bmm-skills/ship/bmad-code-review/steps/step-02-review.md +3 -3
  72. package/src/bmm-skills/ship/bmad-code-review/steps/step-03-triage.md +25 -21
  73. package/src/bmm-skills/ship/bmad-code-review/steps/step-04-present.md +20 -18
  74. package/src/bmm-skills/ship/bmad-correct-course/SKILL.md +13 -5
  75. package/src/bmm-skills/ship/bmad-correct-course/customize.toml +1 -3
  76. package/src/bmm-skills/ship/bmad-qa-generate-e2e-tests/SKILL.md +2 -2
  77. package/src/bmm-skills/ship/bmad-qa-generate-e2e-tests/customize.toml +1 -3
  78. package/src/bmm-skills/ship/bmad-retrospective/SKILL.md +1 -1
  79. package/src/bmm-skills/ship/bmad-retrospective/customize.toml +1 -3
  80. package/src/bmm-skills/ship/bmad-retrospective/scripts/__pycache__/sprint_status.cpython-311.pyc +0 -0
  81. package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_git_evidence.cpython-311-pytest-9.1.1.pyc +0 -0
  82. package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_sprint_status.cpython-311-pytest-9.1.1.pyc +0 -0
  83. package/src/bmm-skills/ship/{bmad-checkpoint-preview → bmad-walkthrough}/SKILL.md +4 -4
  84. package/src/bmm-skills/ship/{bmad-checkpoint-preview → bmad-walkthrough}/customize.toml +2 -4
  85. package/src/bmm-skills/ship/{bmad-checkpoint-preview → bmad-walkthrough}/step-05-wrapup.md +1 -1
  86. package/src/bmm-skills/v6-shims/README.md +1 -0
  87. package/src/bmm-skills/v6-shims/bmad-checkpoint-preview/SKILL.md +21 -0
  88. package/src/bmm-skills/v6-shims/bmad-create-architecture/SKILL.md +1 -1
  89. package/src/bmm-skills/v6-shims/bmad-create-architecture/customize.toml +1 -3
  90. package/src/bmm-skills/v6-shims/bmad-create-prd/SKILL.md +1 -1
  91. package/src/bmm-skills/v6-shims/bmad-create-prd/customize.toml +1 -3
  92. package/src/bmm-skills/v6-shims/bmad-create-story/SKILL.md +3 -3
  93. package/src/bmm-skills/v6-shims/bmad-create-story/customize.toml +1 -3
  94. package/src/bmm-skills/v6-shims/bmad-dev-story/SKILL.md +2 -2
  95. package/src/bmm-skills/v6-shims/bmad-dev-story/customize.toml +1 -6
  96. package/src/bmm-skills/v6-shims/bmad-domain-research/SKILL.md +1 -1
  97. package/src/bmm-skills/v6-shims/bmad-edit-prd/SKILL.md +1 -1
  98. package/src/bmm-skills/v6-shims/bmad-edit-prd/customize.toml +1 -3
  99. package/src/bmm-skills/v6-shims/bmad-market-research/SKILL.md +1 -1
  100. package/src/bmm-skills/v6-shims/bmad-sprint-status/SKILL.md +1 -1
  101. package/src/bmm-skills/v6-shims/bmad-sprint-status/customize.toml +1 -3
  102. package/src/bmm-skills/v6-shims/bmad-technical-research/SKILL.md +1 -1
  103. package/src/bmm-skills/v6-shims/bmad-validate-prd/SKILL.md +1 -1
  104. package/src/bmm-skills/v6-shims/bmad-validate-prd/customize.toml +1 -3
  105. package/src/core-skills/bmad-advanced-elicitation/SKILL.md +22 -23
  106. package/src/core-skills/bmad-brainstorming/SKILL.md +1 -1
  107. package/src/core-skills/bmad-brainstorming/customize.toml +5 -6
  108. package/src/core-skills/bmad-brainstorming/scripts/brain.py +19 -0
  109. package/src/core-skills/bmad-brainstorming/scripts/tests/test_brain.py +50 -0
  110. package/src/core-skills/bmad-customize/SKILL.md +1 -1
  111. package/src/core-skills/bmad-deep-recon/SKILL.md +1 -1
  112. package/src/core-skills/bmad-forge-idea/SKILL.md +1 -1
  113. package/src/core-skills/bmad-forge-idea/customize.toml +5 -6
  114. package/src/core-skills/bmad-forge-idea/scripts/resolve_personas.py +3 -1
  115. package/src/core-skills/bmad-forge-idea/scripts/tests/test_resolve_personas.py +22 -0
  116. package/src/core-skills/bmad-help/SKILL.md +1 -1
  117. package/src/core-skills/bmad-party-mode/SKILL.md +1 -1
  118. package/src/core-skills/bmad-party-mode/customize.toml +4 -4
  119. package/src/core-skills/bmad-party-mode/references/create-party.md +1 -1
  120. package/src/core-skills/bmad-party-mode/scripts/resolve_party.py +3 -1
  121. package/src/core-skills/bmad-party-mode/scripts/tests/test_resolve_party.py +22 -0
  122. package/src/core-skills/bmad-review/SKILL.md +5 -4
  123. package/src/core-skills/bmad-review/customize.toml +1 -1
  124. package/src/core-skills/bmad-review/references/lens-edge-case-hunter.md +18 -0
  125. package/src/core-skills/module-help.csv +1 -1
  126. package/src/scripts/__pycache__/config_utils.cpython-311.pyc +0 -0
  127. package/src/scripts/resolve_config.py +9 -1
  128. package/src/scripts/resolve_customization.py +72 -7
  129. package/src/scripts/tests/__pycache__/test_config_utils.cpython-311.pyc +0 -0
  130. package/src/scripts/tests/__pycache__/test_resolve_config.cpython-311.pyc +0 -0
  131. package/src/scripts/tests/__pycache__/test_resolve_customization.cpython-311.pyc +0 -0
  132. package/src/scripts/tests/test_resolve_config.py +28 -0
  133. package/src/scripts/tests/test_resolve_customization.py +102 -0
  134. package/tools/installer/core/installer.js +33 -1
  135. package/tools/installer/core/shim-policy.js +75 -7
  136. package/tools/installer/ide/platform-codes.yaml +13 -0
  137. package/tools/installer/prompts.js +15 -2
  138. package/tools/installer/ui.js +28 -8
  139. package/tools/skill-validator.md +85 -151
  140. package/tools/tests/__pycache__/test_validate_skills.cpython-311.pyc +0 -0
  141. package/tools/tests/fixtures/validate-skills/bmad/SKILL.md +8 -0
  142. package/tools/tests/fixtures/validate-skills/deprecated-shim/SKILL.md +9 -0
  143. package/tools/tests/fixtures/validate-skills/missing-trigger/SKILL.md +9 -0
  144. package/tools/tests/fixtures/validate-skills/with-trigger/SKILL.md +8 -0
  145. package/tools/tests/test_validate_skills.py +476 -0
  146. package/tools/validate-published-implementation-model.mjs +0 -9
  147. package/tools/validate_skills.py +698 -0
  148. package/tools/validate-skills.js +0 -735
  149. /package/src/bmm-skills/ship/{bmad-checkpoint-preview → bmad-walkthrough}/generate-trail.md +0 -0
  150. /package/src/bmm-skills/ship/{bmad-checkpoint-preview → bmad-walkthrough}/step-01-orientation.md +0 -0
  151. /package/src/bmm-skills/ship/{bmad-checkpoint-preview → bmad-walkthrough}/step-02-walkthrough.md +0 -0
  152. /package/src/bmm-skills/ship/{bmad-checkpoint-preview → bmad-walkthrough}/step-03-detail-pass.md +0 -0
  153. /package/src/bmm-skills/ship/{bmad-checkpoint-preview → bmad-walkthrough}/step-04-testing.md +0 -0
@@ -25,6 +25,6 @@ HALT — do not proceed until the user makes their choice.
25
25
 
26
26
  ## On Complete
27
27
 
28
- Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete`
28
+ Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow.on_complete`
29
29
 
30
30
  If the resolved `workflow.on_complete` is non-empty, follow it as the final terminal instruction before exiting.
@@ -18,6 +18,7 @@ stated intent and pre-resolved customization fields so the target skips its own
18
18
  | `bmad-domain-research` | `bmad-deep-recon` (domain type) |
19
19
  | `bmad-technical-research` | `bmad-deep-recon` (technical type) |
20
20
  | `bmad-sprint-status` | `bmad-sprint-planning` (status view) |
21
+ | `bmad-checkpoint-preview` | `bmad-walkthrough` |
21
22
 
22
23
  Enterprise users may still depend on these IDs, so they ship by default. Removal rides the
23
24
  v7 cut — never a 6.x minor.
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: bmad-checkpoint-preview
3
+ description: "Deprecated: forwards to bmad-walkthrough. Do not use unless invoked by name"
4
+ metadata:
5
+ lifecycle: shim
6
+ ---
7
+
8
+ # Deprecated Walkthrough Alias
9
+
10
+ ## On Activation
11
+
12
+ 1. Check whether either legacy customization file exists:
13
+ - `{project-root}/_bmad/custom/bmad-checkpoint-preview.toml`
14
+ - `{project-root}/_bmad/custom/bmad-checkpoint-preview.user.toml`
15
+ 2. If neither legacy file exists, output exactly `bmad-checkpoint-preview is deprecated. Redirecting to bmad-walkthrough. Please use bmad-walkthrough in the future.`, invoke `bmad-walkthrough` exactly once with the user's original input verbatim, then execute no further steps in this shim.
16
+ 3. For every legacy file that exists, use its matching new filename:
17
+ - `{project-root}/_bmad/custom/bmad-checkpoint-preview.toml` becomes `{project-root}/_bmad/custom/bmad-walkthrough.toml`.
18
+ - `{project-root}/_bmad/custom/bmad-checkpoint-preview.user.toml` becomes `{project-root}/_bmad/custom/bmad-walkthrough.user.toml`.
19
+ 4. If the matching new file does not exist, tell the user that the customization file uses the deprecated name and offer to rename it. Rename it only after explicit approval. If approval is declined or unavailable, or the rename fails, HALT and do not invoke any skill.
20
+ 5. If the matching new file already exists, do not overwrite it. Read both files, explain their differences, and propose the exact content for the new file. Resolve conflicting values with the user. Only after the user explicitly approves that content, save and verify the new file, then remove the legacy file. If approval is declined or unavailable, or any operation fails, HALT and do not invoke any skill.
21
+ 6. After every detected legacy file has been migrated successfully and no legacy file remains, output exactly `bmad-checkpoint-preview is deprecated. Redirecting to bmad-walkthrough. Please use bmad-walkthrough in the future.`, invoke `bmad-walkthrough` exactly once with the user's original input verbatim, then execute no further steps in this shim.
@@ -11,7 +11,7 @@ This skill was consolidated into `bmad-architecture`. It is retained as a thin c
11
11
 
12
12
  ## On Activation
13
13
 
14
- 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-create-architecture.toml` and `bmad-create-architecture.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
14
+ 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-create-architecture.toml` and `bmad-create-architecture.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
15
15
 
16
16
  2. Load `{project-root}/_bmad/bmm/config.yaml` (and `config.user.yaml` if present) to resolve `{user_name}` and `{communication_language}`.
17
17
 
@@ -30,9 +30,7 @@ activation_steps_append = []
30
30
  # - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
31
31
  # (glob patterns are supported; the file's contents are loaded and treated as facts).
32
32
 
33
- persistent_facts = [
34
- "file:{project-root}/**/project-context.md",
35
- ]
33
+ persistent_facts = []
36
34
 
37
35
  # Scalar: executed when the workflow reaches Step 8 (Architecture Completion & Handoff),
38
36
  # after the architecture document frontmatter is updated and next-steps guidance is given.
@@ -11,7 +11,7 @@ This skill was consolidated into `bmad-prd`. It is retained as a thin compatibil
11
11
 
12
12
  ## On Activation
13
13
 
14
- 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-create-prd.toml` and `bmad-create-prd.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
14
+ 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-create-prd.toml` and `bmad-create-prd.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
15
15
 
16
16
  2. Load `{project-root}/_bmad/bmm/config.yaml` (and `config.user.yaml` if present) to resolve `{user_name}` and `{communication_language}`.
17
17
 
@@ -30,9 +30,7 @@ activation_steps_append = []
30
30
  # - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
31
31
  # (glob patterns are supported; the file's contents are loaded and treated as facts).
32
32
 
33
- persistent_facts = [
34
- "file:{project-root}/**/project-context.md",
35
- ]
33
+ persistent_facts = []
36
34
 
37
35
  # Scalar: executed when the workflow reaches Step 12 (Workflow Completion),
38
36
  # after the PRD is finalized and workflow status is updated. Override wins.
@@ -32,7 +32,7 @@ If you need an explicit user instruction to run them, ask once now for the whole
32
32
 
33
33
  ### Step 1: Resolve the Workflow Block
34
34
 
35
- Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
35
+ Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`
36
36
 
37
37
  **If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
38
38
 
@@ -257,7 +257,7 @@ Activation is complete. If `activation_steps_prepend` or `activation_steps_appen
257
257
 
258
258
  <!-- Load all available content through discovery protocol -->
259
259
  <action>Read fully and follow `./discover-inputs.md` to load all input files</action>
260
- <note>Available content: {epics_content}, {prd_content}, {architecture_content}, {ux_content}, plus the project-context facts loaded during activation via `persistent_facts`.</note>
260
+ <note>Available content: {epics_content}, {prd_content}, {architecture_content}, {ux_content}, plus any facts loaded during activation via `persistent_facts` (empty unless the user opted in).</note>
261
261
 
262
262
  <!-- Analyze epics file for story foundation -->
263
263
  <action>From {epics_content}, extract Epic {{epic_num}} complete context:</action> **EPIC ANALYSIS:** - Epic
@@ -430,7 +430,7 @@ Activation is complete. If `activation_steps_prepend` or `activation_steps_appen
430
430
 
431
431
  **The developer now has everything needed for flawless implementation!**
432
432
  </output>
433
- <action>Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.</action>
433
+ <action>Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.</action>
434
434
  </step>
435
435
 
436
436
  </workflow>
@@ -30,9 +30,7 @@ activation_steps_append = []
30
30
  # - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
31
31
  # (glob patterns are supported; the file's contents are loaded and treated as facts).
32
32
 
33
- persistent_facts = [
34
- "file:{project-root}/**/project-context.md",
35
- ]
33
+ persistent_facts = []
36
34
 
37
35
  # Scalar: executed when the workflow reaches Step 6 (Update sprint status and finalize),
38
36
  # after the story file is saved and sprint-status.yaml is updated. Override wins.
@@ -29,7 +29,7 @@ metadata:
29
29
 
30
30
  ### Step 1: Resolve the Workflow Block
31
31
 
32
- Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
32
+ Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`
33
33
 
34
34
  **If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
35
35
 
@@ -498,7 +498,7 @@ Activation is complete. If `activation_steps_prepend` or `activation_steps_appen
498
498
  <action>Suggest checking {sprint_status} to see project progress</action>
499
499
  </check>
500
500
  <action>Remain flexible - allow user to choose their own path or ask for other assistance</action>
501
- <action>Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.</action>
501
+ <action>Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.</action>
502
502
  </step>
503
503
 
504
504
  </workflow>
@@ -30,12 +30,7 @@ activation_steps_append = []
30
30
  # - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
31
31
  # (glob patterns are supported; the file's contents are loaded and treated as facts).
32
32
 
33
- persistent_facts = [
34
- "file:{project-root}/**/project-context.md",
35
- "Never add epic or story references as inline code comments (e.g. # Epic: X, # Story: PROJ-42).",
36
- "Code comments explain why, not what — no AI workflow metadata, planning refs, or story tracking in source code.",
37
- "Generated code must be production-ready: clean, minimal, and free of AI-generated noise.",
38
- ]
33
+ persistent_facts = []
39
34
 
40
35
  # Scalar: executed when the workflow reaches its final step,
41
36
  # after the story implementation is complete and status is updated. Override wins.
@@ -11,6 +11,6 @@ This skill was consolidated into `bmad-deep-recon`. It is retained as a thin com
11
11
 
12
12
  ## On Activation
13
13
 
14
- 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-domain-research.toml` and `bmad-domain-research.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
14
+ 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-domain-research.toml` and `bmad-domain-research.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
15
15
  2. Emit a deprecation notice to the user (in their configured communication language): `bmad-domain-research` is deprecated and forwards to `bmad-deep-recon` with the domain type. To silence this notice and access the full new surface (draft/process/run modes, research types, verification levels, HTML briefing, handoffs), migrate `_bmad/custom/bmad-domain-research.toml` to `_bmad/custom/bmad-deep-recon.toml` and invoke `bmad-deep-recon` directly.
16
16
  3. Invoke `bmad-deep-recon` with: **research type** `domain` (skip its type inference), the four legacy fields above as pre-resolved values, and the user's original input verbatim. `bmad-deep-recon` takes the workflow from here — do not execute any further steps in this shim.
@@ -11,7 +11,7 @@ This skill was consolidated into `bmad-prd`. It is retained as a thin compatibil
11
11
 
12
12
  ## On Activation
13
13
 
14
- 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-edit-prd.toml` and `bmad-edit-prd.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
14
+ 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-edit-prd.toml` and `bmad-edit-prd.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
15
15
 
16
16
  2. Load `{project-root}/_bmad/bmm/config.yaml` (and `config.user.yaml` if present) to resolve `{user_name}` and `{communication_language}`.
17
17
 
@@ -30,9 +30,7 @@ activation_steps_append = []
30
30
  # - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
31
31
  # (glob patterns are supported; the file's contents are loaded and treated as facts).
32
32
 
33
- persistent_facts = [
34
- "file:{project-root}/**/project-context.md",
35
- ]
33
+ persistent_facts = []
36
34
 
37
35
  # Scalar: executed when the workflow reaches Step E-4 (Complete & Validate) and the
38
36
  # user exits via [S] Summary or [X] Exit — not on [V] Validate (which chains to
@@ -11,6 +11,6 @@ This skill was consolidated into `bmad-deep-recon`. It is retained as a thin com
11
11
 
12
12
  ## On Activation
13
13
 
14
- 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-market-research.toml` and `bmad-market-research.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
14
+ 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-market-research.toml` and `bmad-market-research.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
15
15
  2. Emit a deprecation notice to the user (in their configured communication language): `bmad-market-research` is deprecated and forwards to `bmad-deep-recon` with the market type. To silence this notice and access the full new surface (draft/process/run modes, research types, verification levels, HTML briefing, handoffs), migrate `_bmad/custom/bmad-market-research.toml` to `_bmad/custom/bmad-deep-recon.toml` and invoke `bmad-deep-recon` directly.
16
16
  3. Invoke `bmad-deep-recon` with: **research type** `market` (skip its type inference), the four legacy fields above as pre-resolved values, and the user's original input verbatim. `bmad-deep-recon` takes the workflow from here — do not execute any further steps in this shim.
@@ -11,7 +11,7 @@ This skill was consolidated into `bmad-sprint-planning`, which now owns the whol
11
11
 
12
12
  ## On Activation
13
13
 
14
- 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-sprint-status.toml` and `bmad-sprint-status.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
14
+ 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-sprint-status.toml` and `bmad-sprint-status.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
15
15
 
16
16
  2. Load `{project-root}/_bmad/bmm/config.yaml` (and `config.user.yaml` if present) to resolve `{user_name}` and `{communication_language}`.
17
17
 
@@ -30,9 +30,7 @@ activation_steps_append = []
30
30
  # - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
31
31
  # (glob patterns are supported; the file's contents are loaded and treated as facts).
32
32
 
33
- persistent_facts = [
34
- "file:{project-root}/**/project-context.md",
35
- ]
33
+ persistent_facts = []
36
34
 
37
35
  # Scalar: executed when the workflow reaches its final step,
38
36
  # after sprint status is summarized and risks are surfaced. Override wins.
@@ -11,6 +11,6 @@ This skill was consolidated into `bmad-deep-recon`. It is retained as a thin com
11
11
 
12
12
  ## On Activation
13
13
 
14
- 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-technical-research.toml` and `bmad-technical-research.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
14
+ 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-technical-research.toml` and `bmad-technical-research.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
15
15
  2. Emit a deprecation notice to the user (in their configured communication language): `bmad-technical-research` is deprecated and forwards to `bmad-deep-recon` with the technical type. To silence this notice and access the full new surface (draft/process/run modes, research types, verification levels, HTML briefing, handoffs), migrate `_bmad/custom/bmad-technical-research.toml` to `_bmad/custom/bmad-deep-recon.toml` and invoke `bmad-deep-recon` directly.
16
16
  3. Invoke `bmad-deep-recon` with: **research type** `technical` (skip its type inference), the four legacy fields above as pre-resolved values, and the user's original input verbatim. `bmad-deep-recon` takes the workflow from here — do not execute any further steps in this shim.
@@ -11,7 +11,7 @@ This skill was consolidated into `bmad-prd`. It is retained as a thin compatibil
11
11
 
12
12
  ## On Activation
13
13
 
14
- 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-validate-prd.toml` and `bmad-validate-prd.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
14
+ 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-validate-prd.toml` and `bmad-validate-prd.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
15
15
 
16
16
  2. Load `{project-root}/_bmad/bmm/config.yaml` (and `config.user.yaml` if present) to resolve `{user_name}` and `{communication_language}`.
17
17
 
@@ -30,9 +30,7 @@ activation_steps_append = []
30
30
  # - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
31
31
  # (glob patterns are supported; the file's contents are loaded and treated as facts).
32
32
 
33
- persistent_facts = [
34
- "file:{project-root}/**/project-context.md",
35
- ]
33
+ persistent_facts = []
36
34
 
37
35
  # Scalar: executed when the workflow reaches Step 13 (Validation Report Complete) and
38
36
  # the user exits via [X] Exit — not on [E] Use Edit Workflow (which chains to
@@ -14,12 +14,12 @@ You are BMad's shared refinement checkpoint: other skills invoke you at natural
14
14
 
15
15
  ## On Activation
16
16
 
17
- 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults.
17
+ 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults.
18
18
  2. Hold every `{workflow.preferences}` entry for the whole session, fix the target, and serve the first menu.
19
19
 
20
20
  ## Serving the Catalog
21
21
 
22
- `scripts/pick_methods.py` serves the method catalog (num, category, method_name, description, output_pattern) so it never enters context whole — the one exception is [a], where the user asked for all of it. Invoke as:
22
+ `scripts/pick_methods.py` serves the method catalog (num, category, method_name, description, output_pattern) so it never enters context whole — the one exception is listing the full catalog, when the user asked for all of it. Invoke as:
23
23
 
24
24
  ```bash
25
25
  uv run {skill-root}/scripts/pick_methods.py --file {workflow.methods_file} <command>
@@ -28,7 +28,7 @@ uv run {skill-root}/scripts/pick_methods.py --file {workflow.methods_file} <comm
28
28
  If `{workflow.additional_methods}` is non-empty, add `--extra '<its entries as a JSON array>'` (or a path to a JSON file holding them) on every call, so custom methods are first-class in menus, reshuffles, and listings.
29
29
 
30
30
  - `categories` — category names + counts, the cheap map.
31
- - `list --category <cat> [--category <cat>]` — the index for chosen categories; `--all` dumps the whole catalog, only for [a].
31
+ - `list --category <cat> [--category <cat>]` — the index for chosen categories; `--all` dumps the whole catalog, only when listing all.
32
32
  - `show <name-or-num> [...]` — full rows by name or num.
33
33
  - `random -n 5 --spread [--exclude <name>]...` — a category-diverse random draw.
34
34
 
@@ -36,30 +36,29 @@ If `{workflow.additional_methods}` is non-empty, add `--extra '<its entries as a
36
36
 
37
37
  ## The Menu
38
38
 
39
- ```
40
- **Advanced Elicitation Options**
41
- Choose a number (1-5), [r] to Reshuffle, [a] List All, or [x] to Proceed:
42
-
43
- 1. [Method Name]
44
- 2. [Method Name]
45
- 3. [Method Name]
46
- 4. [Method Name]
47
- 5. [Method Name]
48
- r. Reshuffle the list with 5 new options
49
- a. List all methods with descriptions
50
- x. Proceed / No Further Actions
51
- ```
39
+ HALT and give the user a choice:
40
+
41
+ - The five offered methods, listed by name. The user may pick one or several.
42
+ - **Reshuffle** — replace the list with five new options.
43
+ - **List all** — show the full catalog with descriptions.
44
+ - **Proceed** — no further elicitation.
52
45
 
53
- This menu is the interface other skills and their users rely on — keep its options and behavior stable. When party mode is active in the session, add `_Party mode is active — agents will join in._` under the heading. Handle the response:
46
+ This menu is the interface other skills and their users rely on — keep its options and behavior stable. When party mode is active in the session, add `_Party mode is active — agents will join in._` under the heading.
54
47
 
55
- - **1–5** — run that method (several numbers: in sequence), then re-present the menu.
56
- - **r** — reshuffle as above and re-present.
57
- - **a** — show the full catalog (`list --all`) as a compact table; a pick by name or number runs like a numbered choice.
58
- - **x** — done. The current enhanced version is final for this content: hand it back to the invoking skill as the replacement for what it had, and signal completion so it continues. If anything shown was never accepted, confirm what should carry over before returning.
59
- - **Anything else** — treat as direction: apply it to the target and re-present the menu.
48
+ - If the user picks methods: run them (several: in sequence), then offer the menu again.
49
+ - If the user chooses **Reshuffle**: reshuffle as above and offer the menu again.
50
+ - If the user chooses **List all**: show the full catalog (`list --all`) as a compact table; a pick by name or number runs like a method choice.
51
+ - If the user chooses **Proceed**: done. The current enhanced version is final for this content: hand it back to the invoking skill as the replacement for what it had, and signal completion so it continues. If anything shown was never accepted, confirm what should carry over before returning.
52
+ - Any other reply is direction: apply it to the target and offer the menu again.
60
53
 
61
54
  ## Running a Method
62
55
 
63
- Use the method's description as its intent and its output_pattern as a flexible flow guide; scale depth to the target — a paragraph gets a light pass, an architecture decision gets the full treatment. Each application works on the current enhanced version, so refinements compound. Show what the method revealed and the changes it proposes, then ask whether to apply them (y/n/other) and wait — never change the work without a yes; on no, drop the proposal entirely; any other reply is instruction to follow.
56
+ Use the method's description as its intent and its output_pattern as a flexible flow guide; scale depth to the target — a paragraph gets a light pass, an architecture decision gets the full treatment. Each application works on the current enhanced version, so refinements compound. Show what the method revealed and the changes it proposes, then HALT and give the user a choice:
57
+
58
+ - **Apply** — accept the proposed changes.
59
+ - **Reject** — drop the proposal entirely.
60
+ - Or give different direction.
61
+
62
+ Never change the work unless the user accepts the proposal. If they reject it, drop the proposal entirely. Any other reply is instruction to follow.
64
63
 
65
64
  When a method casts personas (round tables, panels, debates), reuse party members already in the session if party mode is active; otherwise resolve installed agents on demand via `uv run {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root} --key agents` (a four-layer merge of `_bmad/config.toml`, `config.user.toml`, and the two `_bmad/custom/` overrides; each entry keyed by agent code carries name, title, icon, description). If neither yields a fit, invent named viewpoints suited to the content.
@@ -18,7 +18,7 @@ The session runs in one of three stances, chosen by the user — set explicitly
18
18
 
19
19
  ## On Activation
20
20
 
21
- 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, use a subagent to read `{skill-root}/customize.toml` directly with defaults.
21
+ 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. On failure, use a subagent to read `{skill-root}/customize.toml` directly with defaults.
22
22
  2. Run each `{workflow.activation_steps_prepend}` entry. Treat each `{workflow.persistent_facts}` entry as foundational context (`file:`-prefixed entries are paths/globs under `{project-root}` — load their contents; others are facts verbatim).
23
23
  3. Resolve central config: `uv run {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root} --key core` (merges `_bmad/config.toml`, `_bmad/config.user.toml`, and the `_bmad/custom/` overrides); from the merged JSON resolve `{user_name}`, `{communication_language}`, `{document_output_language}`, `{output_folder}`, `{project_name}`; `{date}` is today. On failure or missing values → neutral defaults; never block.
24
24
  4. **If launched headless** (a machine signal, not a human asking for output — `references/headless.md` lists them): load `references/headless.md` and follow it for the whole run; never load it otherwise. Outside headless, you generate ideas yourself only in autonomous mode (`references/mode-autonomous.md`) — never in facilitator or partner mode.
@@ -22,12 +22,11 @@ activation_steps_append = []
22
22
  # Persistent facts the facilitator keeps in mind for the whole session
23
23
  # (domain constraints, house rules, stylistic guardrails). Each entry is a
24
24
  # literal sentence, a skill prefixed with `skill:`, or a `file:`-prefixed
25
- # path/glob whose contents are loaded as facts. Default loads project-context.md
26
- # if bmad-generate-project-context has produced one, giving the facilitator
27
- # persistent awareness of the project's domain without re-asking.
28
- persistent_facts = [
29
- "file:{project-root}/**/project-context.md",
30
- ]
25
+ # path/glob whose contents are loaded as facts. Empty by default — repo-wide context
26
+ # belongs in AGENTS.md (see bmad-project-context), which every skill already sees. Use
27
+ # this for context only the facilitator needs, loaded on demand rather than carried as
28
+ # constant memory (e.g. `file:{project-root}/**/project-context.md` if you keep one).
29
+ persistent_facts = []
31
30
 
32
31
  # The technique library loaded on demand during the session. Swap the path in
33
32
  # team/user TOML to ship a different or extended catalog of creative methods.
@@ -692,7 +692,26 @@ def html_doc(rows: list[dict]) -> str:
692
692
  )
693
693
 
694
694
 
695
+ def pin_utf8(stream):
696
+ """Pin a console stream to UTF-8, keeping its own error handler.
697
+
698
+ `--extra` technique text and the technique names echoed to stderr are
699
+ arbitrary user input, so either stream can carry a character the platform
700
+ default cannot encode (cp1252 on Windows) and print() then raises.
701
+
702
+ errors= is passed through deliberately: reconfigure(encoding=...) alone
703
+ resets the handler to "strict", which would silently downgrade stderr's
704
+ POSIX default of "backslashreplace" and turn a diagnostic about an
705
+ undecodable path into a traceback.
706
+ """
707
+ reconfigure = getattr(stream, "reconfigure", None)
708
+ if reconfigure is not None:
709
+ reconfigure(encoding="utf-8", errors=getattr(stream, "errors", None) or "strict")
710
+
711
+
695
712
  def main(argv: list[str] | None = None) -> int:
713
+ pin_utf8(sys.stdout)
714
+ pin_utf8(sys.stderr)
696
715
  p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
697
716
  p.add_argument("--file", type=Path, default=DEFAULT_FILE, help="technique CSV (default: sibling assets/brain-methods.csv)")
698
717
  p.add_argument("--extra", type=Path, help="JSON overlay of additional techniques (customize.toml additional_techniques), merged into every command")
@@ -3,6 +3,7 @@
3
3
  # dependencies = ["pytest>=8.0"]
4
4
  # ///
5
5
  """Tests for brain.py. Run: uv run -m pytest scripts/tests/test_brain.py"""
6
+ import io
6
7
  import json
7
8
  import sys
8
9
  from pathlib import Path
@@ -227,6 +228,55 @@ def test_unknown_category_style_uses_fallback_glyph():
227
228
  assert glyph == brain._FALLBACK_GLYPH
228
229
 
229
230
 
231
+ # --- console encoding (Windows cp1252) ----------------------------------
232
+
233
+ def _cp1252_stream():
234
+ """A text stream that behaves like a Windows console: cp1252, strict."""
235
+ return io.TextIOWrapper(io.BytesIO(), encoding="cp1252", errors="strict", write_through=True)
236
+
237
+
238
+ def test_extra_technique_prints_when_stdout_encoding_is_cp1252(lib, tmp_path, monkeypatch):
239
+ # --extra text is arbitrary user input; the shipped catalog happens to be
240
+ # cp1252-safe, an overlay is not. Unpinned stdout raises UnicodeEncodeError
241
+ # and the command exits having printed nothing.
242
+ overlay = tmp_path / "extra.json"
243
+ overlay.write_text(
244
+ json.dumps([{"category": "wild", "technique_name": "Fikir Fırtınası 🌪", "description": "Beyin fırtınası — 日本語"}]),
245
+ encoding="utf-8",
246
+ )
247
+ fake = _cp1252_stream()
248
+ monkeypatch.setattr(sys, "stdout", fake)
249
+ assert brain.main(["--file", str(lib), "--extra", str(overlay), "list", "--all"]) == 0
250
+ out = fake.buffer.getvalue().decode("utf-8")
251
+ assert "Fikir Fırtınası 🌪" in out
252
+ assert "日本語" in out
253
+
254
+
255
+ def test_missing_technique_name_reports_when_stderr_encoding_is_cp1252(lib, monkeypatch):
256
+ # `show` echoes the name it could not find; that name came from argv.
257
+ fake = _cp1252_stream()
258
+ monkeypatch.setattr(sys, "stderr", fake)
259
+ assert brain.main(["--file", str(lib), "show", "日本語"]) == 1
260
+ assert "日本語" in fake.buffer.getvalue().decode("utf-8")
261
+
262
+
263
+ def test_pin_utf8_preserves_the_streams_error_handler():
264
+ # reconfigure(encoding=...) on its own resets errors to "strict"; stderr on
265
+ # POSIX defaults to "backslashreplace" and must keep it, or a diagnostic
266
+ # carrying a surrogate-escaped path becomes a traceback.
267
+ stream = io.TextIOWrapper(io.BytesIO(), encoding="ascii", errors="backslashreplace")
268
+ brain.pin_utf8(stream)
269
+ assert stream.encoding == "utf-8"
270
+ assert stream.errors == "backslashreplace"
271
+
272
+
273
+ def test_pin_utf8_ignores_a_stream_without_reconfigure():
274
+ class Captured: # e.g. pytest's capture object, or a StringIO stand-in
275
+ errors = None
276
+
277
+ brain.pin_utf8(Captured()) # must not raise
278
+
279
+
230
280
  def test_shipped_selector_is_in_sync_with_catalog():
231
281
  # foolproofing: if someone edits brain-methods.csv they must regenerate the page.
232
282
  # Regenerate with: uv run brain.py html --out assets/brain-selector.html
@@ -87,7 +87,7 @@ Default by character (policy → team, personal → user), confirm before writin
87
87
  3. Write. Create `{project-root}/_bmad/custom/` if needed.
88
88
  4. Verify:
89
89
  ```
90
- uv run {project-root}/_bmad/scripts/resolve_customization.py --skill <install-path> --key <agent-or-workflow>
90
+ uv run {project-root}/_bmad/scripts/resolve_customization.py --skill <install-path> --project-root {project-root} --key <agent-or-workflow>
91
91
  ```
92
92
  Show the merged output, point out the changed fields.
93
93
 
@@ -37,7 +37,7 @@ Three services, freely combined — each detailed in its reference: **Draft** a
37
37
 
38
38
  **Forwarded activation:** if a caller invoked you with a stated intent, research type, or pre-resolved customization fields (the legacy research shims and Mary's menu do), honor them verbatim — skip your own inference for those values and resolve only the rest.
39
39
 
40
- 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow` (on failure read `{skill-root}/customize.toml`, use defaults). Run `{workflow.activation_steps_prepend}`, then `{workflow.activation_steps_append}`.
40
+ 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow` (on failure read `{skill-root}/customize.toml`, use defaults). Run `{workflow.activation_steps_prepend}`, then `{workflow.activation_steps_append}`.
41
41
  2. Resolve config: `uv run {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root}`. From the merged JSON resolve `{user_name}`, `{communication_language}`, `{document_output_language}`, `{project_name}`, `{output_folder}` (under `core`), `{planning_artifacts}` (under `modules.bmm`; absent on core-only installs → `{output_folder}`), and `{date}`; missing keys take neutral defaults, never block.
42
42
  3. Headless (no interactive user) → see `## Headless Mode`. Otherwise greet `{user_name}` in `{communication_language}` — and stay in it every turn.
43
43
  4. Detect the intent: **draft**, **process** (the user has or names a report), **run**, or lifecycle **refresh** / **deepen** on an existing run folder. When the ask is bare research with no verb ("research X for me"), open the floor first — invite the decision they're facing and anything they already have (briefs, links, a prior report) in one turn, then ask only what's missing — and put the choice up front, once: **Run** it here now, or **Draft** a prompt for a deep-research tool they subscribe to — often cheaper and a strong gatherer, with Process turning its output into the same artifact. State the trade honestly (tokens and minutes here vs. one manual round-trip there); their call, remembered for the session.
@@ -22,7 +22,7 @@ Lead by questioning, not lecturing. Ask one question at a time, press on weak po
22
22
 
23
23
  ## On Activation
24
24
 
25
- 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly with defaults. Apply the resolved `{workflow.*}` values throughout.
25
+ 1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly with defaults. Apply the resolved `{workflow.*}` values throughout.
26
26
  2. Run each `{workflow.activation_steps_prepend}` entry; treat each `{workflow.persistent_facts}` entry as foundational context (`file:` entries load their contents, `skill:` names a skill to consult, others are facts verbatim).
27
27
  3. Resolve central config: `uv run {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root} --key core`; from the merged JSON read `{user_name}`, `{communication_language}`, `{output_folder}`. On failure use neutral defaults; never block. Greet `{user_name}` in `{communication_language}` and stay in it.
28
28
  4. Note whether a BMad persona is already active in this conversation — the user loaded one (e.g. the analyst, the storyteller) and invoked the forge from within it. If so, that persona leads the session, in voice, throughout.
@@ -20,12 +20,11 @@ activation_steps_append = []
20
20
  # Persistent facts the interrogator keeps in mind for the whole session
21
21
  # (domain constraints, house rules, what's off the table). Each entry is a
22
22
  # literal sentence, a skill prefixed with `skill:`, or a `file:`-prefixed
23
- # path/glob whose contents are loaded as facts. Default loads project-context.md
24
- # when one exists (e.g. from bmad-generate-project-context), so the forge grounds
25
- # in the project's tech, domain, and constraints without re-asking.
26
- persistent_facts = [
27
- "file:{project-root}/**/project-context.md",
28
- ]
23
+ # path/glob whose contents are loaded as facts. Empty by default — repo-wide context
24
+ # belongs in AGENTS.md (see bmad-project-context), which every skill already sees. Use
25
+ # this for context only the forge needs, loaded on demand rather than carried as constant
26
+ # memory (e.g. `file:{project-root}/**/project-context.md` if you keep one).
27
+ persistent_facts = []
29
28
 
30
29
  # Executed when the session completes. Scalar or array of instructions. Empty for none.
31
30
  on_complete = []
@@ -110,7 +110,9 @@ def find_party_skill(project_root: Path, skill_root: Path):
110
110
  def load_party_workflow(project_root: Path, party_skill: Path):
111
111
  """Merged [workflow] table for bmad-party-mode (base + user overrides)."""
112
112
  resolver = project_root / "_bmad" / "scripts" / "resolve_customization.py"
113
- data = _run_json([sys.executable, str(resolver), "--skill", str(party_skill), "--key", "workflow"])
113
+ data = _run_json(
114
+ [sys.executable, str(resolver), "--skill", str(party_skill), "--project-root", str(project_root), "--key", "workflow"]
115
+ )
114
116
  if data is not None and isinstance(data.get("workflow"), dict):
115
117
  return data["workflow"]
116
118
  # Fallback: base customize.toml directly, no override merge.
@@ -5,6 +5,7 @@
5
5
  """Unit tests for resolve_personas.py — pool merge, alias, party resolution."""
6
6
 
7
7
  import sys
8
+ import tempfile
8
9
  import unittest
9
10
  from pathlib import Path
10
11
 
@@ -134,5 +135,26 @@ class TestOverrideMergeFallback(unittest.TestCase):
134
135
  self.assertEqual([m["code"] for m in wf["party_members"]], ["x", "y"]) # appended
135
136
 
136
137
 
138
+ class TestResolverInvocation(unittest.TestCase):
139
+ """The wrapper knows the project root, so it must not let the resolver
140
+ infer one from the working directory (#2796)."""
141
+
142
+ def _captured_command(self, tmp):
143
+ captured = []
144
+ original = rp._run_json
145
+ rp._run_json = lambda cmd: captured.append(cmd) or {"workflow": {}}
146
+ try:
147
+ rp.load_party_workflow(Path(tmp) / "project", Path(tmp) / "skill")
148
+ finally:
149
+ rp._run_json = original
150
+ return captured[0]
151
+
152
+ def test_passes_project_root_to_the_customization_resolver(self):
153
+ with tempfile.TemporaryDirectory() as tmp:
154
+ cmd = self._captured_command(tmp)
155
+ self.assertIn("--project-root", cmd)
156
+ self.assertEqual(cmd[cmd.index("--project-root") + 1], str(Path(tmp) / "project"))
157
+
158
+
137
159
  if __name__ == "__main__":
138
160
  unittest.main()
@@ -26,7 +26,7 @@ When this skill completes, the user should:
26
26
  - **Config**: Run `uv run {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root}` and use the merged JSON to resolve `output-location` variables and read `core.communication_language` and `modules.bmm.project_knowledge`. The resolver merges `_bmad/config.toml`, `_bmad/config.user.toml`, `_bmad/custom/config.toml`, and `_bmad/custom/config.user.toml` in that order.
27
27
  - **Artifacts**: Files matching `outputs` patterns at resolved `output-location` paths reveal which steps are possibly completed; their content may also provide grounding context for recommendations
28
28
  - **Project knowledge**: If `project_knowledge` resolves to an existing path, read it for grounding context. Never fabricate project-specific details.
29
- - **Module docs**: Rows with `_meta` in the `skill` column carry a URL or path in `output-location` pointing to the module's documentation (e.g., llms.txt). Fetch and use these to answer general questions about that module.
29
+ - **Module docs**: Rows with `_meta` in the `skill` column carry a URL or path in `output-location` pointing to the module's documentation. Fetch and use these to answer general questions about that module.
30
30
 
31
31
  ## CSV Interpretation
32
32
 
@@ -16,7 +16,7 @@ Run a round-table where these agents talk to each other and to the user like rea
16
16
 
17
17
  ## On Activation
18
18
 
19
- 1. **Resolve customization:** `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults. Then run each `{workflow.activation_steps_prepend}` entry, and hold each `{workflow.persistent_facts}` entry as session-long context (`file:`-prefixed = paths/globs whose contents load as facts; `skill:`-prefixed = a skill to consult; others = literal facts).
19
+ 1. **Resolve customization:** `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults. Then run each `{workflow.activation_steps_prepend}` entry, and hold each `{workflow.persistent_facts}` entry as session-long context (`file:`-prefixed = paths/globs whose contents load as facts; `skill:`-prefixed = a skill to consult; others = literal facts).
20
20
  2. **Resolve core config:** `uv run {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root}`. From the merged JSON's `core` table: greet with `{user_name}`, speak in `{communication_language}`, and resolve `{output_folder}`; `{date}` is today's date.
21
21
  3. **Detect intent and route.** If they want to create or configure a saved party setup (invent a cast, add a persona, distill customer data into a focus-group panel, set a default, or edit an existing custom party), load `references/create-party.md` and follow it. Otherwise run a party — continue below.
22
22
  4. **Resolve the roster:** `uv run {skill-root}/scripts/resolve_party.py --project-root {project-root} --skill {skill-root}`. It returns the active roster (`{workflow.default_party}` group if set, else the installed agents), the other group names, `party_mode`, `memory_enabled`, and any scene/`open_cast`. Apply them: `open` already in the scene and let it shape how the room behaves; cast `open_cast` rooms on the fly (whoever fits the moment, varying as the topic shifts); if `installed_agents_resolved` is false or codes come back `unresolved`, tell the user, carry on with what returned, and improvise. Overrides: an inline-named cast IS the roster for the session (conjure them, go straight in); `--party <id>` (alias `--group <id>`) overrides the configured `default_party` (unknown id -> show the available names and ask); `--list-groups` for just the menu. Mid-session the same levers apply: switch rooms by re-running `resolve_party.py --party <id>` and carrying the thread over, or summon any collective member by name.