bmad-method 6.3.1-next.9 → 6.4.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 (140) hide show
  1. package/package.json +3 -2
  2. package/src/bmm-skills/1-analysis/bmad-agent-analyst/SKILL.md +51 -36
  3. package/src/bmm-skills/1-analysis/bmad-agent-analyst/customize.toml +90 -0
  4. package/src/bmm-skills/1-analysis/bmad-agent-tech-writer/SKILL.md +50 -33
  5. package/src/bmm-skills/1-analysis/bmad-agent-tech-writer/customize.toml +81 -0
  6. package/src/bmm-skills/1-analysis/bmad-document-project/SKILL.md +57 -1
  7. package/src/bmm-skills/1-analysis/bmad-document-project/customize.toml +41 -0
  8. package/src/bmm-skills/1-analysis/bmad-document-project/workflows/deep-dive-instructions.md +1 -0
  9. package/src/bmm-skills/1-analysis/bmad-document-project/workflows/full-scan-instructions.md +1 -0
  10. package/src/bmm-skills/1-analysis/bmad-prfaq/SKILL.md +48 -9
  11. package/src/bmm-skills/1-analysis/bmad-prfaq/customize.toml +41 -0
  12. package/src/bmm-skills/1-analysis/bmad-prfaq/references/verdict.md +4 -0
  13. package/src/bmm-skills/1-analysis/bmad-product-brief/SKILL.md +44 -9
  14. package/src/bmm-skills/1-analysis/bmad-product-brief/customize.toml +47 -0
  15. package/src/bmm-skills/1-analysis/bmad-product-brief/prompts/contextual-discovery.md +8 -7
  16. package/src/bmm-skills/1-analysis/bmad-product-brief/prompts/draft-and-review.md +6 -5
  17. package/src/bmm-skills/1-analysis/bmad-product-brief/prompts/finalize.md +4 -1
  18. package/src/bmm-skills/1-analysis/bmad-product-brief/prompts/guided-elicitation.md +3 -2
  19. package/src/bmm-skills/1-analysis/research/bmad-domain-research/SKILL.md +91 -1
  20. package/src/bmm-skills/1-analysis/research/bmad-domain-research/customize.toml +41 -0
  21. package/src/bmm-skills/1-analysis/research/bmad-domain-research/domain-steps/step-06-research-synthesis.md +6 -0
  22. package/src/bmm-skills/1-analysis/research/bmad-market-research/SKILL.md +91 -1
  23. package/src/bmm-skills/1-analysis/research/bmad-market-research/customize.toml +41 -0
  24. package/src/bmm-skills/1-analysis/research/bmad-market-research/steps/step-06-research-completion.md +6 -0
  25. package/src/bmm-skills/1-analysis/research/bmad-technical-research/SKILL.md +91 -1
  26. package/src/bmm-skills/1-analysis/research/bmad-technical-research/customize.toml +41 -0
  27. package/src/bmm-skills/1-analysis/research/bmad-technical-research/technical-steps/step-06-research-synthesis.md +6 -0
  28. package/src/bmm-skills/2-plan-workflows/bmad-agent-pm/SKILL.md +50 -35
  29. package/src/bmm-skills/2-plan-workflows/bmad-agent-pm/customize.toml +85 -0
  30. package/src/bmm-skills/2-plan-workflows/bmad-agent-ux-designer/SKILL.md +50 -31
  31. package/src/bmm-skills/2-plan-workflows/bmad-agent-ux-designer/customize.toml +60 -0
  32. package/src/bmm-skills/2-plan-workflows/bmad-create-prd/SKILL.md +99 -1
  33. package/src/bmm-skills/2-plan-workflows/bmad-create-prd/customize.toml +41 -0
  34. package/src/bmm-skills/2-plan-workflows/bmad-create-prd/steps-c/step-12-complete.md +6 -0
  35. package/src/bmm-skills/2-plan-workflows/bmad-create-ux-design/SKILL.md +70 -1
  36. package/src/bmm-skills/2-plan-workflows/bmad-create-ux-design/customize.toml +41 -0
  37. package/src/bmm-skills/2-plan-workflows/bmad-create-ux-design/steps/step-14-complete.md +6 -0
  38. package/src/bmm-skills/2-plan-workflows/bmad-edit-prd/SKILL.md +97 -1
  39. package/src/bmm-skills/2-plan-workflows/bmad-edit-prd/customize.toml +42 -0
  40. package/src/bmm-skills/2-plan-workflows/bmad-edit-prd/steps-e/step-e-04-complete.md +2 -0
  41. package/src/bmm-skills/2-plan-workflows/bmad-validate-prd/SKILL.md +99 -1
  42. package/src/bmm-skills/2-plan-workflows/bmad-validate-prd/customize.toml +42 -0
  43. package/src/bmm-skills/2-plan-workflows/bmad-validate-prd/steps-v/step-v-13-report-complete.md +1 -0
  44. package/src/bmm-skills/3-solutioning/bmad-agent-architect/SKILL.md +50 -30
  45. package/src/bmm-skills/3-solutioning/bmad-agent-architect/customize.toml +65 -0
  46. package/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/SKILL.md +86 -1
  47. package/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/customize.toml +41 -0
  48. package/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/steps/step-06-final-assessment.md +6 -0
  49. package/src/bmm-skills/3-solutioning/bmad-create-architecture/SKILL.md +69 -1
  50. package/src/bmm-skills/3-solutioning/bmad-create-architecture/customize.toml +41 -0
  51. package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-08-complete.md +6 -0
  52. package/src/bmm-skills/3-solutioning/bmad-create-epics-and-stories/SKILL.md +88 -1
  53. package/src/bmm-skills/3-solutioning/bmad-create-epics-and-stories/customize.toml +41 -0
  54. package/src/bmm-skills/3-solutioning/bmad-create-epics-and-stories/steps/step-04-final-validation.md +6 -0
  55. package/src/bmm-skills/3-solutioning/bmad-generate-project-context/SKILL.md +76 -1
  56. package/src/bmm-skills/3-solutioning/bmad-generate-project-context/customize.toml +41 -0
  57. package/src/bmm-skills/3-solutioning/bmad-generate-project-context/steps/step-03-complete.md +6 -0
  58. package/src/bmm-skills/4-implementation/bmad-agent-dev/SKILL.md +48 -43
  59. package/src/bmm-skills/4-implementation/bmad-agent-dev/customize.toml +90 -0
  60. package/src/bmm-skills/4-implementation/bmad-checkpoint-preview/SKILL.md +46 -7
  61. package/src/bmm-skills/4-implementation/bmad-checkpoint-preview/customize.toml +41 -0
  62. package/src/bmm-skills/4-implementation/bmad-checkpoint-preview/step-05-wrapup.md +6 -0
  63. package/src/bmm-skills/4-implementation/bmad-code-review/SKILL.md +85 -1
  64. package/src/bmm-skills/4-implementation/bmad-code-review/customize.toml +41 -0
  65. package/src/bmm-skills/4-implementation/bmad-code-review/steps/step-04-present.md +6 -0
  66. package/src/bmm-skills/4-implementation/bmad-correct-course/SKILL.md +296 -1
  67. package/src/bmm-skills/4-implementation/bmad-correct-course/customize.toml +41 -0
  68. package/src/bmm-skills/4-implementation/bmad-create-story/SKILL.md +424 -1
  69. package/src/bmm-skills/4-implementation/bmad-create-story/customize.toml +41 -0
  70. package/src/bmm-skills/4-implementation/bmad-dev-story/SKILL.md +480 -1
  71. package/src/bmm-skills/4-implementation/bmad-dev-story/customize.toml +41 -0
  72. package/src/bmm-skills/4-implementation/bmad-qa-generate-e2e-tests/SKILL.md +171 -1
  73. package/src/bmm-skills/4-implementation/bmad-qa-generate-e2e-tests/customize.toml +41 -0
  74. package/src/bmm-skills/4-implementation/bmad-quick-dev/SKILL.md +106 -1
  75. package/src/bmm-skills/4-implementation/bmad-quick-dev/customize.toml +41 -0
  76. package/src/bmm-skills/4-implementation/bmad-quick-dev/step-05-present.md +6 -0
  77. package/src/bmm-skills/4-implementation/bmad-quick-dev/step-oneshot.md +6 -0
  78. package/src/bmm-skills/4-implementation/bmad-retrospective/SKILL.md +1507 -1
  79. package/src/bmm-skills/4-implementation/bmad-retrospective/customize.toml +41 -0
  80. package/src/bmm-skills/4-implementation/bmad-sprint-planning/SKILL.md +294 -1
  81. package/src/bmm-skills/4-implementation/bmad-sprint-planning/customize.toml +41 -0
  82. package/src/bmm-skills/4-implementation/bmad-sprint-status/SKILL.md +292 -1
  83. package/src/bmm-skills/4-implementation/bmad-sprint-status/customize.toml +41 -0
  84. package/src/bmm-skills/module.yaml +49 -0
  85. package/src/core-skills/bmad-advanced-elicitation/SKILL.md +7 -1
  86. package/src/core-skills/bmad-customize/SKILL.md +111 -0
  87. package/src/core-skills/bmad-customize/scripts/list_customizable_skills.py +231 -0
  88. package/src/core-skills/bmad-customize/scripts/tests/test_list_customizable_skills.py +249 -0
  89. package/src/core-skills/bmad-distillator/resources/distillate-format-reference.md +1 -1
  90. package/src/core-skills/bmad-party-mode/SKILL.md +13 -10
  91. package/src/core-skills/module-help.csv +1 -0
  92. package/src/core-skills/module.yaml +2 -0
  93. package/src/scripts/resolve_config.py +176 -0
  94. package/src/scripts/resolve_customization.py +230 -0
  95. package/tools/installer/commands/install.js +13 -0
  96. package/tools/installer/core/config.js +4 -1
  97. package/tools/installer/core/install-paths.js +11 -5
  98. package/tools/installer/core/installer.js +181 -94
  99. package/tools/installer/core/manifest-generator.js +339 -184
  100. package/tools/installer/core/manifest.js +86 -86
  101. package/tools/installer/ide/platform-codes.yaml +6 -0
  102. package/tools/installer/modules/channel-plan.js +203 -0
  103. package/tools/installer/modules/channel-resolver.js +241 -0
  104. package/tools/installer/modules/community-manager.js +130 -23
  105. package/tools/installer/modules/custom-module-manager.js +160 -19
  106. package/tools/installer/modules/external-manager.js +235 -32
  107. package/tools/installer/modules/official-modules.js +58 -12
  108. package/tools/installer/modules/registry-client.js +139 -7
  109. package/tools/installer/modules/registry-fallback.yaml +8 -0
  110. package/tools/installer/modules/version-resolver.js +336 -0
  111. package/tools/installer/project-root.js +54 -0
  112. package/tools/installer/ui.js +561 -50
  113. package/tools/platform-codes.yaml +6 -0
  114. package/src/bmm-skills/1-analysis/bmad-agent-analyst/bmad-skill-manifest.yaml +0 -11
  115. package/src/bmm-skills/1-analysis/bmad-agent-tech-writer/bmad-skill-manifest.yaml +0 -11
  116. package/src/bmm-skills/1-analysis/bmad-document-project/workflow.md +0 -25
  117. package/src/bmm-skills/1-analysis/research/bmad-domain-research/workflow.md +0 -51
  118. package/src/bmm-skills/1-analysis/research/bmad-market-research/workflow.md +0 -51
  119. package/src/bmm-skills/1-analysis/research/bmad-technical-research/workflow.md +0 -52
  120. package/src/bmm-skills/2-plan-workflows/bmad-agent-pm/bmad-skill-manifest.yaml +0 -11
  121. package/src/bmm-skills/2-plan-workflows/bmad-agent-ux-designer/bmad-skill-manifest.yaml +0 -11
  122. package/src/bmm-skills/2-plan-workflows/bmad-create-prd/workflow.md +0 -61
  123. package/src/bmm-skills/2-plan-workflows/bmad-create-ux-design/workflow.md +0 -35
  124. package/src/bmm-skills/2-plan-workflows/bmad-edit-prd/workflow.md +0 -62
  125. package/src/bmm-skills/2-plan-workflows/bmad-validate-prd/workflow.md +0 -61
  126. package/src/bmm-skills/3-solutioning/bmad-agent-architect/bmad-skill-manifest.yaml +0 -11
  127. package/src/bmm-skills/3-solutioning/bmad-check-implementation-readiness/workflow.md +0 -47
  128. package/src/bmm-skills/3-solutioning/bmad-create-architecture/workflow.md +0 -32
  129. package/src/bmm-skills/3-solutioning/bmad-create-epics-and-stories/workflow.md +0 -51
  130. package/src/bmm-skills/3-solutioning/bmad-generate-project-context/workflow.md +0 -39
  131. package/src/bmm-skills/4-implementation/bmad-agent-dev/bmad-skill-manifest.yaml +0 -11
  132. package/src/bmm-skills/4-implementation/bmad-code-review/workflow.md +0 -55
  133. package/src/bmm-skills/4-implementation/bmad-correct-course/workflow.md +0 -267
  134. package/src/bmm-skills/4-implementation/bmad-create-story/workflow.md +0 -380
  135. package/src/bmm-skills/4-implementation/bmad-dev-story/workflow.md +0 -450
  136. package/src/bmm-skills/4-implementation/bmad-qa-generate-e2e-tests/workflow.md +0 -136
  137. package/src/bmm-skills/4-implementation/bmad-quick-dev/workflow.md +0 -76
  138. package/src/bmm-skills/4-implementation/bmad-retrospective/workflow.md +0 -1479
  139. package/src/bmm-skills/4-implementation/bmad-sprint-planning/workflow.md +0 -263
  140. package/src/bmm-skills/4-implementation/bmad-sprint-status/workflow.md +0 -261
@@ -0,0 +1,41 @@
1
+ # DO NOT EDIT -- overwritten on every update.
2
+ #
3
+ # Workflow customization surface for bmad-sprint-status. Mirrors the
4
+ # agent customization shape under the [workflow] namespace.
5
+
6
+ [workflow]
7
+
8
+ # --- Configurable below. Overrides merge per BMad structural rules: ---
9
+ # scalars: override wins • arrays (persistent_facts, activation_steps_*): append
10
+ # arrays-of-tables with `code`/`id`: replace matching items, append new ones.
11
+
12
+ # Steps to run before the standard activation (config load, greet).
13
+ # Overrides append. Use for pre-flight loads, compliance checks, etc.
14
+
15
+ activation_steps_prepend = []
16
+
17
+ # Steps to run after greet but before the workflow begins.
18
+ # Overrides append. Use for context-heavy setup that should happen
19
+ # once the user has been acknowledged.
20
+
21
+ activation_steps_append = []
22
+
23
+ # Persistent facts the workflow keeps in mind for the whole run
24
+ # (standards, compliance constraints, stylistic guardrails).
25
+ # Distinct from the runtime memory sidecar — these are static context
26
+ # loaded on activation. Overrides append.
27
+ #
28
+ # Each entry is either:
29
+ # - a literal sentence, e.g. "All stories must include testable acceptance criteria."
30
+ # - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
31
+ # (glob patterns are supported; the file's contents are loaded and treated as facts).
32
+
33
+ persistent_facts = [
34
+ "file:{project-root}/**/project-context.md",
35
+ ]
36
+
37
+ # Scalar: executed when the workflow reaches its final step,
38
+ # after sprint status is summarized and risks are surfaced. Override wins.
39
+ # Leave empty for no custom post-completion behavior.
40
+
41
+ on_complete = ""
@@ -18,6 +18,7 @@ user_skill_level:
18
18
  prompt:
19
19
  - "What is your development experience level?"
20
20
  - "This affects how agents explain concepts in chat."
21
+ scope: user
21
22
  default: "intermediate"
22
23
  result: "{value}"
23
24
  single-select:
@@ -48,3 +49,51 @@ directories:
48
49
  - "{planning_artifacts}"
49
50
  - "{implementation_artifacts}"
50
51
  - "{project_knowledge}"
52
+
53
+ # Agent roster — essence only. External skills (party-mode, retrospective,
54
+ # advanced-elicitation, help catalog) read these descriptors to route, display,
55
+ # and embody agents. Full persona and behavior live in each agent's
56
+ # customize.toml. `team` defaults to the module code when omitted; users can
57
+ # add their own agents (real or fictional) via _bmad/custom/config.toml or _bmad/custom/config.user.toml.
58
+ agents:
59
+ - code: bmad-agent-analyst
60
+ name: Mary
61
+ title: Business Analyst
62
+ icon: "📊"
63
+ team: software-development
64
+ description: "Channels Porter's strategic rigor and Minto's Pyramid Principle, grounds every finding in verifiable evidence, represents every stakeholder voice. Speaks like a treasure hunter narrating the find: thrilled by every clue, precise once the pattern emerges."
65
+
66
+ - code: bmad-agent-tech-writer
67
+ name: Paige
68
+ title: Technical Writer
69
+ icon: "📚"
70
+ team: software-development
71
+ description: "Master of CommonMark, DITA, and OpenAPI; turns complex concepts into accessible structured docs, favors diagrams over walls of text, every word earning its place. Speaks like the patient teacher you wish you'd had, using analogies that make complex things feel simple."
72
+
73
+ - code: bmad-agent-pm
74
+ name: John
75
+ title: Product Manager
76
+ icon: "📋"
77
+ team: software-development
78
+ description: "Drives Jobs-to-be-Done over template filling, user value first, technical feasibility is a constraint not the driver. Speaks like a detective interrogating a cold case: short questions, sharper follow-ups, every 'why?' tightening the net."
79
+
80
+ - code: bmad-agent-ux-designer
81
+ name: Sally
82
+ title: UX Designer
83
+ icon: "🎨"
84
+ team: software-development
85
+ description: "Balances empathy with edge-case rigor, starts simple and evolves through feedback, every decision serves a genuine user need. Speaks like a filmmaker pitching the scene before the code exists, painting user stories that make you feel the problem."
86
+
87
+ - code: bmad-agent-architect
88
+ name: Winston
89
+ title: System Architect
90
+ icon: "🏗️"
91
+ team: software-development
92
+ description: "Favors boring technology for stability, developer productivity as architecture, ties every decision to business value. Speaks like a seasoned engineer at the whiteboard: measured, always laying out trade-offs rather than verdicts."
93
+
94
+ - code: bmad-agent-dev
95
+ name: Amelia
96
+ title: Senior Software Engineer
97
+ icon: "💻"
98
+ team: software-development
99
+ description: "Test-first discipline (red, green, refactor), 100% pass before review, no fluff all precision. Speaks like a terminal prompt: exact file paths, AC IDs, and commit-message brevity — every statement citable."
@@ -35,7 +35,13 @@ When invoked from another prompt or process:
35
35
 
36
36
  ### Step 1: Method Registry Loading
37
37
 
38
- **Action:** Load and read `./methods.csv` and '{project-root}/_bmad/_config/agent-manifest.csv'
38
+ **Action:** Load `./methods.csv` for elicitation methods. If party-mode may participate, resolve the agent roster via:
39
+
40
+ ```bash
41
+ python3 {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root} --key agents
42
+ ```
43
+
44
+ The resolver merges four layers in order: `_bmad/config.toml` (installer base, team-scoped), `_bmad/config.user.toml` (installer base, user-scoped), `_bmad/custom/config.toml` (team overrides), and `_bmad/custom/config.user.toml` (personal overrides). Each entry under `agents` is keyed by the agent's `code` and carries `name`, `title`, `icon`, `description`, `module`, and `team`.
39
45
 
40
46
  #### CSV Structure
41
47
 
@@ -0,0 +1,111 @@
1
+ ---
2
+ name: bmad-customize
3
+ description: Authors and updates customization overrides for installed BMad skills. Use when the user says 'customize bmad', 'override a skill', 'change agent behavior', or 'customize a workflow'.
4
+ ---
5
+
6
+ # BMad Customize
7
+
8
+ Translate the user's intent into a correctly-placed TOML override file under `{project-root}/_bmad/custom/` for a customizable agent or workflow skill. Discover, route, author, write, verify.
9
+
10
+ Scope v1: per-skill `[agent]` overrides (`bmad-agent-<role>.toml` / `.user.toml`) and per-skill `[workflow]` overrides (`bmad-<workflow>.toml` / `.user.toml`). Central config (`{project-root}/_bmad/custom/config.toml`) is out of scope — point users at the [How to Customize BMad guide](https://docs.bmad-method.org/how-to/customize-bmad/).
11
+
12
+ When the target's `customize.toml` doesn't expose what the user wants, say so plainly. Don't invent fields.
13
+
14
+ ## Preflight
15
+
16
+ - No `{project-root}/_bmad/` → BMad isn't installed. Say so, stop.
17
+ - `{project-root}/_bmad/scripts/resolve_customization.py` missing → continue, but Step 6 verify falls back to manual merge.
18
+ - Both present → proceed.
19
+
20
+ ## Activation
21
+
22
+ Load `_bmad/config.toml` and `_bmad/config.user.toml` from `{project-root}` for `user_name` (default `BMad`) and `communication_language` (default `English`). Greet. If the user's invocation already names a target skill AND a specific change, jump to Step 3.
23
+
24
+ ## Step 1: Classify intent
25
+
26
+ - **Directed** — specific skill + specific change → Step 3.
27
+ - **Exploratory** — "what can I customize?" → Step 2.
28
+ - **Audit/iterate** — wants to review or change something already customized → Step 2, lead with skills that have existing overrides; read the existing override in Step 3 before composing.
29
+ - **Cross-cutting** — could live on multiple surfaces → Step 3, choose agent vs workflow explicitly with the user.
30
+
31
+ ## Step 2: Discovery
32
+
33
+ ```
34
+ python3 {skill-root}/scripts/list_customizable_skills.py --project-root {project-root}
35
+ ```
36
+
37
+ Use `--extra-root <path>` (repeatable) if the user has skills installed in additional locations.
38
+
39
+ Group the returned `agents` and `workflows` for the user; for each show name, description, whether `has_team_override` or `has_user_override` is true. Surface any `errors[]`. For audit/iterate intents, lead with already-overridden entries.
40
+
41
+ Empty list: show `scanned_roots`, ask whether skills live elsewhere (offer `--extra-root`); otherwise stop.
42
+
43
+ ## Step 3: Determine the right surface
44
+
45
+ Read the target's `customize.toml`. Top-level `[agent]` or `[workflow]` block defines the surface.
46
+
47
+ If a team or user override already exists, read it first and summarize what's already overridden before composing.
48
+
49
+ **Cross-cutting intent — walk both surfaces with the user:**
50
+ - Every workflow a given agent runs → agent surface (e.g. `bmad-agent-pm.toml` with `persistent_facts`, `principles`).
51
+ - One workflow only → workflow surface (e.g. `bmad-create-prd.toml` with `activation_steps_prepend`).
52
+ - Several specific workflows → multiple workflow overrides in sequence, not an agent override.
53
+
54
+ **Single-surface heuristic:**
55
+ - Workflow-level: template swap, output path, step-specific behavior, or a named scalar already exposed (`*_template`, `on_complete`). Surgical, reliable.
56
+ - Agent-level: persona, communication style, org-wide facts, menu changes, behavior that should apply to every workflow the agent dispatches.
57
+
58
+ When ambiguous, present both with tradeoff, recommend one, let the user decide.
59
+
60
+ Intent outside the exposed surface (step logic, ordering, anything not in `customize.toml`): say so; offer `activation_steps_prepend`/`append` or `persistent_facts` as approximations, or recommend `bmad-builder` to create a custom skill.
61
+
62
+ ## Step 4: Compose the override
63
+
64
+ Translate plain-English into TOML against the target's `customize.toml` fields. If an existing override was read, frame the change as additive.
65
+
66
+ Merge semantics:
67
+ - **Scalars** (`icon`, `role`, `*_template`, `on_complete`) — override wins.
68
+ - **Append arrays** (`persistent_facts`, `activation_steps_prepend`/`append`, `principles`) — team/user entries append in order.
69
+ - **Keyed arrays of tables** (menu items with `code` or `id`) — matching keys replace, new keys append.
70
+
71
+ Overrides are sparse: only the fields being changed. Never copy the whole `customize.toml`.
72
+
73
+ **Template swap** (`*_template` scalar): offer to copy the default template to `{project-root}/_bmad/custom/{skill-name}-{purpose}-template.md`, point the override at the new path, offer to help edit it.
74
+
75
+ ## Step 5: Team or user placement
76
+
77
+ Under `{project-root}/_bmad/custom/`:
78
+ - `{skill-name}.toml` — team, committed. Policies, org conventions, compliance.
79
+ - `{skill-name}.user.toml` — user, gitignored. Personal tone, private facts, shortcuts.
80
+
81
+ Default by character (policy → team, personal → user), confirm before writing.
82
+
83
+ ## Step 6: Show, confirm, write, verify
84
+
85
+ 1. Show the full TOML. If the file exists, show a diff. Never silently overwrite.
86
+ 2. Wait for explicit yes.
87
+ 3. Write. Create `{project-root}/_bmad/custom/` if needed.
88
+ 4. Verify:
89
+ ```
90
+ python3 {project-root}/_bmad/scripts/resolve_customization.py --skill <install-path> --key <agent-or-workflow>
91
+ ```
92
+ Show the merged output, point out the changed fields.
93
+
94
+ **Resolver missing or fails:** read whichever layers exist — `<install-path>/customize.toml` (base), `{project-root}/_bmad/custom/{skill-name}.toml` (team), `{project-root}/_bmad/custom/{skill-name}.user.toml` (user) — apply base → team → user with the same merge rules (scalars override, tables deep-merge, `code`/`id`-keyed arrays merge by key, all other arrays append), describe how the changed fields resolve.
95
+
96
+ **Verify shows override didn't land** (field unchanged, merge conflict, file not picked up): re-enter Step 4 with the verify output as context. Usually wrong field name, wrong merge mode (scalar vs array), or wrong scope.
97
+ 5. Summarize what changed, where the file lives, how to iterate. Remind the user to commit team overrides.
98
+
99
+ ## Complete when
100
+
101
+ - Override file written (or user explicitly aborted).
102
+ - User has seen resolver output (or manual fallback merge summary).
103
+ - User has acknowledged the summary.
104
+
105
+ Otherwise the skill isn't done — finish or tell the user they're exiting incomplete.
106
+
107
+ ## When this skill can't help
108
+
109
+ - **Central config** (`{project-root}/_bmad/custom/config.toml`) — see the [How to Customize BMad guide](https://docs.bmad-method.org/how-to/customize-bmad/).
110
+ - **Step logic, ordering, behavior not in `customize.toml`** — open a feature request, or use `bmad-builder` to create a custom skill. Offer to help with either.
111
+ - **Skills without a `customize.toml`** — not customizable.
@@ -0,0 +1,231 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # requires-python = ">=3.11"
4
+ # ///
5
+ """Enumerate customizable BMad skills installed alongside this one.
6
+
7
+ Scans a skills directory (by default: the directory this script's own skill
8
+ lives in, derived from __file__), finds every sibling directory containing a
9
+ `customize.toml`, classifies each as agent and/or workflow based on its
10
+ top-level blocks, reads the skill's SKILL.md frontmatter description for a
11
+ one-liner, and checks whether override files already exist in
12
+ `{project-root}/_bmad/custom/`.
13
+
14
+ Skills in BMad are loaded either from a project-local location (e.g. the
15
+ project's `.claude/skills/` or `.cursor/skills/`) or from a user-global
16
+ location (e.g. `~/.claude/skills/`). We do not hardcode those paths — the
17
+ running skill's own location is the source of truth for sibling discovery.
18
+ `--extra-root` is available for the rare case where skills live in multiple
19
+ locations on the same machine.
20
+
21
+ Output: JSON to stdout. Non-empty `errors[]` in the payload is non-fatal
22
+ by contract — the scanner surfaces malformed TOML, missing roots, and
23
+ skills with no customization block as data for the caller to display,
24
+ and still exits 0. Exit 2 is reserved for invocation errors (e.g.
25
+ missing or unreadable `--project-root`) where no useful payload can be
26
+ produced.
27
+ """
28
+
29
+ from __future__ import annotations
30
+
31
+ import argparse
32
+ import json
33
+ import re
34
+ import sys
35
+ import tomllib
36
+ from pathlib import Path
37
+
38
+ # Top-level TOML blocks that indicate a customization surface.
39
+ SURFACE_KEYS = ("agent", "workflow")
40
+
41
+ FRONTMATTER_RE = re.compile(r"^---\s*\n(.*?)\n---\s*\n", re.DOTALL)
42
+
43
+
44
+ def default_skills_root() -> Path:
45
+ """Derive the skills root from this script's location.
46
+
47
+ Layout assumption: {skills_root}/bmad-customize/scripts/list_customizable_skills.py.
48
+ So the skills root is three parents up from this file.
49
+ """
50
+ return Path(__file__).resolve().parent.parent.parent
51
+
52
+
53
+ def read_frontmatter_description(skill_md: Path) -> str:
54
+ """Extract the `description:` value from a SKILL.md YAML frontmatter block.
55
+
56
+ Returns an empty string if the file is missing, unreadable, or has no
57
+ description field. Intentionally permissive — this is metadata for a
58
+ human-facing list, not a validation target.
59
+ """
60
+ if not skill_md.is_file():
61
+ return ""
62
+ try:
63
+ text = skill_md.read_text(encoding="utf-8")
64
+ except (OSError, UnicodeDecodeError):
65
+ return ""
66
+ m = FRONTMATTER_RE.match(text)
67
+ if not m:
68
+ return ""
69
+ for line in m.group(1).splitlines():
70
+ stripped = line.strip()
71
+ if stripped.startswith("description:"):
72
+ value = stripped[len("description:") :].strip()
73
+ # Strip surrounding quotes if present.
74
+ if (value.startswith("'") and value.endswith("'")) or (
75
+ value.startswith('"') and value.endswith('"')
76
+ ):
77
+ value = value[1:-1]
78
+ return value
79
+ return ""
80
+
81
+
82
+ def load_customize(toml_path: Path) -> dict | None:
83
+ """Return the parsed TOML, or None if unreadable."""
84
+ try:
85
+ with toml_path.open("rb") as f:
86
+ return tomllib.load(f)
87
+ except (OSError, tomllib.TOMLDecodeError):
88
+ return None
89
+
90
+
91
+ def scan_skills(
92
+ skills_roots: list[Path],
93
+ project_root: Path,
94
+ ) -> dict:
95
+ """Scan each skills root for directories that contain a customize.toml."""
96
+ agents: list[dict] = []
97
+ workflows: list[dict] = []
98
+ errors: list[str] = []
99
+ scanned_roots: list[str] = []
100
+ seen_names: set[str] = set()
101
+ custom_dir = project_root / "_bmad" / "custom"
102
+
103
+ for root in skills_roots:
104
+ if not root.is_dir():
105
+ errors.append(f"skills root does not exist: {root}")
106
+ continue
107
+ scanned_roots.append(str(root))
108
+
109
+ for skill_dir in sorted(p for p in root.iterdir() if p.is_dir()):
110
+ customize_toml = skill_dir / "customize.toml"
111
+ if not customize_toml.is_file():
112
+ continue
113
+
114
+ data = load_customize(customize_toml)
115
+ if data is None:
116
+ errors.append(f"failed to parse {customize_toml}")
117
+ continue
118
+
119
+ skill_name = skill_dir.name
120
+ # If a skill with this name was already found in an earlier
121
+ # root, skip it — roots are scanned in the order provided, so
122
+ # the first occurrence wins.
123
+ if skill_name in seen_names:
124
+ continue
125
+ seen_names.add(skill_name)
126
+
127
+ description = read_frontmatter_description(skill_dir / "SKILL.md")
128
+ team_override = custom_dir / f"{skill_name}.toml"
129
+ user_override = custom_dir / f"{skill_name}.user.toml"
130
+
131
+ entry_base = {
132
+ "name": skill_name,
133
+ "install_path": str(skill_dir),
134
+ "skills_root": str(root),
135
+ "description": description,
136
+ "has_team_override": team_override.is_file(),
137
+ "has_user_override": user_override.is_file(),
138
+ "team_override_path": str(team_override),
139
+ "user_override_path": str(user_override),
140
+ }
141
+
142
+ # A skill may expose an agent surface, a workflow surface, or
143
+ # both. Emit one entry per surface so the caller can group cleanly.
144
+ surfaces_found = [k for k in SURFACE_KEYS if k in data]
145
+ if not surfaces_found:
146
+ errors.append(
147
+ f"no [agent] or [workflow] block in {customize_toml}"
148
+ )
149
+ continue
150
+ for surface in surfaces_found:
151
+ entry = dict(entry_base)
152
+ entry["surface"] = surface
153
+ if surface == "agent":
154
+ agents.append(entry)
155
+ else:
156
+ workflows.append(entry)
157
+
158
+ return {
159
+ "project_root": str(project_root),
160
+ "scanned_roots": scanned_roots,
161
+ "custom_dir": str(custom_dir),
162
+ "agents": agents,
163
+ "workflows": workflows,
164
+ "errors": errors,
165
+ }
166
+
167
+
168
+ def parse_args(argv: list[str]) -> argparse.Namespace:
169
+ parser = argparse.ArgumentParser(
170
+ description=(
171
+ "List customizable BMad skills installed alongside this one, "
172
+ "grouped by surface (agent vs workflow), with override status "
173
+ "looked up against {project-root}/_bmad/custom/."
174
+ )
175
+ )
176
+ parser.add_argument(
177
+ "--project-root",
178
+ required=True,
179
+ help="Absolute path to the project root (the folder containing _bmad/).",
180
+ )
181
+ parser.add_argument(
182
+ "--skills-root",
183
+ default=None,
184
+ help=(
185
+ "Override the primary skills directory to scan. Defaults to the "
186
+ "directory this script's own skill lives in."
187
+ ),
188
+ )
189
+ parser.add_argument(
190
+ "--extra-root",
191
+ action="append",
192
+ default=[],
193
+ metavar="PATH",
194
+ help=(
195
+ "Additional skills directory to include (repeatable). Useful "
196
+ "when skills live in multiple locations on the same machine "
197
+ "(e.g. project-local plus a user-global install)."
198
+ ),
199
+ )
200
+ return parser.parse_args(argv)
201
+
202
+
203
+ def main(argv: list[str]) -> int:
204
+ args = parse_args(argv)
205
+ project_root = Path(args.project_root).expanduser().resolve()
206
+ if not project_root.is_dir():
207
+ print(
208
+ f"error: project-root does not exist or is not a directory: {project_root}",
209
+ file=sys.stderr,
210
+ )
211
+ return 2
212
+
213
+ primary = (
214
+ Path(args.skills_root).expanduser().resolve()
215
+ if args.skills_root
216
+ else default_skills_root()
217
+ )
218
+ extras = [Path(p).expanduser().resolve() for p in args.extra_root]
219
+ # Deduplicate in order of appearance.
220
+ roots: list[Path] = []
221
+ for root in [primary, *extras]:
222
+ if root not in roots:
223
+ roots.append(root)
224
+
225
+ result = scan_skills(roots, project_root)
226
+ print(json.dumps(result, indent=2, sort_keys=True))
227
+ return 0
228
+
229
+
230
+ if __name__ == "__main__":
231
+ sys.exit(main(sys.argv[1:]))