bmad-method 6.0.2 → 6.0.4

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 (73) hide show
  1. package/.claude/skills/bmad-os-root-cause-analysis/SKILL.md +12 -0
  2. package/.claude/skills/bmad-os-root-cause-analysis/prompts/instructions.md +74 -0
  3. package/.github/ISSUE_TEMPLATE/config.yaml +1 -1
  4. package/.github/ISSUE_TEMPLATE/documentation.yaml +1 -1
  5. package/CHANGELOG.md +40 -0
  6. package/README.md +8 -8
  7. package/docs/index.md +1 -1
  8. package/package.json +1 -1
  9. package/src/bmm/agents/qa.agent.yaml +1 -1
  10. package/src/bmm/module-help.csv +1 -1
  11. package/src/bmm/workflows/1-analysis/create-product-brief/steps/step-06-complete.md +1 -1
  12. package/src/bmm/workflows/1-analysis/create-product-brief/workflow.md +1 -1
  13. package/src/bmm/workflows/1-analysis/research/workflow-domain-research.md +1 -1
  14. package/src/bmm/workflows/1-analysis/research/workflow-market-research.md +1 -1
  15. package/src/bmm/workflows/1-analysis/research/workflow-technical-research.md +1 -1
  16. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-12-complete.md +1 -1
  17. package/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-13-report-complete.md +1 -1
  18. package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-create-prd.md +1 -1
  19. package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-edit-prd.md +1 -1
  20. package/src/bmm/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md +1 -1
  21. package/src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-14-complete.md +1 -1
  22. package/src/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md +1 -1
  23. package/src/bmm/workflows/3-solutioning/check-implementation-readiness/steps/step-06-final-assessment.md +1 -1
  24. package/src/bmm/workflows/3-solutioning/check-implementation-readiness/workflow.md +1 -1
  25. package/src/bmm/workflows/3-solutioning/create-architecture/steps/step-08-complete.md +1 -1
  26. package/src/bmm/workflows/3-solutioning/create-architecture/workflow.md +1 -1
  27. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-04-final-validation.md +1 -1
  28. package/src/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md +1 -1
  29. package/src/bmm/workflows/4-implementation/code-review/workflow.yaml +1 -1
  30. package/src/bmm/workflows/4-implementation/correct-course/workflow.yaml +1 -1
  31. package/src/bmm/workflows/4-implementation/create-story/workflow.yaml +1 -1
  32. package/src/bmm/workflows/4-implementation/dev-story/workflow.yaml +1 -1
  33. package/src/bmm/workflows/4-implementation/retrospective/workflow.yaml +1 -1
  34. package/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +1 -1
  35. package/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml +1 -1
  36. package/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +1 -1
  37. package/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +1 -1
  38. package/src/bmm/workflows/document-project/workflow.yaml +1 -1
  39. package/src/bmm/workflows/generate-project-context/workflow.md +1 -1
  40. package/src/bmm/workflows/qa-generate-e2e-tests/workflow.yaml +2 -2
  41. package/src/core/module-help.csv +1 -0
  42. package/src/core/tasks/editorial-review-prose.xml +1 -1
  43. package/src/core/tasks/editorial-review-structure.xml +1 -1
  44. package/src/core/tasks/help.md +1 -1
  45. package/src/core/tasks/index-docs.xml +1 -1
  46. package/src/core/tasks/review-adversarial-general.xml +1 -1
  47. package/src/core/tasks/review-edge-case-hunter.xml +63 -0
  48. package/src/core/tasks/shard-doc.xml +1 -1
  49. package/src/core/workflows/advanced-elicitation/workflow.xml +1 -1
  50. package/src/core/workflows/brainstorming/steps/step-01-session-setup.md +31 -18
  51. package/src/core/workflows/brainstorming/steps/step-01b-continue.md +1 -1
  52. package/src/core/workflows/brainstorming/steps/step-03-technique-execution.md +2 -2
  53. package/src/core/workflows/brainstorming/steps/step-04-idea-organization.md +2 -2
  54. package/src/core/workflows/brainstorming/workflow.md +4 -2
  55. package/src/core/workflows/party-mode/workflow.md +1 -1
  56. package/test/test-installation-components.js +1 -1
  57. package/tools/cli/installers/install-messages.yaml +1 -1
  58. package/tools/cli/installers/lib/core/manifest-generator.js +4 -6
  59. package/tools/cli/installers/lib/ide/_config-driven.js +80 -5
  60. package/tools/cli/installers/lib/ide/manager.js +3 -1
  61. package/tools/cli/installers/lib/ide/platform-codes.yaml +11 -2
  62. package/tools/cli/installers/lib/ide/templates/agent-command-template.md +1 -1
  63. package/tools/cli/installers/lib/ide/templates/combined/default-workflow-yaml.md +3 -3
  64. package/tools/cli/installers/lib/ide/templates/combined/default-workflow.md +1 -1
  65. package/tools/cli/installers/lib/ide/templates/combined/gemini-workflow-yaml.toml +1 -1
  66. package/tools/cli/installers/lib/ide/templates/combined/gemini-workflow.toml +1 -1
  67. package/tools/cli/installers/lib/ide/templates/combined/opencode-agent.md +1 -1
  68. package/tools/cli/installers/lib/ide/templates/combined/opencode-task.md +0 -1
  69. package/tools/cli/installers/lib/ide/templates/combined/opencode-tool.md +0 -1
  70. package/tools/cli/installers/lib/ide/templates/combined/opencode-workflow-yaml.md +0 -1
  71. package/tools/cli/installers/lib/ide/templates/combined/opencode-workflow.md +0 -1
  72. package/tools/cli/installers/lib/ide/templates/workflow-command-template.md +2 -2
  73. package/tools/cli/installers/lib/ide/templates/workflow-commander.md +1 -1
@@ -0,0 +1,63 @@
1
+ <!-- if possible, run this in a separate subagent or process with read access to the project,
2
+ but no context except the content to review -->
3
+
4
+ <task id="_bmad/core/tasks/review-edge-case-hunter.xml" name="Edge Case Hunter Review"
5
+ description="Walk every branching path and boundary condition in content, report only unhandled edge cases. Orthogonal to adversarial review - method-driven not attitude-driven.">
6
+ <objective>You are a pure path tracer. Never comment on whether code is good or bad; only list missing handling.
7
+ When a diff is provided, scan only the diff hunks and list boundaries that are directly reachable from the changed lines and lack an explicit guard in the diff.
8
+ When no diff is provided (full file or function), treat the entire provided content as the scope.
9
+ Ignore the rest of the codebase unless the provided content explicitly references external functions.</objective>
10
+
11
+ <inputs>
12
+ <input name="content" desc="Content to review - diff, full file, or function" />
13
+ <input name="also_consider" required="false"
14
+ desc="Optional areas to keep in mind during review alongside normal edge-case analysis" />
15
+ </inputs>
16
+
17
+ <output-format>Return ONLY a valid JSON array of objects. Each object must contain exactly these four fields and nothing else:
18
+ {
19
+ "location": "file:line",
20
+ "trigger_condition": "one-line description (max 15 words)",
21
+ "guard_snippet": "minimal code sketch that closes the gap",
22
+ "potential_consequence": "what could actually go wrong (max 15 words)"
23
+ }
24
+ No extra text, no explanations, no markdown wrapping.</output-format>
25
+
26
+ <llm critical="true">
27
+ <i>MANDATORY: Execute ALL steps in the flow section IN EXACT ORDER</i>
28
+ <i>DO NOT skip steps or change the sequence</i>
29
+ <i>HALT immediately when halt-conditions are met</i>
30
+ <i>Each action xml tag within step xml tag is a REQUIRED action to complete that step</i>
31
+
32
+ <i>Your method is exhaustive path enumeration — mechanically walk every branch, not hunt by intuition</i>
33
+ <i>Trace each branching path: conditionals, switches, early returns, guard clauses, loops, error handlers</i>
34
+ <i>Trace each boundary condition: null, undefined, empty, zero, negative, overflow, max-length, type coercion, concurrency, timing</i>
35
+ <i>Report ONLY paths and conditions that lack handling — discard handled ones silently</i>
36
+ <i>Do NOT editorialize or add filler — findings only</i>
37
+ </llm>
38
+
39
+ <flow>
40
+ <step n="1" title="Receive Content">
41
+ <action>Load the content to review from provided input or context</action>
42
+ <action>If content to review is empty, ask for clarification and abort task</action>
43
+ <action>Identify content type (diff, full file, or function) to determine scope rules</action>
44
+ </step>
45
+
46
+ <step n="2" title="Exhaustive Path Analysis" critical="true">
47
+ <mandate>Walk every branching path and boundary condition within scope - report only unhandled ones</mandate>
48
+ <action>If also_consider input was provided, incorporate those areas into the analysis</action>
49
+ <action>Enumerate all branching paths and boundary conditions within scope: conditionals, switches, early returns, guard clauses, loops, error handlers, null/empty states, overflow, type edges, concurrency, timing</action>
50
+ <action>For each path: determine whether the content handles it</action>
51
+ <action>Collect only the unhandled paths as findings - discard handled ones silently</action>
52
+ </step>
53
+
54
+ <step n="3" title="Present Findings">
55
+ <action>Output findings as a JSON array following the output-format specification exactly</action>
56
+ </step>
57
+ </flow>
58
+
59
+ <halt-conditions>
60
+ <condition>HALT if content is empty or unreadable</condition>
61
+ </halt-conditions>
62
+
63
+ </task>
@@ -1,5 +1,5 @@
1
1
  <task id="_bmad/core/tasks/shard-doc" name="Shard Document"
2
- description="Splits large markdown documents into smaller, organized files based on level 2 (default) sections. Use if the user says 'Shard Document [document]'">
2
+ description="Splits large markdown documents into smaller, organized files based on level 2 (default) sections. Use if the user says perform shard document">
3
3
  <objective>Split large markdown documents into smaller, organized files based on level 2 sections using @kayvan/markdown-tree-parser tool</objective>
4
4
 
5
5
  <llm critical="true">
@@ -1,5 +1,5 @@
1
1
  <task id="_bmad/core/workflows/advanced-elicitation/workflow.xml" name="Advanced Elicitation"
2
- description="Push the LLM to reconsider refine and improve its recent output. Use when the user asks for 'advanced elicitation'"
2
+ description="Push the LLM to reconsider refine and improve its recent output. Use when the user asks for advanced elicitation"
3
3
  methods="{project-root}/_bmad/core/workflows/advanced-elicitation/methods.csv"
4
4
  agent-party="{project-root}/_bmad/_config/agent-manifest.csv">
5
5
  <llm critical="true">
@@ -29,23 +29,30 @@ Initialize the brainstorming workflow by detecting continuation state and settin
29
29
 
30
30
  ## INITIALIZATION SEQUENCE:
31
31
 
32
- ### 1. Check for Existing Workflow
32
+ ### 1. Check for Existing Sessions
33
33
 
34
- First, check if the output document already exists:
34
+ First, check the brainstorming sessions folder for existing sessions:
35
35
 
36
- - Look for file at `{output_folder}/brainstorming/brainstorming-session-{{date}}.md`
37
- - If exists, read the complete file including frontmatter
38
- - If not exists, this is a fresh workflow
36
+ - List all files in `{output_folder}/brainstorming/`
37
+ - **DO NOT read any file contents** - only list filenames
38
+ - If files exist, identify the most recent by date/time in the filename
39
+ - If no files exist, this is a fresh workflow
39
40
 
40
- ### 2. Handle Continuation (If Document Exists)
41
+ ### 2. Handle Existing Sessions (If Files Found)
41
42
 
42
- If the document exists and has frontmatter with `stepsCompleted`:
43
+ If existing session files are found:
43
44
 
44
- - **STOP here** and load `./step-01b-continue.md` immediately
45
- - Do not proceed with any initialization tasks
46
- - Let step-01b handle the continuation logic
45
+ - Display the most recent session filename (do NOT read its content)
46
+ - Ask the user: "Found existing session: `[filename]`. Would you like to:
47
+ **[1]** Continue this session
48
+ **[2]** Start a new session
49
+ **[3]** See all existing sessions"
47
50
 
48
- ### 3. Fresh Workflow Setup (If No Document)
51
+ - If user selects **[1]** (continue): Set `{brainstorming_session_output_file}` to that file path and load `./step-01b-continue.md`
52
+ - If user selects **[2]** (new): Generate new filename with current date/time and proceed to step 3
53
+ - If user selects **[3]** (see all): List all session filenames and ask which to continue or if new
54
+
55
+ ### 3. Fresh Workflow Setup (If No Files or User Chooses New)
49
56
 
50
57
  If no document exists or no `stepsCompleted` in frontmatter:
51
58
 
@@ -55,10 +62,10 @@ Create the brainstorming session document:
55
62
 
56
63
  ```bash
57
64
  # Create directory if needed
58
- mkdir -p "$(dirname "{output_folder}/brainstorming/brainstorming-session-{{date}}.md")"
65
+ mkdir -p "$(dirname "{brainstorming_session_output_file}")"
59
66
 
60
67
  # Initialize from template
61
- cp "{template_path}" "{output_folder}/brainstorming/brainstorming-session-{{date}}.md"
68
+ cp "{template_path}" "{brainstorming_session_output_file}"
62
69
  ```
63
70
 
64
71
  #### B. Context File Check and Loading
@@ -134,7 +141,7 @@ _[Content based on conversation about session parameters and facilitator approac
134
141
 
135
142
  ## APPEND TO DOCUMENT:
136
143
 
137
- When user selects approach, append the session overview content directly to `{output_folder}/brainstorming/brainstorming-session-{{date}}.md` using the structure from above.
144
+ When user selects approach, append the session overview content directly to `{brainstorming_session_output_file}` using the structure from above.
138
145
 
139
146
  ### E. Continue to Technique Selection
140
147
 
@@ -152,7 +159,7 @@ Which approach appeals to you most? (Enter 1-4)"
152
159
 
153
160
  #### When user selects approach number:
154
161
 
155
- - **Append initial session overview to `{output_folder}/brainstorming/brainstorming-session-{{date}}.md`**
162
+ - **Append initial session overview to `{brainstorming_session_output_file}`**
156
163
  - **Update frontmatter:** `stepsCompleted: [1]`, `selected_approach: '[selected approach]'`
157
164
  - **Load the appropriate step-02 file** based on selection
158
165
 
@@ -167,7 +174,9 @@ After user selects approach number:
167
174
 
168
175
  ## SUCCESS METRICS:
169
176
 
170
- ✅ Existing workflow detected and continuation handled properly
177
+ ✅ Existing sessions detected without reading file contents
178
+ ✅ User prompted to continue existing session or start new
179
+ ✅ Correct session file selected for continuation
171
180
  ✅ Fresh workflow initialized with correct document structure
172
181
  ✅ Session context gathered and understood clearly
173
182
  ✅ User's approach selection captured and routed correctly
@@ -176,7 +185,9 @@ After user selects approach number:
176
185
 
177
186
  ## FAILURE MODES:
178
187
 
179
- Not checking for existing document before creating new one
188
+ Reading file contents during session detection (wastes context)
189
+ ❌ Not asking user before continuing existing session
190
+ ❌ Not properly routing user's continue/new session selection
180
191
  ❌ Missing continuation detection leading to duplicate work
181
192
  ❌ Insufficient session context gathering
182
193
  ❌ Not properly routing user's approach selection
@@ -184,7 +195,9 @@ After user selects approach number:
184
195
 
185
196
  ## SESSION SETUP PROTOCOLS:
186
197
 
187
- - Always verify document existence before initialization
198
+ - Always list sessions folder WITHOUT reading file contents
199
+ - Ask user before continuing any existing session
200
+ - Only load continue step after user confirms
188
201
  - Load brain techniques CSV only when needed for technique presentation
189
202
  - Use collaborative facilitation language throughout
190
203
  - Maintain psychological safety for creative exploration
@@ -35,7 +35,7 @@ Load existing document and analyze current state:
35
35
 
36
36
  **Document Analysis:**
37
37
 
38
- - Read existing `{output_folder}/brainstorming/brainstorming-session-{{date}}.md`
38
+ - Read existing `{brainstorming_session_output_file}`
39
39
  - Examine frontmatter for `stepsCompleted`, `session_topic`, `session_goals`
40
40
  - Review content to understand session progress and outcomes
41
41
  - Identify current stage and next logical steps
@@ -296,7 +296,7 @@ After final technique element:
296
296
 
297
297
  #### If 'C' (Move to organization):
298
298
 
299
- - **Append the technique execution content to `{output_folder}/brainstorming/brainstorming-session-{{date}}.md`**
299
+ - **Append the technique execution content to `{brainstorming_session_output_file}`**
300
300
  - **Update frontmatter:** `stepsCompleted: [1, 2, 3]`
301
301
  - **Load:** `./step-04-idea-organization.md`
302
302
 
@@ -356,7 +356,7 @@ _[Short narrative describing the user and AI collaboration journey - what made t
356
356
 
357
357
  ## APPEND TO DOCUMENT:
358
358
 
359
- When user selects 'C', append the content directly to `{output_folder}/brainstorming/brainstorming-session-{{date}}.md` using the structure from above.
359
+ When user selects 'C', append the content directly to `{brainstorming_session_output_file}` using the structure from above.
360
360
 
361
361
  ## SUCCESS METRICS:
362
362
 
@@ -253,14 +253,14 @@ Provide final session wrap-up and forward guidance:
253
253
 
254
254
  #### If [C] Complete:
255
255
 
256
- - **Append the final session content to `{output_folder}/brainstorming/brainstorming-session-{{date}}.md`**
256
+ - **Append the final session content to `{brainstorming_session_output_file}`**
257
257
  - Update frontmatter: `stepsCompleted: [1, 2, 3, 4]`
258
258
  - Set `session_active: false` and `workflow_completed: true`
259
259
  - Complete workflow with positive closure message
260
260
 
261
261
  ## APPEND TO DOCUMENT:
262
262
 
263
- When user selects 'C', append the content directly to `{output_folder}/brainstorming/brainstorming-session-{{date}}.md` using the structure from step 7.
263
+ When user selects 'C', append the content directly to `{brainstorming_session_output_file}` using the structure from step 7.
264
264
 
265
265
  ## SUCCESS METRICS:
266
266
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: brainstorming
3
- description: "Facilitate interactive brainstorming sessions using diverse creative techniques and ideation methods. Use when the user says 'help me brainstorm' or 'help me ideate'."
3
+ description: 'Facilitate interactive brainstorming sessions using diverse creative techniques and ideation methods. Use when the user says help me brainstorm or help me ideate.'
4
4
  context_file: '' # Optional context file path for project-specific guidance
5
5
  ---
6
6
 
@@ -45,7 +45,9 @@ Load config from `{project-root}/_bmad/core/config.yaml` and resolve:
45
45
  - `installed_path` = `{project-root}/_bmad/core/workflows/brainstorming`
46
46
  - `template_path` = `{installed_path}/template.md`
47
47
  - `brain_techniques_path` = `{installed_path}/brain-methods.csv`
48
- - `default_output_file` = `{output_folder}/brainstorming/brainstorming-session-{{date}}.md`
48
+ - `brainstorming_session_output_file` = `{output_folder}/brainstorming/brainstorming-session-{{date}}-{{time}}.md` (evaluated once at workflow start)
49
+
50
+ All steps MUST reference `{brainstorming_session_output_file}` instead of the full path pattern.
49
51
  - `context_file` = Optional context file path from workflow invocation for project-specific guidance
50
52
  - `advancedElicitationTask` = `{project-root}/_bmad/core/workflows/advanced-elicitation/workflow.xml`
51
53
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: party-mode
3
- description: "Orchestrates group discussions between all installed BMAD agents, enabling natural multi-agent conversations. Use when user requests 'party mode' only."
3
+ description: 'Orchestrates group discussions between all installed BMAD agents, enabling natural multi-agent conversations. Use when user requests party mode.'
4
4
  ---
5
5
 
6
6
  # Party Mode Workflow
@@ -173,7 +173,7 @@ async function runTests() {
173
173
 
174
174
  assert(compiled.includes('QA Engineer'), 'QA agent compilation includes agent title');
175
175
 
176
- assert(compiled.includes('qa/automate'), 'QA agent menu includes automate workflow');
176
+ assert(compiled.includes('qa-generate-e2e-tests'), 'QA agent menu includes automate workflow');
177
177
 
178
178
  // Cleanup
179
179
  await fs.remove(tempOutput);
@@ -12,7 +12,7 @@ startMessage: |
12
12
  - Select and install modules during setup - customize your experience
13
13
  - New BMad Method for Agile AI-Driven Development (the evolution of V4)
14
14
  - Exciting new modules available during installation, with community modules coming soon
15
- - Documentation: docs.bmad-method.com
15
+ - Documentation: https://docs.bmad-method.org
16
16
 
17
17
  🌟 BMad is 100% free and open source.
18
18
  - No gated Discord. No paywalls. No gated content.
@@ -24,16 +24,14 @@ class ManifestGenerator {
24
24
  }
25
25
 
26
26
  /**
27
- * Clean text for CSV output by normalizing whitespace and escaping quotes
27
+ * Clean text for CSV output by normalizing whitespace.
28
+ * Note: Quote escaping is handled by escapeCsv() at write time.
28
29
  * @param {string} text - Text to clean
29
- * @returns {string} Cleaned text safe for CSV
30
+ * @returns {string} Cleaned text
30
31
  */
31
32
  cleanForCSV(text) {
32
33
  if (!text) return '';
33
- return text
34
- .trim()
35
- .replaceAll(/\s+/g, ' ') // Normalize all whitespace (including newlines) to single space
36
- .replaceAll('"', '""'); // Escape quotes for CSV
34
+ return text.trim().replaceAll(/\s+/g, ' '); // Normalize all whitespace (including newlines) to single space
37
35
  }
38
36
 
39
37
  /**
@@ -34,6 +34,25 @@ class ConfigDrivenIdeSetup extends BaseIdeSetup {
34
34
  * @returns {Promise<Object>} Setup result
35
35
  */
36
36
  async setup(projectDir, bmadDir, options = {}) {
37
+ // Check for BMAD files in ancestor directories that would cause duplicates
38
+ if (this.installerConfig?.ancestor_conflict_check) {
39
+ const conflict = await this.findAncestorConflict(projectDir);
40
+ if (conflict) {
41
+ await prompts.log.error(
42
+ `Found existing BMAD commands in ancestor installation: ${conflict}\n` +
43
+ ` ${this.name} inherits commands from parent directories, so this would cause duplicates.\n` +
44
+ ` Please remove the BMAD files from that directory first:\n` +
45
+ ` rm -rf "${conflict}"/bmad*`,
46
+ );
47
+ return {
48
+ success: false,
49
+ reason: 'ancestor-conflict',
50
+ error: `Ancestor conflict: ${conflict}`,
51
+ conflictDir: conflict,
52
+ };
53
+ }
54
+ }
55
+
37
56
  if (!options.silent) await prompts.log.info(`Setting up ${this.name}...`);
38
57
 
39
58
  // Clean up any old BMAD installation first
@@ -453,6 +472,15 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
453
472
  * @param {string} projectDir - Project directory
454
473
  */
455
474
  async cleanup(projectDir, options = {}) {
475
+ // Migrate legacy target directories (e.g. .opencode/agent → .opencode/agents)
476
+ if (this.installerConfig?.legacy_targets) {
477
+ if (!options.silent) await prompts.log.message(' Migrating legacy directories...');
478
+ for (const legacyDir of this.installerConfig.legacy_targets) {
479
+ await this.cleanupTarget(projectDir, legacyDir, options);
480
+ await this.removeEmptyParents(projectDir, legacyDir);
481
+ }
482
+ }
483
+
456
484
  // Clean all target directories
457
485
  if (this.installerConfig?.targets) {
458
486
  const parentDirs = new Set();
@@ -532,24 +560,71 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
532
560
  }
533
561
  }
534
562
  /**
535
- * Recursively remove empty directories walking up from dir toward projectDir
563
+ * Check ancestor directories for existing BMAD files in the same target_dir.
564
+ * IDEs like Claude Code inherit commands from parent directories, so an existing
565
+ * installation in an ancestor would cause duplicate commands.
566
+ * @param {string} projectDir - Project directory being installed to
567
+ * @returns {Promise<string|null>} Path to conflicting directory, or null if clean
568
+ */
569
+ async findAncestorConflict(projectDir) {
570
+ const targetDir = this.installerConfig?.target_dir;
571
+ if (!targetDir) return null;
572
+
573
+ const resolvedProject = await fs.realpath(path.resolve(projectDir));
574
+ let current = path.dirname(resolvedProject);
575
+ const root = path.parse(current).root;
576
+
577
+ while (current !== root && current.length > root.length) {
578
+ const candidatePath = path.join(current, targetDir);
579
+ try {
580
+ if (await fs.pathExists(candidatePath)) {
581
+ const entries = await fs.readdir(candidatePath);
582
+ const hasBmad = entries.some((e) => typeof e === 'string' && e.toLowerCase().startsWith('bmad'));
583
+ if (hasBmad) {
584
+ return candidatePath;
585
+ }
586
+ }
587
+ } catch {
588
+ // Can't read directory — skip
589
+ }
590
+ current = path.dirname(current);
591
+ }
592
+
593
+ return null;
594
+ }
595
+
596
+ /**
597
+ * Walk up ancestor directories from relativeDir toward projectDir, removing each if empty
536
598
  * Stops at projectDir boundary — never removes projectDir itself
537
599
  * @param {string} projectDir - Project root (boundary)
538
600
  * @param {string} relativeDir - Relative directory to start from
539
601
  */
540
602
  async removeEmptyParents(projectDir, relativeDir) {
603
+ const resolvedProject = path.resolve(projectDir);
541
604
  let current = relativeDir;
542
605
  let last = null;
543
606
  while (current && current !== '.' && current !== last) {
544
607
  last = current;
545
- const fullPath = path.join(projectDir, current);
608
+ const fullPath = path.resolve(projectDir, current);
609
+ // Boundary guard: never traverse outside projectDir
610
+ if (!fullPath.startsWith(resolvedProject + path.sep) && fullPath !== resolvedProject) break;
546
611
  try {
547
- if (!(await fs.pathExists(fullPath))) break;
612
+ if (!(await fs.pathExists(fullPath))) {
613
+ // Dir already gone — advance current; last is reset at top of next iteration
614
+ current = path.dirname(current);
615
+ continue;
616
+ }
548
617
  const remaining = await fs.readdir(fullPath);
549
618
  if (remaining.length > 0) break;
550
619
  await fs.rmdir(fullPath);
551
- } catch {
552
- break;
620
+ } catch (error) {
621
+ // ENOTEMPTY: TOCTOU race (file added between readdir and rmdir) — skip level, continue upward
622
+ // ENOENT: dir removed by another process between pathExists and rmdir — skip level, continue upward
623
+ if (error.code === 'ENOTEMPTY' || error.code === 'ENOENT') {
624
+ current = path.dirname(current);
625
+ continue;
626
+ }
627
+ break; // fatal error (e.g. EACCES) — stop upward walk
553
628
  }
554
629
  current = path.dirname(current);
555
630
  }
@@ -206,7 +206,9 @@ class IdeManager {
206
206
  if (handlerResult.tools > 0) parts.push(`${handlerResult.tools} tools`);
207
207
  detail = parts.join(', ');
208
208
  }
209
- return { success: true, ide: ideName, detail, handlerResult };
209
+ // Propagate handler's success status (default true for backward compat)
210
+ const success = handlerResult?.success !== false;
211
+ return { success, ide: ideName, detail, error: handlerResult?.error, handlerResult };
210
212
  } catch (error) {
211
213
  await prompts.log.error(`Failed to setup ${ideName}: ${error.message}`);
212
214
  return { success: false, ide: ideName, error: error.message };
@@ -40,6 +40,7 @@ platforms:
40
40
  installer:
41
41
  target_dir: .claude/commands
42
42
  template_type: default
43
+ ancestor_conflict_check: true
43
44
 
44
45
  cline:
45
46
  name: "Cline"
@@ -131,11 +132,14 @@ platforms:
131
132
  category: ide
132
133
  description: "OpenCode terminal coding assistant"
133
134
  installer:
135
+ legacy_targets:
136
+ - .opencode/agent
137
+ - .opencode/command
134
138
  targets:
135
- - target_dir: .opencode/agent
139
+ - target_dir: .opencode/agents
136
140
  template_type: opencode
137
141
  artifact_types: [agents]
138
- - target_dir: .opencode/command
142
+ - target_dir: .opencode/commands
139
143
  template_type: opencode
140
144
  artifact_types: [workflows, tasks, tools]
141
145
 
@@ -191,12 +195,17 @@ platforms:
191
195
  # template_type: string # Default template type to use
192
196
  # header_template: string (optional) # Override for header/frontmatter template
193
197
  # body_template: string (optional) # Override for body/content template
198
+ # legacy_targets: array (optional) # Old target dirs to clean up on reinstall (migration)
199
+ # - string # Relative path, e.g. .opencode/agent
194
200
  # targets: array (optional) # For multi-target installations
195
201
  # - target_dir: string
196
202
  # template_type: string
197
203
  # artifact_types: [agents, workflows, tasks, tools]
198
204
  # artifact_types: array (optional) # Filter which artifacts to install (default: all)
199
205
  # skip_existing: boolean (optional) # Skip files that already exist (default: false)
206
+ # ancestor_conflict_check: boolean (optional) # Refuse install when ancestor dir has BMAD files
207
+ # # in the same target_dir (for IDEs that inherit
208
+ # # commands from parent directories)
200
209
 
201
210
  # ============================================================================
202
211
  # Platform Categories
@@ -6,7 +6,7 @@ description: '{{description}}'
6
6
  You must fully embody this agent's persona and follow all activation instructions exactly as specified. NEVER break character until given an exit command.
7
7
 
8
8
  <agent-activation CRITICAL="TRUE">
9
- 1. LOAD the FULL agent file from @_bmad/{{module}}/agents/{{path}}
9
+ 1. LOAD the FULL agent file from {project-root}/_bmad/{{module}}/agents/{{path}}
10
10
  2. READ its entire contents - this contains the complete agent persona, menu, and instructions
11
11
  3. Execute ALL activation steps exactly as written in the agent file
12
12
  4. Follow the agent's persona and menu system precisely
@@ -6,9 +6,9 @@ description: '{{description}}'
6
6
  IT IS CRITICAL THAT YOU FOLLOW THESE STEPS - while staying in character as the current agent persona you may have loaded:
7
7
 
8
8
  <steps CRITICAL="TRUE">
9
- 1. Always LOAD the FULL @{project-root}/{{bmadFolderName}}/core/tasks/workflow.xml
10
- 2. READ its entire contents - this is the CORE OS for EXECUTING the specific workflow-config @{project-root}/{{bmadFolderName}}/{{path}}
11
- 3. Pass the yaml path @{project-root}/{{bmadFolderName}}/{{path}} as 'workflow-config' parameter to the workflow.xml instructions
9
+ 1. Always LOAD the FULL {project-root}/{{bmadFolderName}}/core/tasks/workflow.xml
10
+ 2. READ its entire contents - this is the CORE OS for EXECUTING the specific workflow-config {project-root}/{{bmadFolderName}}/{{path}}
11
+ 3. Pass the yaml path {project-root}/{{bmadFolderName}}/{{path}} as 'workflow-config' parameter to the workflow.xml instructions
12
12
  4. Follow workflow.xml instructions EXACTLY as written to process and follow the specific workflow config and its instructions
13
13
  5. Save outputs after EACH section when generating any documents from templates
14
14
  </steps>
@@ -3,4 +3,4 @@ name: '{{name}}'
3
3
  description: '{{description}}'
4
4
  ---
5
5
 
6
- IT IS CRITICAL THAT YOU FOLLOW THIS COMMAND: LOAD the FULL @{project-root}/{{bmadFolderName}}/{{path}}, READ its entire contents and follow its directions exactly!
6
+ IT IS CRITICAL THAT YOU FOLLOW THIS COMMAND: LOAD the FULL {project-root}/{{bmadFolderName}}/{{path}}, READ its entire contents and follow its directions exactly!
@@ -1,4 +1,4 @@
1
- description = """{{description}}"""
1
+ description = '{{description}}'
2
2
  prompt = """
3
3
  Execute the BMAD '{{name}}' workflow.
4
4
 
@@ -1,4 +1,4 @@
1
- description = """{{description}}"""
1
+ description = '{{description}}'
2
2
  prompt = """
3
3
  Execute the BMAD '{{name}}' workflow.
4
4
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- name: '{{name}}'
2
+ mode: all
3
3
  description: '{{description}}'
4
4
  ---
5
5
 
@@ -1,5 +1,4 @@
1
1
  ---
2
- name: '{{name}}'
3
2
  description: '{{description}}'
4
3
  ---
5
4
 
@@ -1,5 +1,4 @@
1
1
  ---
2
- name: '{{name}}'
3
2
  description: '{{description}}'
4
3
  ---
5
4
 
@@ -1,5 +1,4 @@
1
1
  ---
2
- name: '{{name}}'
3
2
  description: '{{description}}'
4
3
  ---
5
4
 
@@ -1,5 +1,4 @@
1
1
  ---
2
- name: '{{name}}'
3
2
  description: '{{description}}'
4
3
  ---
5
4
 
@@ -5,8 +5,8 @@ description: '{{description}}'
5
5
  IT IS CRITICAL THAT YOU FOLLOW THESE STEPS - while staying in character as the current agent persona you may have loaded:
6
6
 
7
7
  <steps CRITICAL="TRUE">
8
- 1. Always LOAD the FULL @_bmad/core/tasks/workflow.xml
9
- 2. READ its entire contents - this is the CORE OS for EXECUTING the specific workflow-config @{{workflow_path}}
8
+ 1. Always LOAD the FULL {project-root}/_bmad/core/tasks/workflow.xml
9
+ 2. READ its entire contents - this is the CORE OS for EXECUTING the specific workflow-config {project-root}/{{workflow_path}}
10
10
  3. Pass the yaml path {{workflow_path}} as 'workflow-config' parameter to the workflow.xml instructions
11
11
  4. Follow workflow.xml instructions EXACTLY as written to process and follow the specific workflow config and its instructions
12
12
  5. Save outputs after EACH section when generating any documents from templates
@@ -2,4 +2,4 @@
2
2
  description: '{{description}}'
3
3
  ---
4
4
 
5
- IT IS CRITICAL THAT YOU FOLLOW THIS COMMAND: LOAD the FULL @{{workflow_path}}, READ its entire contents and follow its directions exactly!
5
+ IT IS CRITICAL THAT YOU FOLLOW THIS COMMAND: LOAD the FULL {project-root}/{{workflow_path}}, READ its entire contents and follow its directions exactly!