Skip to content

Conversation

@dickymoore
Copy link
Contributor

@dickymoore dickymoore commented Feb 6, 2026

What

Migrated workflows to the Markdown-based workflow.md format and removed legacy XML/YAML workflow artifacts and references across the repo. This includes CLI/template/docs/test updates to keep tooling aligned with the single workflow definition format.

Why

To align with the v6 step-file workflow architecture and eliminate format drift that caused stale references and inconsistent behavior in tooling and workflows. This consolidation reduces maintenance and avoids mismatched file expectations.

How

  • Converted remaining workflows (including QA automate) to workflow.md and removed workflow.yaml/workflow.xml artifacts.
  • Updated CLI/IDE tooling and templates to treat workflow.md as the canonical workflow definition format.
  • Updated workflow reference guards and cleaned references in agents/docs/tests to prevent legacy formats from reappearing.

Testing

Ran npm test (test:schemas, test:install, validate:schemas, lint, lint:md, format:check).

Summary

Migrated workflows to the Markdown-based format and cleaned up legacy XML/YAML references across the repo, including CLI/template/docs/test updates that align with the new workflow.md structure.

Detailed Changes

  • Removed legacy workflow XML files and associated references.
  • Completed migration to workflow.md and eliminated workflow.yaml references (including the QA automate workflow).
  • Updated CLI installer comments/wording to reflect workflow definition files.
  • Adjusted templates/docs to align with the workflow.md format.
  • Updated tests to remove legacy exclusions for deleted workflow files and tighten reference checks.

Scope/Overlap Check

  • Primary areas: CHANGELOG.md, docs/**, src/bmm/agents/**, src/bmm/module-help.csv, src/bmm/workflows/**, src/core/tasks/**, src/core/workflows/**, src/core/resources/excalidraw/**, src/utility/agent-components/**, test/test-installation-components.js, tools/cli/installers/**.
  • No unrelated cleanup noted beyond the workflow.md migration/removal work.

Potential Conflicts

  • Likely overlap with concurrent CLI/IDE template changes in tools/cli/installers/lib/ide/** and workflow manifest generation in tools/cli/installers/lib/core/**.
  • Recommend rebasing on upstream/main before merge to pick up recent CLI/IDE template updates.

Migration Note

  • Only workflow.md is supported; legacy workflow.xml/workflow.yaml files should be converted to Markdown-based workflows.

Compatibility Notes

  • Workflow status YAML references (bmm-workflow-status.yaml / workflow-status) are preserved; status tracking behavior not changed.

Commit Breakdown

  • Make workflow references platform-agnostic.
  • Convert sprint-planning + sprint-status workflows to MD.
  • Convert Phase 1 workflows to MD; add advanced-elicitation MD workflow + guard.
  • Convert Phase 2/3 workflows to MD.
  • Add validate-workflow MD task and guard.
  • Migrate workflow runner references to workflow.md.
  • Remove workflow.xml runner and XML workflow file(s).
  • Drop YAML workflow support in CLI tooling and remove YAML templates.
  • Remove workflow.yaml mention from changelog.
  • Remove unused workflow command template.

Notes / Breaking Changes

  • Legacy workflow.xml and workflow.yaml artifacts are no longer supported; workflows should use workflow.md.

Note for maintainers:

  • This is a substantial refactor, so it may be presumptuous. I hope it’s helpful; if it’s not the direction you want, I’m happy to close it or rework it to better match the project’s needs.

Tracking

Refs #1585

@coderabbitai
Copy link

coderabbitai bot commented Feb 6, 2026

📝 Walkthrough

Walkthrough

Migrates workflow/task definitions from XML/YAML to Markdown-with-frontmatter, updates workflow references and agent configs, adds many new MD workflow/task and step files, refactors CLI/installer discovery and manifest generation to parse MD frontmatter, adds tests and helpers for the new discovery rules, and removes legacy XML/YAML workflow templates.

Changes

Cohort / File(s) Summary
Docs & Quick Start
docs/tutorials/getting-started.md, docs/how-to/customize-bmad.md, README.md
Removed slash-prefixed command examples and command-centric steps; updated workflow path references to .md; added workflow path resolution docs.
Agent configs
src/bmm/agents/*.agent.yaml
Replaced .yaml/.xml workflow paths with .md across agent menu entries (QA, Analyst, Dev, PM, SM, Tech Writer, Quick-flow).
Workflow frontmatter & step updates
src/bmm/workflows/**/steps/**/*.md, src/core/workflows/**/steps/**/*.md
Updated many frontmatter/protocol references from workflow.xml/workflow.yaml → workflow.md; minor wording and control-flow clarifications in several steps.
New MD workflow/task specs
src/core/tasks/workflow.md, src/core/tasks/validate-workflow.md, src/core/tasks/help.md, src/core/workflows/advanced-elicitation/workflow.md
Added Markdown-based workflow/task runner definitions and validate/help tasks to replace removed XML tasks.
New MD workflows & step-file architectures
src/bmm/workflows/4-implementation/**/workflow.md, src/bmm/workflows/4-implementation/**/steps/*.md, src/bmm/workflows/document-project/workflow.md, src/bmm/workflows/qa/automate/workflow.md, src/bmm/workflows/*/workflow.md
Added multiple new workflow.md files (code-review, dev-story, create-story, correct-course, retrospective, sprint-planning, sprint-status, document-project, QA automate, quick-flow variants) and many step files implementing step-file driven control flows.
Removed legacy XML/YAML workflow files & templates
src/core/tasks/workflow.xml, src/core/workflows/advanced-elicitation/workflow.xml, many src/bmm/.../*.yaml & .xml, tools/cli/installers/lib/ide/templates/*-yaml.md
Deleted legacy workflow XML/YAML configurations and several installer templates that referenced workflow.xml/workflow.yaml.
Installer / CLI refactor
tools/cli/installers/lib/core/manifest-generator.js, tools/cli/installers/lib/ide/_base-ide.js, tools/cli/installers/lib/ide/_config-driven.js, tools/cli/installers/lib/modules/manager.js, tools/cli/installers/lib/ide/shared/*
Refactored discovery to find workflow-*.md with YAML frontmatter, changed manifest generation to MD frontmatter parsing, added/renamed methods (e.g., findWorkflowFiles, copyWorkflowFileStripped, setBmadFolderName), updated template-loading API and CSV handling.
Task/Tool/Command generators
tools/cli/installers/lib/ide/shared/task-tool-command-generator.js, .../workflow-command-generator.js, .../agent-command-generator.js, .../bmad-artifacts.js
Added frontmatter-based standalone/internal filtering, standardized command templates to reference .md, simplified launcher replacement, and filtered out internal/non-standalone items from generated artifacts.
Module manager & path utils
tools/cli/installers/lib/modules/manager.js, tools/cli/installers/lib/ide/shared/path-utils.js
Added frontmatter web_bundle stripping, MD workflow path handling, updated config_source/main_config update logic, and small doc comment tweaks.
Agent handlers & utilities
src/utility/agent-components/handler-*.txt
Switched handler docs/behavior to expect workflow.md loader paths and added primary/fallback loader resolution and deterministic error handling.
Tests
test/test-installation-components.js, test/test-file-refs-csv.js
Added extensive tests and helper collectFiles, covering installer/manifest generation, workflow discovery, frontmatter handling, and legacy-reference guards.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • pbean
  • bmadcode
  • muratkeremozcan
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Remove legacy workflow.xml/yaml references and complete workflow.md migration' accurately and concisely summarizes the main change: migrating workflows to Markdown format and removing legacy XML/YAML artifacts.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining what was changed (workflow format migration), why (align with v6 architecture), and how (converted workflows, updated tooling). It provides clear context for the substantial refactor.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
tools/cli/installers/lib/modules/manager.js (1)

1096-1102: ⚠️ Potential issue | 🟠 Major

Regex doesn't match hardcoded bmad despite the comment claiming it does.

Lines 1096–1097 state the regex handles both _bmad and hardcoded bmad, but the regex (?:_bmad) on line 1098 only matches the literal _bmad. A path like {project-root}/bmad/bmm/workflows/... (second example in the comment) would fail to match, causing the workflow to be silently skipped.

Proposed fix — make the underscore optional
-      const sourceMatch = sourceWorkflowPath.match(/\{project-root\}\/(?:_bmad)\/([^/]+)\/workflows\/(.+)/);
+      const sourceMatch = sourceWorkflowPath.match(/\{project-root\}\/(?:_?bmad)\/([^/]+)\/workflows\/(.+)/);
src/bmm/workflows/generate-project-context/steps/step-02-generate.md (1)

270-270: ⚠️ Potential issue | 🟡 Minor

Stale XML reference: advanced-elicitation.xml not updated to match the migration.

Line 32 was correctly updated to reference workflow.md, but line 270 still says "Execute advanced-elicitation.xml with current category rules." This should be updated to reflect the .md format for consistency.

Note: This stale reference won't be caught by the new guard tests (Test 6) since they check for advanced-elicitation/workflow.xml specifically, not advanced-elicitation.xml.

Proposed fix
-- Execute advanced-elicitation.xml with current category rules
+- Execute advanced-elicitation workflow with current category rules
tools/cli/installers/lib/ide/_base-ide.js (1)

290-299: ⚠️ Potential issue | 🔴 Critical

Bug: findWorkflowYamlFiles no longer exists — core workflow discovery will crash.

Line 292 still calls this.findWorkflowYamlFiles(coreWorkflowsPath), but the method was renamed to findWorkflowFiles on Line 331. This will throw TypeError: this.findWorkflowYamlFiles is not a function at runtime when discovering core workflows. Line 307 was correctly updated for module workflows.

      const coreWorkflows = await this.findWorkflowFiles(coreWorkflowsPath);
tools/cli/installers/lib/ide/shared/workflow-command-generator.js (1)

221-237: ⚠️ Potential issue | 🔴 Critical

Bug: transformWorkflowPath never handles /src/core/ paths and returns undefined for them.

The else if on line 228 is nested inside the if (workflowPath.includes('/src/bmm/')) block, making it unreachable for core-only paths. When a path contains /src/core/ but not /src/bmm/, the outer if is false, the function falls through with no return, and returns undefined. The return transformed on line 235 is also only reachable inside the outer if.

Additionally, line 228's else if is dead code: if includes('/src/bmm/') is true, the regex on line 225 will always match, so the else branch is never entered.

🐛 Proposed fix — flatten the nesting
   transformWorkflowPath(workflowPath) {
     let transformed = workflowPath;
 
     if (workflowPath.includes('/src/bmm/')) {
       const match = workflowPath.match(/\/src\/bmm\/(.+)/);
       if (match) {
         transformed = `{project-root}/${this.bmadFolderName}/bmm/${match[1]}`;
       }
-    } else if (workflowPath.includes('/src/core/')) {
-      const match = workflowPath.match(/\/src\/core\/(.+)/);
-      if (match) {
-        transformed = `{project-root}/${this.bmadFolderName}/core/${match[1]}`;
+    } else if (workflowPath.includes('/src/core/')) {
+      const match = workflowPath.match(/\/src\/core\/(.+)/);
+      if (match) {
+        transformed = `{project-root}/${this.bmadFolderName}/core/${match[1]}`;
       }
-    }
+    }
 
-      return transformed;
-    }
+    return transformed;
   }
tools/cli/installers/lib/ide/_config-driven.js (1)

157-177: ⚠️ Potential issue | 🟠 Major

Workflow template name is doubled: ${templateType}-workflow-workflow.md.

Line 163 builds workflowTemplateType = \${templateType}-workflow`and then line 167 passes it toloadTemplate(workflowTemplateType, 'workflow', ...). Inside loadTemplate(line 196), the template file is resolved as`${templateType}-${artifactType}.md`→ e.g.claude-workflow-workflow.md`.

The primary template lookup will always miss, silently falling through to the default-workflow.md fallback. This means per-IDE workflow template customization is broken.

Either pass just templateType to loadTemplate, or don't append -workflow on line 163:

🐛 Proposed fix (option A — align with agent pattern)
       if (artifact.type === 'workflow-command') {
-        // Default to 'default' template type, but allow override via config
-        const workflowTemplateType = config.md_workflow_template || `${templateType}-workflow`;
-
-        // Fall back to default template if the requested one doesn't exist
-        const finalTemplateType = 'default-workflow';
-        const template = await this.loadTemplate(workflowTemplateType, 'workflow', config, finalTemplateType);
+        const template = await this.loadTemplate(templateType, 'workflow', config, 'default-workflow');
🤖 Fix all issues with AI agents
In
`@src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md`:
- Around line 7-9: The prdPurpose path references are inconsistent across
workflow step files (e.g., prdPurpose in step-e-01-discovery.md,
step-e-01b-legacy-conversion.md, step-e-02-review.md, step-e-03-edit.md,
step-v-01-discovery.md); update each file to use a single standardized path (use
the installed-context recommended path
`{project-root}/_bmad/bmm/workflows/2-plan-workflows/create-prd/data/prd-purpose.md`)
by replacing the existing prdPurpose value in those markdown front-matter blocks
so all steps reference the same prd-purpose.md location (search for the
`prdPurpose` key in those filenames and change its value accordingly).

In `@src/bmm/workflows/4-implementation/create-story/workflow.md`:
- Around line 134-189: Remove the duplicated auto-discover block that repeats
the sprint-status parsing, backlog-story discovery, epic-status validation, and
GOTO logic (the second copy starting with <action>Load the FULL file:
{{sprint_status}}</action> and ending with <action>GOTO step 2a</action>); keep
only the original guarded copy inside the <check if="no user input provided">
flow so the agent does not re-run the auto-discover steps unconditionally.
Ensure the remaining block still contains the parsing, the "Find the FIRST
story" logic, the epic-first-story check (epic-{{epic_num}} handling), and the
GOTO step 2a call.

In `@src/bmm/workflows/excalidraw-diagrams/create-dataflow/instructions.md`:
- Around line 123-125: The <invoke-task> in step n="9" (goal="Validate Content")
is missing the explicit task file path; update the <invoke-task> element in
src/bmm/workflows/excalidraw-diagrams/create-dataflow/instructions.md (the step
with n="9" and goal="Validate Content") to include the task path consistent with
sibling workflows (e.g., same pattern used in create-diagram and
create-flowchart) so it reads "Validate against {{validation}} using
{_bmad}/core/tasks/validate-workflow.md".

In `@src/bmm/workflows/testarch/trace/instructions.md`:
- Around line 930-934: Remove the stray fenced-code-marker that opens an
unintended code block near the "Enhance P2 Coverage" section: delete the lone
"```" that appears after the closed four-backtick block (the one noted around
the "Enhance P2 Coverage: Add E2E validation for session timeout" text) so the
rest of instructions.md (Validation Checklist, Notes, Troubleshooting, Related
Workflows) renders as normal Markdown; ensure the original four-backtick block
opened earlier remains unchanged and that there are no other unmatched fence
markers.

In `@test/test-installation-components.js`:
- Around line 238-274: The scan never excludes the intended file because
excludedFile is never checked; update the walk function (used in the for loop
that iterates searchRoots) to skip the exclusion before reading files by
comparing the current fullPath to excludedFile (use path.resolve or
path.normalize on both sides to avoid path-sep differences) — if they match,
continue without reading/inspecting the file; keep the existing checks for
allowedExtensions and forbiddenRef and push matches into offenders as before.
- Around line 278-314: The test currently uses content.includes(forbiddenRef)
which false-positives on names like "validate-workflow.xml"; update the check in
the walk function to perform a filename-aware match: either replace the simple
substring test with a regex that matches whole-filename occurrences (e.g.
/\bworkflow\.xml\b/.test(content)) or add an exclusion check (e.g. skip when
content.includes('validate-workflow.xml')) before pushing to offenders; refer to
the variables/function names walk, forbiddenRef, offenders, allowedExtensions
and apply the change where content.includes(forbiddenRef) is used so only true
references to "workflow.xml" are flagged.

In `@tools/cli/installers/lib/core/manifest-generator.js`:
- Around line 778-789: The CSV column-count check is incorrect so existing
agents are never preserved: inside the loop that parses lines using split('","')
(variables lines, parts, name, module, existingEntries), change the guard from
parts.length >= 11 to parts.length >= 10 so 10-column rows are accepted; keep
the existing extraction of name = parts[0].replace(/^"/, '') and module =
parts[8] and continue to set existingEntries.set(`${module}:${name}`, line).

In `@tools/cli/installers/lib/ide/_base-ide.js`:
- Around line 347-358: The frontmatter regex in the workflow.md reader is
LF-only and will fail on CRLF files; update the regex used in the workflow.md
branch (the block that reads workflow.md in the method containing the else-if
where entry.isFile() && entry.name === 'workflow.md') to accept CRLF like the
one used in scanDirectoryWithStandalone (use a pattern with \r? before newlines)
so frontmatter is matched on both LF and CRLF line endings; ensure you use the
same normalized regex as in scanDirectoryWithStandalone to keep behavior
consistent.

In `@tools/cli/installers/lib/modules/manager.js`:
- Around line 765-772: The first replaceAll call on mdContent
(mdContent.replaceAll('_bmad', '_bmad')) is a no-op and should be removed or
corrected; update the code around mdContent in manager.js so that either (A) you
remove the redundant mdContent.replaceAll('_bmad', '_bmad') line, or (B) if you
intended to normalize a different placeholder (for example '{_bmad}' or 'bmad'),
change the search string to that placeholder (e.g.,
mdContent.replaceAll('{_bmad}', '_bmad')) before the subsequent replacement that
uses this.bmadFolderName; ensure you keep the following replacement and the call
to this.stripWebBundleFromFrontmatter(mdContent) and the final write to
targetFile.
🧹 Nitpick comments (5)
tools/cli/installers/lib/modules/manager.js (2)

1000-1044: processAgentFiles is a no-op with its body entirely commented out — dead code.

The method body is fully commented out, yet it's still called at lines 551 and 608. findAgentMdFiles (lines 1025–1044) is also only referenced inside the commented-out block, making it unreachable. Consider removing the commented-out code and the unused helper, or at minimum adding a TODO explaining why it's retained and when it will be restored.


419-419: Replace deprecated --production flag with --omit=dev.

The --production flag is deprecated in npm v7+. Update lines 419 and 444:

Suggested change
execSync('npm install --omit=dev --no-audit --no-fund --prefer-offline --no-progress', {
test/test-installation-components.js (1)

189-316: Consider extracting the duplicated walk function into a shared helper.

The recursive directory walk logic is copy-pasted three times across Tests 6, 7, and 8. Extracting it into a reusable helper would reduce duplication and make it easier to apply fixes (like the missing exclusion check) consistently.

Suggested helper extraction
+/**
+ * Recursively scan directories for files containing a forbidden reference string.
+ * `@param` {string[]} searchRoots - Directories to scan
+ * `@param` {Set<string>} allowedExtensions - File extensions to check
+ * `@param` {string} forbiddenRef - String to search for in file contents
+ * `@param` {string} projectRoot - Project root for relative path output
+ * `@param` {Set<string>} [excludedFiles] - Full paths to skip
+ * `@returns` {Promise<string[]>} Relative paths of offending files
+ */
+async function findForbiddenRefs(searchRoots, allowedExtensions, forbiddenRef, projectRoot, excludedFiles = new Set()) {
+  const offenders = [];
+  const walk = async (dir) => {
+    const entries = await fs.readdir(dir, { withFileTypes: true });
+    for (const entry of entries) {
+      const fullPath = path.join(dir, entry.name);
+      if (entry.isDirectory()) {
+        await walk(fullPath);
+        continue;
+      }
+      if (!allowedExtensions.has(path.extname(entry.name))) continue;
+      if (excludedFiles.has(fullPath)) continue;
+      const content = await fs.readFile(fullPath, 'utf8');
+      if (content.includes(forbiddenRef)) {
+        offenders.push(path.relative(projectRoot, fullPath));
+      }
+    }
+  };
+  for (const root of searchRoots) {
+    if (await fs.pathExists(root)) {
+      await walk(root);
+    }
+  }
+  return offenders;
+}
tools/cli/installers/lib/ide/shared/workflow-command-generator.js (1)

115-148: Redundant template path resolution and no-op replaceAll.

Two issues in generateCommandContent:

  1. Line 117: templatePath is re-derived from this.templatePath but resolves to the exact same file (workflow-commander.md). This is dead code left from when multiple templates existed.

  2. Lines 147–148: The second .replaceAll('_bmad', '_bmad') is a no-op — it replaces _bmad with itself. If the intent was to prevent the first replacement from touching certain occurrences, it doesn't achieve that because replaceAll on line 147 already replaced all occurrences.

Proposed cleanup
   async generateCommandContent(workflow, bmadDir) {
-    // Determine template based on workflow file type
-    const templatePath = path.join(path.dirname(this.templatePath), 'workflow-commander.md');
-
     // Load the appropriate template
-    const template = await fs.readFile(templatePath, 'utf8');
+    const template = await fs.readFile(this.templatePath, 'utf8');
 
     // ...
 
     // Replace template variables
     return template
       .replaceAll('{{name}}', workflow.name)
       .replaceAll('{{module}}', workflow.module)
       .replaceAll('{{description}}', workflow.description)
       .replaceAll('{{workflow_path}}', workflowPath)
-      .replaceAll('_bmad', this.bmadFolderName)
-      .replaceAll('_bmad', '_bmad');
+      .replaceAll('_bmad', this.bmadFolderName);
   }
tools/cli/installers/lib/core/manifest-generator.js (1)

316-323: cleanForCSV is redefined on every loop iteration.

The helper is a pure function with no closure over per-iteration state. Defining it once outside the for loop (or as a module-level/static helper) avoids unnecessary re-creation.

Copy link
Collaborator

@bmadcode bmadcode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would love to merge this and be done with it, but the stright conversion of the yaml to md will cause issues without also converting to step files or including even more instructions from the workflow.xml into each instruction file. best to instead finish the conversion of each file to the step flow.

Also the pr adds back deleted excalidraw content.

Would love the hlep with this though if you would like to run the bmb and help convert some of these workflows that remain.

The goal is to do this right after we finish beta on sunday.

@dickymoore
Copy link
Contributor Author

@bmadcode thanks for the comment, and for the invitation to help. I'd love to help out if I can. I'll continue working through this, and will make the PR as draft until it's ready for another review.

@dickymoore
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Feb 7, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@dickymoore
Copy link
Contributor Author

dickymoore commented Feb 7, 2026

Process update (clean):

  • Added tracking issue linkage in PR body: Refs Track workflow.md migration follow-up and phased review for PR #1567 #1585 (large-change tracking).
  • Re-ran validation locally after latest fixes: npm test, npm run validate:refs, plus fresh install checks (tools: none, claude-code, windsurf) all passed.
  • Addressed previously reported technical blockers around:
    • workflow runner install path
    • workflow-*.md manifest coverage
    • template selection behavior
    • path/regex handling in installers
    • remaining step-flow conversions

If preferred, this can be split for easier review due size, I can break follow-on cleanup into smaller PRs and keep this PR strictly migration-critical.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 19

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (36)
src/bmm/workflows/3-solutioning/create-architecture/steps/step-04-decisions.md (10)

14-14: ⚠️ Potential issue | 🟠 Major

Placeholder brace style is inconsistent and likely breaks templating.

{communication_language} uses single braces while all other placeholders use {{...}}, so this value may never resolve. Standardize the placeholder format.

Proposed fix
-- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}`
+- ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{{communication_language}}`

57-76: ⚠️ Potential issue | 🟠 Major

Mismatched placeholder names will drop user preferences.

You reference {{user_technical_preferences_from_step_3}} and later {{user_technology_preferences}}. If only one exists, the other renders empty and breaks “Already Decided.” Unify to a single variable.


29-31: ⚠️ Potential issue | 🟠 Major

“C (Continue)” is defined three different ways.

Line 31 says C proceeds to the next decision category, while Line 261 says it moves to implementation patterns and Lines 281–286 load the next step. This ambiguity will cause premature step transitions.

Also applies to: 258-262, 281-286


47-47: ⚠️ Potential issue | 🟠 Major

You ban recommendations, then give recommendations.

Line 47 says “Collaborative decision making, not recommendations,” but Intermediate/Beginner modes explicitly recommend options. Either allow recommendations or remove the “not recommendations” rule.

Also applies to: 138-159


18-18: ⚠️ Potential issue | 🟠 Major

“Show your analysis” conflicts with non-disclosure policies.

Requiring analysis disclosure forces chain-of-thought exposure, which is unsafe and typically disallowed. Replace with “brief rationale” or “summary.”

Proposed fix
-- 🎯 Show your analysis before taking any action
+- 🎯 Provide a brief rationale before taking any action

5-5: ⚠️ Potential issue | 🟠 Major

“Never generate content without user input” contradicts “This step will generate content.”

Line 27 implies auto-generation independent of user input, directly violating Line 5. Clarify that content is generated only after the user has provided decisions.

Also applies to: 27-27


78-81: ⚠️ Potential issue | 🟠 Major

No enforcement that critical decisions are completed before Continue.

You declare critical decisions must be made before implementation, but the Continue path lacks any guard. Add a check to prevent advancing if any critical decision is still unresolved.

Also applies to: 281-286


163-170: ⚠️ Potential issue | 🟡 Minor

Web search instructions assume every tech has “LTS.”

Many technologies have no LTS track; this will produce irrelevant searches and confusion. Make LTS optional or conditional on the technology.


20-20: ⚠️ Potential issue | 🟠 Major

Menu cadence is inconsistent.

Line 20 says present A/P/C after each major decision category, while Lines 248–261 present it after all content generation. Pick one cadence to avoid duplicate or missing menus.

Also applies to: 248-261


21-21: ⚠️ Potential issue | 🟠 Major

Saving semantics are unclear and conflicting.

Line 21 says “ONLY save when user chooses C,” but C is offered after each category, while Lines 199–201 and 281–289 imply a single final append. Specify whether saves are incremental or only at the end.

Also applies to: 199-201, 281-289

src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md (2)

88-95: ⚠️ Potential issue | 🟡 Minor

Shell command in a workflow step assumes Unix environment and relies on ls with glob.

Lines 92-95 embed a bash command (ls -t ... 2>/dev/null | head -1) for auto-detecting validation reports. This is executed conceptually by an AI agent, not a real shell — but the instruction to use ls -t with glob patterns and pipe to head presumes a Unix filesystem. If the agent interprets this literally in a non-Unix context (e.g., Windows, or an API-only environment), it will fail silently. The 2>/dev/null suppression means the agent gets no feedback on failure.

This is pre-existing and tangential to the migration, but it's a fragility worth noting.


110-143: ⚠️ Potential issue | 🟡 Minor

Steps 4 and 5 are redundant — both ask about validation reports.

Step 4 (lines 88-124) auto-detects a validation report in the PRD folder and asks the user whether to use it. Step 5 (lines 126-143) then asks again "Do you have a validation report to guide edits?" — even if the user already said yes or no in step 4. If the user chose "Use validation report" in step 4, step 5 re-asks the same question. If no report was found in step 4 and the flow falls through silently (line 124), step 5 asks again.

This creates a confusing double-prompt experience. Step 5 only makes sense if step 4 found nothing, but the control flow doesn't skip step 5 in the "found and accepted" case.

src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-11-component-strategy.md (1)

196-200: ⚠️ Potential issue | 🟠 Major

No validation of "enhanced component insights" returned from advanced elicitation.

Lines 196-200 describe the flow: invoke advanced-elicitation workflow.md, "process the enhanced component insights that come back," then ask the user to accept or reject. But there's no specification for:

  • What format should "enhanced component insights" take?
  • How does the agent know the returned content is actually "enhanced insights" vs. an error message or malformed output?
  • What if advanced-elicitation returns empty content or null?
  • Is there a schema or structure that the returned insights must conform to?

Without validation, the agent might present garbage data to the user as "enhanced insights," leading them to accept changes that break the component strategy. This is especially risky in step 11, where component decisions affect downstream implementation.

Add validation logic for returned insights

Before presenting the insights to the user, validate the structure:

#### If 'A' (Advanced Elicitation):

- Read fully and follow: {project-root}/_bmad/core/workflows/advanced-elicitation/workflow.md with the current component strategy content
- Process the enhanced component insights that come back
- **Validate insights structure**: Confirm returned content includes component specifications, rationale, and accessibility considerations
- **If validation fails**: Inform user that advanced elicitation didn't produce valid insights and return to A/P/C menu without applying changes
- Ask user: "Accept these improvements to the component strategy? (y/n)"
src/bmm/workflows/3-solutioning/create-architecture/steps/step-06-structure.md (1)

328-332: ⚠️ Potential issue | 🟠 Major

Architecture decisions require deeper validation than generic workflow outputs.

Lines 328-332 invoke advanced-elicitation and process "enhanced organizational insights" for project structure, then ask the user to accept or reject changes. But project structure decisions are foundational—they affect every subsequent implementation story, file organization, and deployment strategy.

Unlike UX insights (which can be adjusted later), bad architecture insights create technical debt that compounds over time. The validation here needs to be stricter:

  • Verify that returned insights include complete directory structure (not partial)
  • Check that boundary definitions (API, component, service, data) are all addressed
  • Confirm that requirements-to-structure mappings are present
  • Validate that integration points are defined

Currently, there's no validation beyond "did advanced-elicitation return something?" This is insufficient for architecture decisions.

tools/cli/installers/lib/modules/manager.js (3)

604-609: ⚠️ Potential issue | 🔴 Critical

options is not defined in update() — will throw ReferenceError at runtime.

Line 607 references options.installer, but the method signature on line 584 is async update(moduleName, bmadDir, force = false) — there is no options parameter. This will crash whenever a non-force update triggers the else branch.

Proposed fix
-  async update(moduleName, bmadDir, force = false) {
+  async update(moduleName, bmadDir, force = false, options = {}) {

999-1017: ⚠️ Potential issue | 🟠 Major

processAgentFiles is called but entirely commented out — activation injection silently skipped.

Line 551 calls await this.processAgentFiles(targetPath, moduleName), but the method body (lines 999–1017) is entirely commented out, making it a no-op. If this is intentional (activation is handled elsewhere now), remove both the call and the dead code. If it's a regression, restore the logic.


1095-1109: ⚠️ Potential issue | 🟡 Minor

Vendoring regex only matches bmad or _bmad — won't work with custom folder names.

The regex (?:_?bmad) on lines 1097 and 1109 matches exactly bmad or _bmad. If the user configured a different bmadFolderName (e.g., .bmad-custom), these patterns silently fail to match, and vendored workflows are skipped with a warning. Consider building the regex dynamically from this.bmadFolderName:

const folderPattern = this.bmadFolderName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const sourceMatch = sourceWorkflowPath.match(
  new RegExp(`\\{project-root\\}/${folderPattern}/([^/]+)/workflows/(.+)`)
);
src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md (1)

1-10: ⚠️ Potential issue | 🟠 Major

Add validationReportPath to frontmatter; it's referenced in the body but undefined.

Lines 133 and 174 use {validationReportPath}, yet the frontmatter (lines 1–10) omits this variable. All subsequent validation steps (step-v-02 through step-v-13) define it; step-v-01 must too. Without it, the agent cannot initialize the validation report. Add to frontmatter:

validationReportPath: '{validation_report_path}'
src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-06-innovation.md (1)

19-19: ⚠️ Potential issue | 🟡 Minor

Step total count mismatch with sibling step file.

Line 19 states "Step 6 of 11", but step-05-domain.md (in the same steps-c directory) states "Step 5 of 13" at its Line 17, and its menu text references "Step 6 of 13" when pointing to this file. One of these totals is wrong. Pre-existing issue, but this migration pass is a good opportunity to reconcile.

src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-09-functional.md (1)

1-12: ⚠️ Potential issue | 🟠 Major

Security concern: Markdown files can contain executable code.

The migration from XML/YAML to Markdown introduces a security risk. Markdown files can contain code blocks, HTML, and potentially JavaScript (if rendered in a web context). If agents parse and execute these MD files without sanitization, malicious workflow.md files could inject executable code. The PR provides no discussion of security boundaries or sanitization strategy.

Establish security boundaries for workflow.md parsing:

  1. Whitelist allowed Markdown features: Restrict to headers, lists, code blocks, emphasis — no raw HTML or JavaScript
  2. Sanitize frontmatter: Validate YAML frontmatter doesn't contain executable directives (e.g., !!python/object tags)
  3. Path traversal protection: Ensure path interpolation can't escape repository root ({project-root}/../../../etc/passwd)
  4. Content Security Policy: If workflows are rendered in web UI, enforce strict CSP

Document the security model for workflow.md files and implement parser-level sanitization.

src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-04-journeys.md (1)

158-161: ⚠️ Potential issue | 🟠 Major

Menu loop has no escape hatch—infinite loop risk.

The menu handling logic (lines 158-161) can redisplay the menu after executing advanced elicitation or party mode, but there's no maximum attempt counter, timeout, or explicit exit condition beyond selecting 'C'. If a workflow returns invalid state or the user gets stuck in refinement loops, there's no safety valve.

src/bmm/workflows/document-project/instructions.md (8)

13-16: ⚠️ Potential issue | 🟠 Major

Missing guard when workflow-status is unavailable.

You invoke {project-root}/_bmad/bmm/workflows/workflow-status without a fallback if that workflow is missing or fails. The rest of Step 1 assumes status variables exist and will break silently. Add an explicit failure path (e.g., set standalone_mode=true, status_file_found=false, and continue) when the invoke fails.

As per coding guidelines: "Review with extreme skepticism — assume problems exist. Find at least 10 issues to fix or improve."


18-23: ⚠️ Potential issue | 🟠 Major

Ambiguous condition uses implicit boolean.

status_exists == false is referenced without defining how status_exists is computed or whether it can be null/undefined. If the status workflow returns nothing, this check may not fire, leading to undefined flow. Add an explicit default assignment before the checks.

As per coding guidelines: "Be skeptical of everything. Look for what's missing, not just what's wrong."


30-36: ⚠️ Potential issue | 🟠 Major

Greenfield prompt exits without cleaning up state.

If the user answers “n” to continue, you exit without updating or clearing any status markers. That can leave a workflow-status file in an inconsistent “in-progress” state. Add a status update (e.g., mark aborted) before exit when status tracking is enabled.

As per coding guidelines: "Look for what's missing, not just what's wrong."


39-52: ⚠️ Potential issue | 🟡 Minor

Warning handling is destructive without preserving reason.

When warning != '' and the user chooses "n", you exit without storing the warning or suggestion in state. That loses valuable context for audit/troubleshooting. Persist warning/suggestion to the status file before exit.

As per coding guidelines: "Be skeptical of everything."


60-66: ⚠️ Potential issue | 🟠 Major

“Check for state file” doesn’t specify existence failure path.

The step only describes what happens if the state file exists. It never explicitly defines the else path (file missing), yet later steps rely on resume_mode. Define resume_mode = false when the file doesn’t exist to avoid undefined branching.

As per coding guidelines: "Look for what's missing, not just what's wrong."


121-126: ⚠️ Potential issue | 🟠 Major

Conflicting resume logic can double-trigger.

The “state file age >= 24 hours” check runs after user selection blocks; if the user already chose resume (1), this later check can still force a fresh scan, contradicting user input. Gate the age check before the user prompt or short-circuit if a selection was made.

As per coding guidelines: "Be skeptical of everything."


148-161: ⚠️ Potential issue | 🟠 Major

No validation that sub-workflow actually completes.

Steps assume the sub-workflow completes and then continue to Step 4. If the sub-workflow fails or is aborted, Step 4 still runs and may incorrectly mark status complete. Add an explicit success check (e.g., subworkflow_success == true) before continuing.

As per coding guidelines: "Look for what's missing, not just what's wrong."


192-217: ⚠️ Potential issue | 🟠 Major

Status output block has mismatched templating scope.

You open {{#if status_file_found}} and close with {{/if}} inside <output> but the indentation and placement suggest mixed templating/agent markers; there’s no explicit guarantee the engine supports this inside <output>. This risks rendering the template literally. Confirm supported template scope or move conditional logic outside <output>.

Based on learnings: In BMAD-METHOD workflow files under src/bmm/workflows/, XML-style tags like , , etc. are processing markers for AI agents executing workflows and should not be treated as HTML/Markdown for GitHub rendering. These tags may contain Markdown that will be output by the agent, not rendered by GitHub's sanitizer. When reviewing, ensure these markers are preserved and that any Markdown inside them is allowed for agent output; do not modify or strip content inside these processing tags to maintain correct agent behavior.

src/bmm/workflows/2-plan-workflows/create-prd/steps-c/step-03-success.md (2)

175-181: ⚠️ Potential issue | 🟠 Major

Menu flow uses advanced/party workflows without specifying return contract.

The A/P paths call other workflows and then “redisplay menu” after asking for acceptance. There’s no explicit requirement that those workflows return enhanced criteria in a known variable. Define the expected output variable names so content replacement is deterministic.

As per coding guidelines: "Look for what's missing, not just what's wrong."


178-180: ⚠️ Potential issue | 🟠 Major

Potential infinite loop when user rejects changes.

If the user answers “no” to accepting improvements, you “keep original content then redisplay menu,” but nothing changes; the user can get stuck in a loop with the same content. Provide a path to exit or refine without re-running external workflows.

As per coding guidelines: "Be skeptical of everything."

src/bmm/workflows/3-solutioning/create-epics-and-stories/steps/step-01-validate-prerequisites.md (4)

6-21: ⚠️ Potential issue | 🟠 Major

Duplicate epicsTemplate key in frontmatter.

epicsTemplate is declared twice (Lines 13 and 20). That is ambiguous in YAML frontmatter and may clobber earlier values. Remove one and keep a single authoritative definition.

As per coding guidelines: "Be skeptical of everything."


77-94: ⚠️ Potential issue | 🟠 Major

Document search patterns rely on globbing with no mention of precedence resolution.

You list multiple patterns but don’t specify how to choose when multiple matches exist. This can result in inconsistent document selection. Add deterministic selection rules (e.g., prefer most recent, exact match, or prompt user).

As per coding guidelines: "Look for what's missing, not just what's wrong."


98-100: ⚠️ Potential issue | 🟡 Minor

Instruction typo causes mis-execution.

“read then entire document” is ambiguous and could be interpreted incorrectly. It should be “read the entire document.” This is a functional instruction to the agent, not a style nit.

As per coding guidelines: "Be skeptical of everything."


232-234: ⚠️ Potential issue | 🟡 Minor

Menu handling references an anchor that may not exist.

Redisplay Menu Options” assumes a GitHub-generated anchor, but this file’s headers include “### 10. Present MENU OPTIONS” and may produce a different anchor. If the anchor is wrong, navigation breaks. Ensure the anchor matches GitHub rules.

Based on learnings: When documenting cross-reference patterns in Markdown, ensure header anchors follow GitHub's anchor generation rules: lowercase, spaces to hyphens, remove emojis/special characters, and strip leading/trailing hyphens. Example: '### 🚨 R-001: Title' becomes '#r-001-title'. Use anchors that reflect these rules in documentation across Markdown files.

test/test-installation-components.js (1)

186-198: ⚠️ Potential issue | 🟡 Minor

Test 3 is a permanent placeholder that always passes — this silently inflates the pass count.

Line 192 asserts true unconditionally. This test has never validated anything. If path resolution testing is planned, track it as a TODO. If not, remove it so the pass count reflects reality.

🤖 Fix all issues with AI agents
In
`@src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md`:
- Line 9: The prdPurpose path points to a non-existent _bmad location; update
the prdPurpose entry in step-v-01-discovery.md to reference the actual file
location src/bmm/workflows/2-plan-workflows/create-prd/data/prd-purpose.md (or a
correct relative path from this markdown file) so the link resolves to the
existing prd-purpose.md; update the prdPurpose string value accordingly.

In
`@src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md`:
- Line 33: The markdown references use a non-existent path pattern
"{project-root}/_bmad/core/workflows/..."; update this step
(step-04-emotional-response.md) and all other workflow files using the same
pattern to point to the actual repo location "src/core/workflows/..." or add a
repository-level README explaining how "{project-root}" is resolved at runtime.
Specifically, in the current file replace
"{project-root}/_bmad/core/workflows/advanced-elicitation/workflow.md" with
"src/core/workflows/advanced-elicitation/workflow.md" and run a repo-wide search
for the "{project-root}/_bmad/core/" pattern to either correct paths to
"src/core/" or document the resolution mechanism.

In
`@src/bmm/workflows/4-implementation/code-review/steps/step-03-execute-review.md`:
- Around line 7-57: The "Execute adversarial review" step (step n="3") lacks a
defined findings output structure, so define and document a clear findings
schema (fields: id, severity, type, summary, detail, file:line, proof,
suggested_fix, reviewer, timestamp) and a storage/transfer mechanism (e.g.,
write JSON array to a findings file like review-findings.json or emit to a
shared in-memory artifact) and update the step-03-execute-review.md text to
state: how findings are created (map actions that produce findings to populate
those schema fields), where they are persisted, and how
step-04-present-and-resolve.md should consume them (path/variable and expected
schema), plus include an example record to make the contract explicit.
- Around line 21-26: The AC validation step "Determine: IMPLEMENTED, PARTIAL, or
MISSING" in step-03-execute-review.md is underspecified; add a clear decision
algorithm that defines (a) precise criteria for IMPLEMENTED (e.g., direct code
evidence + tests or documentation references covering all AC clauses), PARTIAL
(some code or tests cover subset of clauses or only non-functional aspects), and
MISSING (no code/tests/docs addressing any clause), (b) rules for evidence types
(comments/README count as weak evidence and require corroborating code or tests
to be IMPLEMENTED), (c) guidance for indirect evidence (e.g., helper functions
or generic utilities are PARTIAL unless explicitly wired or covered by
integration tests), and (d) a severity mapping that ties PARTIAL/MISSING to
HIGH/MEDIUM/LOW severities; reference the phrase "Determine: IMPLEMENTED,
PARTIAL, or MISSING" and the action block so reviewers update that section with
these explicit thresholds and examples.

In `@src/bmm/workflows/4-implementation/correct-course/workflow.md`:
- Around line 1-6: The workflow references installed_path and expects
instructions.md and checklist.md under
{project-root}/_bmad/bmm/workflows/4-implementation/correct-course
(installed_path), but the files currently live at
src/bmm/workflows/4-implementation/correct-course; fix by either moving
instructions.md and checklist.md into the directory matching installed_path
({project-root}/_bmad/bmm/workflows/4-implementation/correct-course) or update
the installed_path value in the workflow metadata to point to
src/bmm/workflows/4-implementation/correct-course so the references to
{installed_path}/instructions.md and {installed_path}/checklist.md resolve
correctly.

In `@src/bmm/workflows/4-implementation/create-story/instructions.xml`:
- Line 313: The invoke-task line references a non-existent path
"_bmad/core/tasks/validate-workflow.md"; update the invoke-task element that
currently contains "Validate against checklist at {installed_path}/checklist.md
using _bmad/core/tasks/validate-workflow.md" to point to the correct file
"src/core/tasks/validate-workflow.md" so the task resolver can find the
validate-workflow.md resource.

In `@src/bmm/workflows/4-implementation/dev-story/steps/step-02-load-context.md`:
- Around line 11-14: The parsing step (step-02-load-context.md) currently lists
actions like "Parse sections" and "Load comprehensive context" but lacks
validation; add explicit checks when parsing each named section (Story,
Acceptance Criteria, Tasks/Subtasks, Dev Notes, Dev Agent Record, File List,
Change Log, Status) to detect missing files, missing sections, empty content, or
malformed structure, and handle them by (1) returning clear validation errors or
logging and halting the workflow when critical (e.g., missing story file or Dev
Notes), (2) providing safe defaults or warnings for non-critical empty sections
(e.g., Change Log), and (3) validating structure (expected keys/format) before
extracting developer guidance; ensure these checks are performed before the
"Load comprehensive context" and that failures propagate as explicit errors
rather than failing silently.

In
`@src/bmm/workflows/4-implementation/dev-story/steps/step-08-mark-task-complete.md`:
- Around line 43-46: Initialize the missing variables before the conditional:
set review_continuation by checking the original task list for the "[AI-Review]"
prefix (e.g., scan original_task_list or task_title and produce a boolean
assigned to review_continuation), compute resolved_count as the length/size of
resolved_review_items (resolved_count = len(resolved_review_items) or
equivalent), and set date from the system-generated timestamp (call the
workflow/system date function to produce a formatted date string and assign it
to date); then use these variables in the existing check and Change Log action
so the conditional and changelog entry succeed.
- Around line 17-29: Initialize the resolved_review_items collection before use
(e.g., set resolved_review_items = [] at workflow start or at the beginning of
this step) and then, when marking review follow-ups, append the resolved item to
that list; for matching the task description to an action item in "Senior
Developer Review (AI) → Action Items", implement a fuzzy-match routine:
normalize both strings (lowercase, trim, remove prefixes like "[AI-Review]"),
try exact substring match first, then compute token-set overlap or a simple
fuzzy score (e.g., Jaccard/token intersection) and pick the highest-scoring
action item if score >= threshold (e.g., 0.6); if multiple candidates tie pick
the best score or log ambiguity, and if no match meets the threshold, log a
warning, add the task to an unresolved_review_items list and still mark the task
checkbox in "Tasks/Subtasks → Review Follow-ups (AI)" and record the resolution
note in Dev Agent Record noting that no corresponding action item was found.

In
`@src/bmm/workflows/4-implementation/dev-story/steps/step-09-mark-review-ready.md`:
- Around line 30-36: The conditional uses an uninitialized variable
{{current_sprint_status}}; initialize it or change the check so it doesn't rely
on that undefined value. Specifically, before the existing check, read the
sprint tracking setting (e.g., set current_sprint_status from the project config
or from the contents of {sprint_status} if present) so {{current_sprint_status}}
is defined, or replace the condition with a direct existence/validity test on
{sprint_status} (e.g., "if {sprint_status} file exists AND its content !=
'no-sprint-tracking'"). Ensure the code that updates
development_status[{{story_key}}] = "review" only runs after the validated
initialization of current_sprint_status or after the direct file validity check.

In `@src/bmm/workflows/4-implementation/dev-story/workflow.md`:
- Line 4: The config references an undefined placeholder {project-root} (e.g.,
in main_config) which will break loading; update the workflow to either (a)
replace {project-root} with a defined variable name and add its initialization
in the workflow config/vars (e.g., projectRoot) or (b) resolve it at startup by
computing the repository root (e.g., using process.cwd() or a locate-repo-root
helper) and interpolating that value into main_config and the other occurrence
before loading the YAML; ensure the chosen symbol (projectRoot or the resolver
function) is declared and used consistently where {project-root} appears.
- Line 43: Define the HALT condition explicitly in the workflow: add a concise
operational definition of "HALT" (what events/criteria trigger it), the exact
behavior when HALT occurs (e.g., stop execution, persist state, notify user,
rollback), and the resume semantics (manual resume, automatic retry, or
checkpoint-based continuation). Update all references (including the "HALT"
mention in the workflow and step-08) to point to that definition and specify any
user prompts or log messages that must be emitted when HALT is reached so the
workflow engine can implement consistent handling.

In `@src/bmm/workflows/document-project/workflows/deep-dive.yaml`:
- Line 10: Fix the typo in the config_source path: update the config_source
value in deep-dive.yaml (key: config_source) from
"{project-root}/_bmad/bmb/config.yaml" to
"{project-root}/_bmad/bmm/config.yaml"; also make the identical change in
full-scan.yaml so both workflows reference the existing _bmad/bmm directory and
can load config.yaml at runtime.

In `@src/core/tasks/validate-workflow.md`:
- Around line 35-37: The "Edits (if applicable)" / Step 5 flow must add a
safe-edit protocol: before applying changes (the part that currently says "ask
for confirmation before editing" and "Only apply changes after user approval"),
create a backup/snapshot and store a reversible diff (or create a temporary
branch/working copy), produce a diff preview for the user, run validation/syntax
checks on the edited copy, and implement an undo/rollback path that restores the
backup if validation fails or the user cancels; update the workflow text (the
"Edits (if applicable)" section / Step 5) to describe these steps and the
locations where backups/diffs/rollbacks are created and verified.
- Around line 10-12: The current docs allow silent failures when loading
`{project-root}/_bmad/core/config.yaml` and treating `communication_language`,
`user_name`, and `document_output_language` as optional; update the
config-loading logic (e.g., the loadConfig / resolveVariables flow) to validate
that the file exists and parses correctly, and enforce required fields or apply
explicit defaults: if parsing fails or required keys are missing, surface a
clear error via logger and abort initialization (or throw), and where defaults
are acceptable set and document them (e.g., default communication_language="en",
document_output_language="en", and require user_name or fail); ensure the
validation is clearly referenced in the README/docs and that the validation
function name (e.g., validateConfig or ensureRequiredConfig) performs these
checks.
- Around line 23-24: Replace the vague "Infer the target file from the checklist
context or workflow inputs" with concrete inference rules: look for explicit
keys in checklist entries and workflow inputs (e.g., "file", "path", "target",
"filePath"), accept single paths or glob patterns, normalize/resolve relative
paths, check repository for existence and that the file type matches expected
(e.g., .yaml/.yml/.json), and parse ambiguous entries by preferring explicit
file fields, then path-like tokens, then first matching file from globs; if no
valid candidate found, prompt the user with a clear schema example (e.g.,
"Please provide the exact file path (relative to repo root), e.g.,
./workflows/ci.yml") and validate the user's reply by normalizing and verifying
existence before proceeding.

In `@src/utility/agent-components/handler-validate-workflow.txt`:
- Line 3: The code currently mandates loading
{project-root}/_bmad/core/tasks/validate-workflow.md with no checks; add robust
error handling around the load so missing/inaccessible/malformed files are
detected and handled gracefully: before attempting to read, verify existence and
read permissions for _bmad/core/tasks/validate-workflow.md, wrap the read/parse
operation in a try/catch, log a clear error via the existing logger (include the
path and caught error), and implement a fallback path—either fail fast with a
descriptive exception, return a default/embedded validation workflow, or mark
the agent as degraded—so callers of the loader get a deterministic result;
update the loader routine that performs the file read (the code that issues the
"MUST LOAD" instruction) to include these checks and fallbacks.

In `@src/utility/agent-components/handler-workflow.txt`:
- Line 4: The "CRITICAL: Always LOAD
{project-root}/_bmad/core/tasks/workflow.md" directive lacks fallback/error
handling; update the loader that enforces this (the code that resolves and reads
workflow.md) to first check file existence and readability for
{project-root}/_bmad/core/tasks/workflow.md, attempt a safe path resolution, and
if missing or unreadable either (a) load a bundled default workflow.json/md
fallback or (b) emit a clear error via the agent logger and fail fast with a
descriptive message; ensure the change updates the same component that
references the "CRITICAL: Always LOAD" directive so it logs the missing-file
path and underlying error before using the fallback or aborting.

In `@tools/cli/installers/lib/ide/shared/workflow-command-generator.js`:
- Line 11: Update the constructor in workflow-command-generator.js to use the
shared constant: import BMAD_FOLDER_NAME from './path-utils' and change the
constructor signature's default from the hardcoded 'bmad' to BMAD_FOLDER_NAME;
adjust any references to the parameter if necessary but keep the parameter name
(bmadFolderName) the same so behavior is unchanged while ensuring it defaults to
the canonical BMAD_FOLDER_NAME constant.

This PR is intentionally large due to coupled workflow.md migration and step-flow parity updates across runtime, installer, and tests.\n\nFollow-up work can be split by domain if maintainers prefer smaller review surfaces.
@dickymoore
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Feb 8, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (14)
tools/cli/installers/lib/ide/shared/bmad-artifacts.js (1)

142-148: ⚠️ Potential issue | 🟠 Major

readdir without withFileTypes will blow up on subdirectories.

getAgentsFromDir (line 87) correctly uses { withFileTypes: true } and checks entry.isDirectory(). Here, getTasksFromDir does a bare readdir — if a subdirectory happens to end with .md or .xml (or even if it doesn't, it's fragile), fs.readFile on a directory path will throw an unhandled error. At minimum, stat the entry or use withFileTypes.

Proposed fix
- const files = await fs.readdir(dirPath);
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });

- for (const file of files) {
+ for (const entry of entries) {
+   if (entry.isDirectory()) continue;
+   const file = entry.name;
src/core/tasks/help.md (5)

9-16: ⚠️ Potential issue | 🟠 Major

Specify CSV schema and define fuzzy-matching algorithm.

KEY RULES references multiple fields (phase, module, required, outputs) that presumably come from the CSV catalog loaded in step 1, but the structure of bmad-help.csv is never documented in this file. Line 14 states "Descriptions contain routing" without clarifying which descriptions (CSV column? Workflow metadata?). Line 16 mentions "fuzzy-match found files to workflow rows" without specifying the matching algorithm, tolerance, or fallback behavior when multiple matches are found.

Document the expected CSV columns and their semantics. Specify the fuzzy-matching algorithm (e.g., Levenshtein distance, edit distance threshold, glob patterns) or reference where it's defined. Clarify which "descriptions" contain routing logic.


18-23: ⚠️ Potential issue | 🟠 Major

Define "recent workflows" and specify module detection precedence.

Line 23 instructs detecting the active module from "conversation context, recent workflows, or user query keywords," but:

  • "Recent workflows" is not defined. How many workflows back? Within the current conversation only, or persisted across sessions?
  • No algorithm or precedence is specified. When context and keywords conflict, which takes priority?
  • No handling for cross-module workflows or scenarios where the user is working in multiple modules simultaneously.

Provide a clear detection algorithm with precedence rules and specify the scope of "recent workflows."


36-38: ⚠️ Potential issue | 🟠 Major

Add validation and error handling for config file scanning.

Step 2 instructs scanning each folder under _bmad/ for config.yaml and extracting specific fields, but provides no error handling or validation:

  • What if a config.yaml is missing or malformed?
  • What if communication_language or project_knowledge fields are absent?
  • What if output-location variables cannot be resolved?

Without validation rules, the task could fail silently or behave unpredictably when encountering incomplete or invalid module configurations. Specify default values or fallback behavior for missing fields, and define how to handle parse errors.


36-36: ⚠️ Potential issue | 🔴 Critical

Document the bmad-help.csv schema.

Step 1 loads bmad-help.csv, and KEY RULES, EXECUTION, and RECOMMENDED OUTPUT FORMAT reference numerous CSV columns (phase, sequence, module, required, outputs, command, agent, name, description, and possibly agent-command), yet the CSV schema is never documented in this file.

Without a schema definition, maintainers cannot validate the CSV, and the task instructions are incomplete. Add a "CSV SCHEMA" section documenting each expected column, its data type, whether it's required, and its purpose. Include an example row if helpful.


34-78: ⚠️ Potential issue | 🟠 Major

Add safeguards for edge cases and operational limits.

The EXECUTION section lacks handling for several edge cases and operational constraints:

  • Circular dependencies: Workflows that reference each other (e.g., A → B → A) could cause infinite loops when resolving next steps. Specify detection and handling (e.g., break the cycle, warn the user).
  • Ambiguous matches: When artifact search finds zero or multiple matches for a workflow's outputs pattern, no tie-breaking or fallback logic is specified.
  • Resource limits: No bounds on directory traversal depth, number of files scanned, or maximum catalog size. An unbounded search could hang or exhaust memory.
  • Module conflicts: If two modules define workflows with the same code or overlapping outputs patterns, no conflict resolution is specified.

Add explicit error handling, tie-breaking rules, and resource constraints to prevent operational failures and ambiguous behavior.

tools/cli/installers/lib/ide/templates/combined/kiro-workflow-yaml.md (1)

1-15: ⚠️ Potential issue | 🟠 Major

Missing error handling: no instructions for malformed or missing workflow files.

Nowhere in the template are there instructions for what the agent should do if:

  • workflow.md doesn't exist at the expected path
  • {{path}} points to a malformed or unreadable workflow config
  • Template variable substitution fails
  • The workflow config references non-existent tasks or steps

The agent will fail silently or unpredictably instead of surfacing actionable errors to the user.

🛡️ Suggested error handling addition
 </steps>
+
+**Error Handling:**
+- If workflow.md or the workflow config cannot be loaded, report the full file path attempted and halt execution with a clear error message.
+- If template variables are undefined, log the missing variable names and request user configuration.
tools/cli/installers/lib/ide/_base-ide.js (1)

331-378: ⚠️ Potential issue | 🟠 Major

relativePath loses directory nesting in recursive calls — all nested workflows get a flat filename.

findWorkflowFiles(dir) recurses by calling this.findWorkflowFiles(fullPath) (line 345), where fullPath is the subdirectory. Inside the recursive call, path.relative(dir, fullPath) on line 366 computes the path relative to the current (subdirectory) dir, not the original top-level directory. This means a workflow at core/workflows/advanced-elicitation/workflow.md would have relativePath: "workflow.md" instead of "advanced-elicitation/workflow.md".

Compare with manifest-generator.js (line 146), which correctly threads a relativePath parameter through recursion to preserve nesting:

const newRelativePath = relativePath ? `${relativePath}/${entry.name}` : entry.name;
await findWorkflows(fullPath, newRelativePath);

This likely causes duplicate names or incorrect path resolution when multiple workflow.md files exist in different subdirectories.

Proposed fix
-  async findWorkflowFiles(dir) {
+  async findWorkflowFiles(dir, baseDir = null) {
     const workflows = [];
+    if (!baseDir) baseDir = dir;
 
     if (!(await fs.pathExists(dir))) {
       return workflows;
@@ -345,1 +345,1 @@
       if (entry.isDirectory()) {
         // Recursively search subdirectories
-        const subWorkflows = await this.findWorkflowFiles(fullPath);
+        const subWorkflows = await this.findWorkflowFiles(fullPath, baseDir);
         workflows.push(...subWorkflows);
       } else if (entry.isFile() && /^workflow(?:-[^/]+)?\.md$/.test(entry.name)) {
@@ -366,1 +366,1 @@
-              relativePath: path.relative(dir, fullPath),
+              relativePath: path.relative(baseDir, fullPath),
tools/cli/installers/lib/modules/manager.js (1)

1143-1157: ⚠️ Potential issue | 🟠 Major

Vendoring regexes hardcode _bmad/bmad — won't match custom folder names.

Lines 1145 and 1157 use (?:_?bmad) to parse workflow source and install paths:

sourceWorkflowPath.match(/\{project-root\}\/(?:_?bmad)\/([^/]+)\/workflows\/(.+)/)

But this.bmadFolderName can be any user-configured value (it's settable via setBmadFolderName). If a project uses a custom folder name (e.g., .bmad or my-bmad), these regexes will fail to match, and the vendoring will silently skip valid workflow paths with a "Could not parse workflow path" warning.

Consider deriving the pattern from this.bmadFolderName or making the folder name segment more permissive:

Proposed fix
-        const sourceMatch = sourceWorkflowPath.match(/\{project-root\}\/(?:_?bmad)\/([^/]+)\/workflows\/(.+)/);
+        const sourceMatch = sourceWorkflowPath.match(/\{project-root\}\/[^/]+\/([^/]+)\/workflows\/(.+)/);

Or more precisely, escape and inject this.bmadFolderName:

+        const escapedFolder = this.bmadFolderName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+        const sourceMatch = sourceWorkflowPath.match(new RegExp(`\\{project-root\\}/${escapedFolder}/([^/]+)/workflows/(.+)`));
tools/cli/installers/lib/ide/_config-driven.js (1)

385-390: ⚠️ Potential issue | 🟡 Minor

Broad _bmad string replacement risks corrupting template content.

Line 387 does replaceAll('_bmad', this.bmadFolderName). This replaces every occurrence of the literal _bmad in the rendered template — including inside prose, comments, or path documentation that mentions _bmad descriptively. Line 390 already handles the proper {{bmadFolderName}} placeholder. If this.bmadFolderName is actually _bmad (which it is by default from BMAD_FOLDER_NAME), it's a no-op, but if a user customizes the folder name, legitimate _bmad references in documentation text get mangled.

Consider scoping the replacement to paths only, or at minimum adding a path-context marker (e.g., {_bmad}) instead of bare substring replacement.

src/bmm/workflows/document-project/instructions.md (4)

121-123: ⚠️ Potential issue | 🟠 Major

Resume path trusts cached project types without validation.
If the CSV schema changed or cached IDs are stale, you’ll resume with invalid requirements. That’s a correctness bug, not a convenience.

🔧 Proposed fix
-    <action>For each cached project_type_id, load ONLY the corresponding row from: {documentation_requirements_csv}</action>
+    <action>For each cached project_type_id, load ONLY the corresponding row from: {documentation_requirements_csv}</action>
+    <action>If any cached ID is missing, warn and fall back to fresh scan (Step 3)</action>

194-203: ⚠️ Potential issue | 🟠 Major

subworkflow_success is never initialized in non-resume flows.
You check it right after delegated workflows, but only the resume branch sets it to false first. That leaves undefined state and can skip failure handling.

🔧 Proposed fix
   <check if="user selects 1">
     <action>Set workflow_mode = "full_rescan"</action>
+    <action>Set subworkflow_success = false</action>
     <action>Display: "Starting full project rescan..."</action>
     <action>Read fully and follow: {installed_path}/workflows/full-scan-instructions.md</action>
     <action>Set subworkflow_success = true only if delegated workflow completed without HALT/error</action>
     <check if="subworkflow_success != true">

Apply the same initialization before deep-dive and initial-scan delegations.

Also applies to: 206-216, 225-234


94-164: ⚠️ Potential issue | 🟠 Major

No invalid-input handling for resume choice.
If the user enters anything other than 1/2/3, there’s no branch, and the workflow proceeds in an undefined state.

🔧 Proposed fix
   <ask>...Your choice [1/2/3]:</ask>
   <check if="user selects 1"> ... </check>
   <check if="user selects 2"> ... </check>
   <check if="user selects 3"> ... </check>
+  <check if="user selects invalid">
+    <output>Invalid choice. Please enter 1, 2, or 3.</output>
+    <action>Repeat prompt</action>
+  </check>

183-222: ⚠️ Potential issue | 🟠 Major

No invalid-input handling for existing-doc choice.
Same issue as above, just a different prompt. Undefined input means undefined behavior.

🔧 Proposed fix
   <ask>...Your choice [1/2/3]:</ask>
   <check if="user selects 1"> ... </check>
   <check if="user selects 2"> ... </check>
   <check if="user selects 3"> ... </check>
+  <check if="user selects invalid">
+    <output>Invalid choice. Please enter 1, 2, or 3.</output>
+    <action>Repeat prompt</action>
+  </check>
🤖 Fix all issues with AI agents
In `@src/core/tasks/validate-workflow.md`:
- Around line 15-17: The docs and config disagree on language default formats:
update the fallback defaults in validate-workflow.md so the values for
communication_language and document_output_language match the defaults defined
in src/core/module.yaml (use "English" instead of "en"), ensuring templates that
render "Communicate all responses in {communication_language}" show the full
name; change the two fallback entries in validate-workflow.md from "en" to
"English" and verify any related text templates reference the same symbol names
(communication_language, document_output_language).

In `@tools/cli/installers/lib/ide/templates/combined/kiro-workflow-yaml.md`:
- Around line 12-13: Update the template text in kiro-workflow-yaml.md to
explicitly show how to pass the workflow path to the workflow.md task by
specifying the exact parameter mechanism: indicate that the task accepts a YAML
parameter key named workflow-config and show that its value must be the path
{{bmadFolderName}}/{{path}} when invoking workflow.md (e.g., add a short example
invocation that uses workflow-config: {{bmadFolderName}}/{{path}} under the
workflow.md task's parameters), so readers know to set the workflow-config YAML
key rather than guessing CLI flags, env vars, or function args.
🟠 Major comments (25)
src/core/tasks/help.md-71-75 (1)

71-75: ⚠️ Potential issue | 🟠 Major

Define agent-command and specify default for communication_language.

Line 74 references "the platform's command format for agent-command," but agent-command is never defined in this file, nor is it included in the documented CSV schema (which is also missing). It's unclear if agent-command is a CSV column, a computed value, or a typo for agent.

Line 72 instructs presenting output in {communication_language} "when available in module config," but provides no default or fallback behavior when this field is absent. Should the task default to English? Preserve the user's input language? Fail?

Document agent-command in the CSV schema section and specify the default language behavior.

src/core/tasks/help.md-48-77 (1)

48-77: 🛠️ Refactor suggestion | 🟠 Major

Provide a complete example of the recommended output format.

The RECOMMENDED OUTPUT FORMAT section describes the structure across 30 lines but provides no end-to-end example showing how a complete response should look when presenting optional and required items together. A full example would clarify:

  • How multiple optional items are formatted in sequence.
  • How the transition from optional to required items appears.
  • How communication_language, fresh context instructions, and validation recommendations integrate into the output.

Add a "EXAMPLE OUTPUT" subsection showing a representative complete response for a typical scenario (e.g., user completed workflow X, presenting optional Y and required Z in module M).

src/core/tasks/help.md-4-4 (1)

4-4: ⚠️ Potential issue | 🟠 Major

Define standalone: true and reconcile with "calling process" reference.

The frontmatter declares standalone: true, suggesting this task can run independently, yet line 78 instructs "Return to the calling process after presenting recommendations." If the task is standalone, there may be no calling process. This contradiction needs resolution.

Additionally, the standalone field is not documented anywhere in this file. Specify what standalone: true means, how it differs from standalone: false (or its absence), and whether line 78's instruction applies only when invoked as a subtask.

src/core/tasks/help.md-25-32 (1)

25-32: ⚠️ Potential issue | 🟠 Major

Eliminate vague instructions and specify artifact search paths.

Lines 28-29 state "Did someone state they completed something? Proceed as if that was the input," but "proceed as if that was the input" is not actionable—input to what? How should the task behave differently?

Line 30 references "resolved artifact locations" without defining what "resolved" means or which directories to search. Line 31 mentions "If an index.md exists" without specifying where (project root? _bmad/? Each module directory?).

Additionally, this section omits "user query keywords" mentioned in MODULE DETECTION (line 23), creating an inconsistency in the detection logic.

Clarify the artifact search algorithm: which directories, search depth, file name patterns. Specify the exact path(s) for index.md. Define what "proceed as if that was the input" means in operational terms.

src/core/tasks/help.md-60-69 (1)

60-69: ⚠️ Potential issue | 🟠 Major

Avoid platform-specific syntax in examples and generalize instructions.

The example in lines 66-68 uses /tech-writer syntax, which assumes a slash-command interface (e.g., Slack, Discord, some AI chat UIs). Not all platforms or invocation methods support this convention (e.g., CLI tools, API calls, or conversational agents without slash commands).

Replace the example with platform-agnostic wording such as "Load the agent named 'Tech Writer' using your platform's agent invocation method, then ask..." or parameterize the example with a placeholder like {agent-invocation-syntax} and instruct the task to adapt to the user's environment.

src/bmm/workflows/4-implementation/correct-course/workflow.md-55-55 (1)

55-55: ⚠️ Potential issue | 🟠 Major

Validate language configuration values before use.

Line 55 instructs the agent to communicate in {communication_language} and generate documents in {document_output_language}, but there is no validation that these variables contain supported language codes (e.g., ISO 639-1: en, es, fr). If a user configures an invalid or unsupported language, the agent could produce garbled output or fail silently.

Add validation in the Initialization section:

- Validate `communication_language` and `document_output_language` are supported ISO 639-1 codes. If unsupported, HALT with error listing available languages.
src/bmm/workflows/4-implementation/correct-course/workflow.md-38-46 (1)

38-46: ⚠️ Potential issue | 🟠 Major

Specify error handling for config loading and variable resolution.

Lines 38-46 instruct the agent to load config and resolve 9 variables but provide no guidance on what to do if:

  • config.yaml is missing, malformed, or unreadable
  • Any variable is undefined or cannot be resolved

Without explicit HALT or fallback instructions, different agent implementations may fail silently, emit warnings, or substitute empty strings—leading to inconsistent workflow behavior.

Suggested fix: add explicit error handling
 ## Initialization
-- Load config from `{project-root}/_bmad/bmm/config.yaml`.
+- Load config from `{project-root}/_bmad/bmm/config.yaml`. If config is missing or malformed, HALT with error.
 - Resolve variables:
   - `user_name`
   - `communication_language`
   - `document_output_language`
   - `user_skill_level`
   - `planning_artifacts`
   - `implementation_artifacts`
   - `project_knowledge`
+  - If any required variable is undefined, HALT and list missing variables.
src/bmm/workflows/4-implementation/correct-course/workflow.md-67-67 (1)

67-67: ⚠️ Potential issue | 🟠 Major

Step 2 fallback exposes a design flaw: Step 1 can fail silently.

Line 67 states "If {{workflow_path}} is not set from step 1, repeat path resolution using checklist.md." This implies that Step 1 might complete execution without setting {{workflow_path}}, which contradicts the explicit HALT instruction in lines 61-62.

If Step 1's HALT is enforced, this fallback is dead code. If the HALT is not enforced (e.g., some agent implementations ignore it), then Step 1 fails silently and Step 2 must recover—an unreliable pattern.

Fix: Remove the fallback in Step 2 and ensure Step 1's HALT is mandatory:

   <step n="2" goal="Validate proposal quality">
-    <action>If {{workflow_path}} is not set from step 1, repeat path resolution using checklist.md</action>
+    <action>Assert {{workflow_path}} is set. If not, HALT with internal error (Step 1 should have resolved path).</action>
     <invoke-task>Validate against checklist at {{workflow_path}}/checklist.md using {project-root}/_bmad/core/tasks/validate-workflow.md</invoke-task>
   </step>
src/bmm/workflows/4-implementation/correct-course/workflow.md-68-68 (1)

68-68: ⚠️ Potential issue | 🟠 Major

Declare checklist.md in input_file_patterns and specify task error handling.

Line 68 references {{workflow_path}}/checklist.md but checklist.md is not declared in the input_file_patterns section (lines 6-35). This breaks the pattern established for other inputs (prd, epics, architecture, etc.) and makes it harder for tooling to pre-validate that required files exist.

Additionally, the <invoke-task> directive provides no error handling: what happens if validate-workflow.md task fails, is missing, or returns validation errors? Does the workflow HALT, log warnings, or continue?

Fix 1: Add checklist to input_file_patterns:

+  checklist:
+    description: "Validation checklist for proposal quality"
+    whole: "{installed_path}/checklist.md"
+    fallback: "{source_path}/checklist.md"
+    load_strategy: "FULL_LOAD"

Fix 2: Specify task error handling:

-    <invoke-task>Validate against checklist at {{workflow_path}}/checklist.md using {project-root}/_bmad/core/tasks/validate-workflow.md</invoke-task>
+    <invoke-task on-error="HALT">
+      Validate against checklist at {{workflow_path}}/checklist.md 
+      using {project-root}/_bmad/core/tasks/validate-workflow.md.
+      If validation fails, HALT and report failed checklist items.
+    </invoke-task>
src/bmm/workflows/4-implementation/correct-course/workflow.md-58-62 (1)

58-62: ⚠️ Potential issue | 🟠 Major

Strengthen path resolution logic and clarify precedence.

The path resolution in lines 58-62 has several ambiguities:

  1. "exists and is readable" does not specify what permissions are required (read-only? execute for directories?). On Unix systems, directory traversal requires execute permission, not just read.
  2. Error message format is unspecified: "emit an error listing both paths and HALT" could be plain text, structured JSON, or a logged warning. Inconsistent error formats hinder debugging.
  3. No check for both paths existing: If both {installed_path}/instructions.md and {source_path}/instructions.md exist, the code silently prefers installed_path. This is implicit and could surprise developers testing from source.
Suggested improvements
     <action>Resolve workflow content path:
-      - If `{installed_path}/instructions.md` exists and is readable, set {{workflow_path}} = `{installed_path}`
-      - Else if `{source_path}/instructions.md` exists and is readable, set {{workflow_path}} = `{source_path}`
-      - Else emit an error listing both paths and HALT
+      - Check if `{installed_path}/instructions.md` exists with read permission. If yes, set {{workflow_path}} = `{installed_path}` and log "Using installed path".
+      - Else check if `{source_path}/instructions.md` exists with read permission. If yes, set {{workflow_path}} = `{source_path}` and log "Fallback to source path".
+      - Else HALT with error: "Cannot locate instructions.md. Tried:\n  - {installed_path}/instructions.md\n  - {source_path}/instructions.md"
     </action>
tools/cli/installers/lib/ide/templates/combined/kiro-workflow-yaml.md-14-14 (1)

14-14: ⚠️ Potential issue | 🟠 Major

Underspecified save instruction: WHERE, WHAT FORMAT, and WHEN to save outputs?

Step 5 demands "Save outputs after EACH section when generating any documents from templates" but omits critical details:

  • WHERE: Local filesystem? Git? A specific directory structure?
  • WHAT FORMAT: Raw text? Markdown? JSON?
  • WHAT constitutes a "section"? Is it defined by the workflow, the template, or arbitrary agent judgment?
  • HOW: Overwrite? Append? Version control?

This vagueness guarantees inconsistent behavior across agents and environments.

📋 Suggested clarification
-5. Save outputs after EACH section when generating any documents from templates
+5. After completing each step marked `<step-output>` in the workflow, persist the generated content to the designated output path specified in the workflow's `output-location` metadata. Use UTF-8 encoding and preserve formatting.
src/bmm/workflows/4-implementation/code-review/steps/step-03-execute-review.md-121-132 (1)

121-132: ⚠️ Potential issue | 🟠 Major

Forced minimum finding count incentivizes false positives.

The <check if="total_issues_found lt 3"> gate at line 121 forces the reviewer agent to manufacture additional findings even when the code may be genuinely clean. This undermines the credibility of the entire review — if stakeholders learn that 3 findings are always guaranteed regardless of code quality, they'll discount all findings. A review that says "no significant issues found" is a valid and valuable outcome.

Consider replacing the hard floor with a confidence check instead, e.g., "If fewer than 3 issues found, re-examine with fresh perspective and confirm that no issues were overlooked — if the code is clean, state that explicitly with supporting evidence."

src/bmm/workflows/4-implementation/retrospective/workflow.md-7-17 (1)

7-17: ⚠️ Potential issue | 🟠 Major

{{epic_num}} and {{prev_epic_num}} are used but never defined or collected.

Lines 12 and 16 reference {{epic_num}} and {{prev_epic_num}} in glob patterns, but neither variable appears in the Initialization section (lines 34-48) or anywhere else in this file. Without a mechanism to prompt the user for these values or resolve them from context, the patterns will contain literal {{…}} text and match nothing.

Add these to the Initialization variable list with a clear source (user prompt, sprint-status lookup, etc.).

tools/cli/installers/lib/ide/shared/workflow-command-generator.js-206-215 (1)

206-215: ⚠️ Potential issue | 🟠 Major

Fallback path src/core/tasks/workflow.md won't exist in installed projects.

The launcher content specifies a fallback at {project-root}/src/core/tasks/workflow.md (line 209). In a user's installed project, files live under _bmad/, not src/. This fallback would only work in the BMAD-METHOD source repository itself, making it useless (or misleading) for end users. If the primary path is missing in a real project, this fallback silently fails too, and the error message on line 212-213 won't help diagnose the real issue (missing installation).

Consider either removing the fallback or pointing it to an alternative installed location.

tools/cli/installers/lib/ide/shared/workflow-command-generator.js-115-120 (1)

115-120: 🛠️ Refactor suggestion | 🟠 Major

Redundant template path computation — templatePath is identical to this.templatePath.

Line 117 computes path.join(path.dirname(this.templatePath), 'workflow-commander.md'), which resolves to the exact same value as this.templatePath set in the constructor (line 12). This is dead logic left over from the removal of conditional YAML/XML template selection.

Proposed fix
   async generateCommandContent(workflow, bmadDir) {
-    // Determine template based on workflow file type
-    const templatePath = path.join(path.dirname(this.templatePath), 'workflow-commander.md');
-
     // Load the appropriate template
-    const template = await fs.readFile(templatePath, 'utf8');
+    const template = await fs.readFile(this.templatePath, 'utf8');
src/bmm/workflows/4-implementation/create-story/workflow.md-176-180 (1)

176-180: ⚠️ Potential issue | 🟠 Major

{{previous_story_num}} is never computed — the agent has no way to resolve this variable.

Line 177 references {{story_dir}}/{{epic_num}}-{{previous_story_num}}-*.md, but this variable is not defined or computed anywhere in the workflow. The Initialization section (lines 32-39) defines story_dir, epic_num, story_num, etc., but previous_story_num is absent. The agent would need to derive this as story_num - 1, but that instruction is missing.

Proposed fix — add explicit computation
     <check if="story_num > 1">
+      <action>Set {{previous_story_num}} = {{story_num}} - 1</action>
       <action>Load previous story file: {{story_dir}}/{{epic_num}}-{{previous_story_num}}-*.md</action>
tools/cli/installers/lib/core/manifest-generator.js-755-767 (1)

755-767: ⚠️ Potential issue | 🟠 Major

Agent manifest CSV fields written without quote escaping — injection risk.

writeAgentManifest (line 763) interpolates agent.name, agent.displayName, agent.title, and agent.icon directly into the CSV without escaping embedded double quotes. If any of these fields contain a " character, the resulting CSV will be structurally broken.

Contrast with writeWorkflowManifest (line 733) which correctly uses escapeCsv() for every field. The same inconsistency applies to writeTaskManifest (line 781) and writeToolManifest (line 799), where name and displayName are unescaped.

Proposed fix — use escapeCsv consistently
   async writeAgentManifest(cfgDir) {
     const csvPath = path.join(cfgDir, 'agent-manifest.csv');
+    const escapeCsv = (value) => `"${String(value ?? '').replaceAll('"', '""')}"`;

     // Create CSV header with persona fields
     let csv = 'name,displayName,title,icon,role,identity,communicationStyle,principles,module,path\n';
     const sortedAgents = [...this.agents].sort((a, b) => `${a.module}:${a.name}`.localeCompare(`${b.module}:${b.name}`));

     for (const agent of sortedAgents) {
-      csv += `"${agent.name}","${agent.displayName}","${agent.title}","${agent.icon}","${agent.role}","${agent.identity}","${agent.communicationStyle}","${agent.principles}","${agent.module}","${agent.path}"\n`;
+      csv += [
+        escapeCsv(agent.name), escapeCsv(agent.displayName), escapeCsv(agent.title),
+        escapeCsv(agent.icon), escapeCsv(agent.role), escapeCsv(agent.identity),
+        escapeCsv(agent.communicationStyle), escapeCsv(agent.principles),
+        escapeCsv(agent.module), escapeCsv(agent.path),
+      ].join(',') + '\n';
     }

Apply the same pattern to writeTaskManifest and writeToolManifest.

tools/cli/installers/lib/core/manifest-generator.js-386-404 (1)

386-404: ⚠️ Potential issue | 🟠 Major

MD tasks without frontmatter are accepted with unsafe defaults, inconsistent with workflow handling elsewhere.

For .md tasks in getTasksFromDir(), when the frontmatter regex doesn't match (line 391), the code falls through without a continue statement. The task is added with default standalone = true and an empty description. This differs from findWorkflowFiles() in the same file (line 356) and _base-ide.js (line 357), which both continue past MD files without frontmatter.

This creates a vulnerability: stray .md files in task directories (e.g., README.md) would be silently accepted as valid standalone tasks. While no such files currently exist, the inconsistency should be resolved for robustness. Either:

  1. Add continue after the frontmatter check fails to align with workflow handling, or
  2. Document why tasks intentionally default to standalone = true and justify the difference
src/utility/agent-components/handler-workflow.txt-4-6 (1)

4-6: ⚠️ Potential issue | 🟠 Major

Fallback loader path references the source tree (src/core/tasks/workflow.md), which won't exist in installed projects.

The primary path (_bmad/core/tasks/workflow.md) is the installed location. The fallback (src/core/tasks/workflow.md) only exists if the agent runs from within the BMAD-METHOD repo itself during development. For end-user installations, both paths resolve to nothing useful if the primary is broken, making the fallback effectively dead code in production.

Consider making the fallback a different installed location or documenting that this fallback is development-only.

src/core/tasks/validate-workflow.md-34-37 (1)

34-37: ⚠️ Potential issue | 🟠 Major

Validation target file types omit .md — the very format this PR canonicalizes.

Line 34 lists .yaml, .yml, .json as expected file types for validation candidates, but .md is conspicuously absent. This task is invoked by MD-based workflows to validate MD-based workflow files. Similarly, line 37's example prompt suggests ./workflows/ci.yml — a YAML example in a PR that eliminates YAML workflows.

Suggested fix
-   - Validate candidate existence and expected file type (`.yaml`, `.yml`, `.json`, or checklist-defined extension).
+   - Validate candidate existence and expected file type (`.md`, `.yaml`, `.yml`, `.json`, or checklist-defined extension).
-     - `Please provide the exact file path (relative to repo root), e.g. ./workflows/ci.yml`
+     - `Please provide the exact file path (relative to repo root), e.g. ./workflows/create-story/workflow.md`
src/bmm/workflows/document-project/instructions.md-79-83 (1)

79-83: ⚠️ Potential issue | 🟠 Major

State-file existence checks use inconsistent paths.
You check {output_folder}/project-scan-report.json in the action, but the condition uses bare project-scan-report.json, which can point at the wrong directory.

🔧 Proposed fix
-<check if="project-scan-report.json exists">
+<check if="{output_folder}/project-scan-report.json exists">
...
-<check if="project-scan-report.json does not exist">
+<check if="{output_folder}/project-scan-report.json does not exist">

Also applies to: 169-172

src/bmm/workflows/document-project/instructions.md-87-88 (1)

87-88: ⚠️ Potential issue | 🟠 Major

{{timestamp}} is never initialized for archive names.
You use {{timestamp}} in archive paths without ever setting it, so the archive filename is undefined.

🔧 Proposed fix
-  <action>Archive old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json</action>
+  <action>Set archive_timestamp = current_time_iso</action>
+  <action>Archive old state file to: {output_folder}/.archive/project-scan-report-{{archive_timestamp}}.json</action>

Also applies to: 155-157

src/bmm/workflows/document-project/instructions.md-82-83 (1)

82-83: ⚠️ Potential issue | 🟠 Major

Age calculation assumes last_updated exists and is valid.
If last_updated is missing or malformed, the age check becomes unreliable and can misroute the flow.

🔧 Proposed fix
-  <action>Calculate age of state file (current time - last_updated)</action>
+  <action>Validate last_updated; if missing/invalid, treat state as stale and start fresh</action>
+  <action>Calculate age of state file (current time - last_updated)</action>
src/bmm/workflows/document-project/instructions.md-23-31 (1)

23-31: ⚠️ Potential issue | 🟠 Major

Don’t silently swallow malformed status files.
Right now you treat missing/unreadable/malformed the same and continue without telling the user what went wrong. That hides data loss and makes debugging impossible.

🔧 Proposed fix
 <action>Attempt to load workflow status directly from `{output_folder}/bmm-workflow-status.yaml`:
   - If file exists, is readable, and parses correctly:
     - Set status_exists = true
     - Set status_file_found = true
     - Set standalone_mode = false
     - Set status_file_path = `{output_folder}/bmm-workflow-status.yaml`
     - Extract field_type, warning, suggestion, next_workflow, next_agent if present
   - If file is missing, unreadable, or malformed:
-    - Keep defaults and continue in standalone mode
+    - Output: "⚠️ Unable to read workflow status. Continuing without progress tracking."
+    - Keep defaults and continue in standalone mode
 </action>
src/bmm/workflows/document-project/instructions.md-80-83 (1)

80-83: ⚠️ Potential issue | 🟠 Major

No guard for unreadable/malformed state file.
You immediately “Read state file and extract…” with no failure branch. If the JSON is corrupt, the workflow will likely crash or use undefined values.

🔧 Proposed fix
 <check if="{output_folder}/project-scan-report.json exists">
-  <action>Read state file and extract: timestamps, mode, scan_level, current_step, completed_steps, project_classification</action>
+  <action>Attempt to read state file; if parse fails, display error, archive the file, and continue to Step 3</action>
+  <action>Read state file and extract: timestamps, mode, scan_level, current_step, completed_steps, project_classification</action>
🟡 Minor comments (25)
tools/cli/installers/lib/ide/shared/bmad-artifacts.js-156-169 (1)

156-169: ⚠️ Potential issue | 🟡 Minor

Frontmatter parsing has a few fragility concerns.

  1. Silent catch (line 166): Swallowing all parse errors means a typo in frontmatter (e.g. bad YAML indentation) silently includes a task that should have been filtered. At minimum, log a warning so debugging isn't a mystery.

  2. Regex won't match a BOM-prefixed file: If any .md file has a UTF-8 BOM (\uFEFF), the ^--- anchor fails. This is an edge case but fs.readFile with utf8 encoding does not strip BOM on all Node versions.

  3. No type guard on yaml.parse result: If frontmatter contains only a scalar (e.g., ---\ntrue\n---), yaml.parse returns a non-object. Accessing .internal on a boolean won't throw but also won't match — defaults kick in, silently including the file. A quick typeof frontmatter === 'object' && frontmatter !== null guard would make intent explicit.

src/core/tasks/help.md-46-51 (1)

46-51: ⚠️ Potential issue | 🟡 Minor

Complete the incomplete sentence and define stopping conditions.

Line 46 states "Format per the following" which is grammatically incomplete (should be "...the following format:" or similar).

Line 50 instructs "List optional workflows until a required step is reached," but provides no stopping condition or guidance for edge cases:

  • What if there are no required steps?
  • What if multiple required steps exist at the same level?
  • Should all required steps be shown, or only the first one?

Complete the sentence and specify the exact stopping logic for listing optional vs. required items.

src/core/tasks/help.md-40-41 (1)

40-41: ⚠️ Potential issue | 🟡 Minor

Clarify documentation discovery strategy and content reading scope.

Step 3 mentions reading "architecture docs, project overview, tech stack references" but doesn't specify:

  • Which file names or directory patterns to scan (e.g., should the task search for specific names like architecture.md, README.md, or use glob patterns?)
  • How much content to read from discovered files (full content, first N lines, summary only?)

Note: Path security is handled by the module config system—project_knowledge defaults to {project-root}/docs, automatically scoping all resolved paths within the project root.

src/bmm/workflows/4-implementation/correct-course/workflow.md-31-34 (1)

31-34: ⚠️ Potential issue | 🟡 Minor

Fix misleading "sharded" key for single-file input.

The document_project pattern uses sharded: "{project_knowledge}/index.md" to reference a single index file. This is inconsistent with other patterns where "sharded" means a directory glob (e.g., line 10: sharded: "{planning_artifacts}/*prd*/*.md"). A single file is not sharded; the key name is misleading.

Either use whole: "{project_knowledge}/index.md" or clarify in a comment why a single index file uses the "sharded" key.

src/bmm/workflows/4-implementation/correct-course/workflow.md-1-35 (1)

1-35: ⚠️ Potential issue | 🟡 Minor

Add version and metadata fields to support schema evolution and audit trails.

The YAML front matter lacks:

  1. version: No way to track workflow schema version. If the schema evolves (e.g., new required fields, deprecated syntax), parsers cannot gracefully handle version mismatches.
  2. author: No accountability for who created this workflow.
  3. created_date / last_modified: No audit trail for when this workflow was authored or last changed.

Without these fields, maintainers cannot reason about schema compatibility or track changes over time, especially in a large repository with many contributors.

Add to front matter:

 ---
 name: correct-course
+version: "1.0.0"
+author: "dickymoore"
+created_date: "2026-02-06"
+last_modified: "2026-02-06"
 description: "Navigate significant changes during sprint execution by analyzing impact, proposing solutions, and routing for implementation"
src/bmm/workflows/4-implementation/correct-course/workflow.md-59-68 (1)

59-68: ⚠️ Potential issue | 🟡 Minor

Resolve variable interpolation syntax inconsistency: {var} vs {{var}}.

The workflow uses single braces {variable} for built-in variables (lines 59-60: {installed_path}, {source_path}) but double braces {{workflow_path}} for the runtime-resolved path (lines 59, 60, 63, 67, 68). This inconsistency is confusing:

  • Are double braces a distinct scope or interpolation phase?
  • Do single braces resolve at parse-time and double braces at runtime?
  • Can users define their own {{custom_var}}?

Without documentation, maintainers cannot reliably author or extend workflows.

Either:

  1. Standardize on single braces and document that all variables resolve at runtime, OR
  2. Document the double-brace convention (e.g., "double braces indicate step-local variables resolved during execution") in the workflow schema or a comment.

Example documentation addition:

## Variable Interpolation
- `{variable}`: Resolved during Initialization from config.yaml or system context.
- `{{variable}}`: Step-local variable assigned during workflow execution.
src/bmm/workflows/4-implementation/correct-course/workflow.md-1-70 (1)

1-70: ⚠️ Potential issue | 🟡 Minor

Define an explicit outputs section to document workflow artifacts.

The workflow produces at least one output file ({planning_artifacts}/sprint-change-proposal-{date}.md from line 52) but has no structured outputs section in the front matter. This is inconsistent with the detailed input_file_patterns section (lines 6-35) and makes it harder for:

  • Downstream workflows to discover this workflow's outputs
  • Tooling to validate that outputs were created
  • Developers to understand what artifacts the workflow produces

Add an outputs section to the front matter:

   input_file_patterns:
     ...
+  outputs:
+    proposal:
+      description: "Change proposal with impact analysis and corrective actions"
+      path: "{planning_artifacts}/sprint-change-proposal-{date}.md"
+      required: true
 ---
src/bmm/workflows/4-implementation/correct-course/workflow.md-52-52 (1)

52-52: ⚠️ Potential issue | 🟡 Minor

Specify the date format for default_output_file to avoid filename ambiguity.

Line 52 interpolates {date} into the output filename sprint-change-proposal-{date}.md but does not specify the format (e.g., YYYY-MM-DD, YYYYMMDD, DD-MM-YYYY). Different systems or agent implementations could produce inconsistent filenames, breaking file references or causing overwrites.

Recommended fix
-  - `default_output_file` = `{planning_artifacts}/sprint-change-proposal-{date}.md`
+  - `default_output_file` = `{planning_artifacts}/sprint-change-proposal-{date:YYYY-MM-DD}.md`
+  - Note: `{date:YYYY-MM-DD}` formats the current date as `2026-02-08`.
src/bmm/workflows/4-implementation/correct-course/workflow.md-4-5 (1)

4-5: ⚠️ Potential issue | 🟡 Minor

Add explicit error handling in Initialization for main_config to match the pattern established in steps 1–2.

Line 4 declares main_config: '{project-root}/_bmad/bmm/config.yaml', and line 38 instructs to "Load config from {project-root}/_bmad/bmm/config.yaml." However, the Initialization section provides no explicit error-handling directive if this file is missing or unreadable. In contrast, step 1 (lines 58–61) explicitly validates instructions.md existence against both {installed_path} and {source_path}, then emits an error and HALTs if both fail. Step 2 (line 67) provides a fallback if step 1's resolution failed.

For consistency and robustness, add a fallback path resolution or explicit HALT instruction to the Initialization section:

  • Check {installed_path}/../config.yaml first (if different from source path)
  • Fall back to {source_path}/../config.yaml
  • Emit error and HALT if both are unreadable

Regarding web_bundle: false on line 5—this field appears in all workflow definitions in the codebase. While its purpose should be documented in the workflow schema or README, it is not undocumented per se, but rather a standard convention across the module.

tools/cli/installers/lib/ide/templates/combined/kiro-workflow-yaml.md-11-11 (1)

11-11: ⚠️ Potential issue | 🟡 Minor

Assumption that workflow.md is a "task": inconsistent with broader workflow architecture.

Line 11 describes workflow.md as "the CORE OS for EXECUTING the specific workflow-config," but line 12 calls it "the workflow.md task instructions." Is workflow.md a task, a runner, an OS, or a meta-instruction set? This terminology inconsistency suggests unclear responsibility boundaries. If workflow.md is truly a task (invokable via <invoke-task>), it should be documented as such. If it's a meta-framework, "task" is the wrong term.

Clarify the role:

-2. READ its entire contents - this is the CORE OS for EXECUTING the specific workflow-config #[[file:{{bmadFolderName}}/{{path}}]]
+2. READ its entire contents - workflow.md defines the execution framework for processing workflow configs like #[[file:{{bmadFolderName}}/{{path}}]]
tools/cli/installers/lib/ide/templates/combined/kiro-workflow-yaml.md-12-12 (1)

12-12: ⚠️ Potential issue | 🟡 Minor

Template variable documentation missing: add inline comments clarifying {{bmadFolderName}} and {{path}} format.

The template uses {{bmadFolderName}}/{{path}} without documenting what these variables contain. While the installer code correctly defines these ({{bmadFolderName}} = '_bmad', {{path}} = relative path to workflow with .md extension), future maintainers may benefit from explicit variable documentation in the template itself.

The suggestion to add a comment block is valid for clarity, but the actual path format is well-defined in the code and works correctly as-is—this is a minor documentation improvement rather than a functional issue.

src/bmm/workflows/4-implementation/retrospective/workflow.md-28-31 (1)

28-31: ⚠️ Potential issue | 🟡 Minor

Overly broad glob {planning_artifacts}/*.md will match epics, architecture, and PRD files.

The document_project input pattern at line 30 ({planning_artifacts}/*.md) overlaps with the globs for epics, architecture, and prd defined above. With INDEX_GUIDED load strategy this might be filtered downstream, but if not, the agent will re-process the same documents under multiple categories, wasting context and potentially causing conflicting analysis.

Consider narrowing the pattern or adding explicit exclusions for files already matched by the other input groups.

src/bmm/workflows/4-implementation/dev-story/workflow.md-33-34 (1)

33-34: ⚠️ Potential issue | 🟡 Minor

project_context glob may match multiple files with no disambiguation rule.

**/project-context.md could match files at multiple directory levels. The workflow doesn't specify what happens if zero or multiple matches are found — does the agent load all of them, pick the nearest, or HALT? Given the rigorous HALT protocol defined above, this deserves a resolution rule.

src/bmm/workflows/4-implementation/dev-story/workflow.md-4-5 (1)

4-5: ⚠️ Potential issue | 🟡 Minor

Frontmatter variable chaining is inconsistent with peer workflows and likely unresolvable.

Line 4 sets projectRoot: '{project-root}' and line 5 references it as main_config: '{projectRoot}/...'. Frontmatter is static YAML metadata — it cannot perform variable interpolation, so main_config will contain the literal string {projectRoot}/_bmad/bmm/config.yaml rather than a resolved path.

Compare with the retrospective/workflow.md in this PR, which uses main_config: '{project-root}/_bmad/bmm/config.yaml' directly — no intermediate variable. The Initialization section (line 24) correctly resolves the path at runtime, so this frontmatter value is decorative at best and misleading at worst.

Proposed fix — align with peer workflows
 ---
 name: dev-story
 description: "Execute a story by implementing tasks/subtasks, writing tests, validating, and updating the story file per acceptance criteria"
-projectRoot: '{project-root}'
-main_config: '{projectRoot}/_bmad/bmm/config.yaml'
+main_config: '{project-root}/_bmad/bmm/config.yaml'
 web_bundle: false
 ---
src/bmm/workflows/4-implementation/create-story/workflow.md-160-160 (1)

160-160: ⚠️ Potential issue | 🟡 Minor

Profanity in workflow instructions.

Line 160 contains "developer fuckups" — this surfaces in tooling output and is visible to users of the workflow. Regardless of intended tone, it's unprofessional in a shared codebase. Consider replacing with something like "developer mistakes" or "implementation errors."

tools/cli/installers/lib/modules/manager.js-807-835 (1)

807-835: ⚠️ Potential issue | 🟡 Minor

stripWebBundleFromFrontmatter introduces mixed line endings on CRLF files.

Line 808 correctly matches CRLF with \r?\n, but line 830 replaces with a hardcoded LF template:

return content.replace(frontmatterMatch[0], `---\n${serialized}\n---`);

If the original file uses CRLF, frontmatterMatch[0] spans CRLF content but the replacement uses LF, producing mixed line endings in the output. Since this is writing to the user's filesystem, it could cause issues with Git (showing unnecessary diffs) or tools that are strict about line endings.

Proposed fix — detect and preserve original line ending style
+    const eol = frontmatterMatch[0].includes('\r\n') ? '\r\n' : '\n';
+
     delete parsed.web_bundle;
     const serialized = yaml
       .stringify(parsed, {
         indent: 2,
         lineWidth: 0,
         sortMapEntries: false,
       })
       .trimEnd();

-    return content.replace(frontmatterMatch[0], `---\n${serialized}\n---`);
+    return content.replace(frontmatterMatch[0], `---${eol}${serialized.replaceAll('\n', eol)}${eol}---`);
src/core/workflows/advanced-elicitation/workflow.md-85-89 (1)

85-89: ⚠️ Potential issue | 🟡 Minor

Hardcoded create-doc.md caller reference limits reusability.

Lines 87 and 89 both reference returning content "back to create-doc.md", but this workflow is invoked from multiple callers (e.g., step-04-decisions.md in the architecture workflow, PRD steps, UX-design steps). An agent following these instructions literally would try to signal a file that isn't the actual caller.

Consider using a generic reference like "the calling workflow" or a variable like {{calling_workflow}} instead.

src/bmm/workflows/4-implementation/create-story/workflow.md-299-306 (1)

299-306: ⚠️ Potential issue | 🟡 Minor

Missing error handling when story status is not "backlog" during sprint status update.

Line 303 instructs the agent to "Verify current status is 'backlog' (expected previous state)" but provides no <check> block or error handling for the case where the status is something else (e.g., already ready-for-dev, in-progress, or done). Compare this with step 1's epic status handling (lines 138-151), which has explicit error paths for unexpected states. Without a guard here, the agent may silently overwrite an unexpected status.

Proposed fix
       <action>Verify current status is "backlog" (expected previous state)</action>
+      <check if="current status is NOT backlog">
+        <output>⚠️ WARNING: Story {{story_key}} status is '{{current_status}}', expected 'backlog'. Proceeding with update.</output>
+      </check>
       <action>Update development_status[{{story_key}}] = "ready-for-dev"</action>
src/core/workflows/advanced-elicitation/workflow.md-80-84 (1)

80-84: ⚠️ Potential issue | 🟡 Minor

Incorrect filename reference: advanced-elicitation-methods.csv vs methods.csv.

Line 81 instructs the agent to "Select 5 random methods from advanced-elicitation-methods.csv", but the variable methods defined in the Initialization section (line 11) resolves to methods.csv:

methods ({project-root}/_bmad/core/workflows/advanced-elicitation/methods.csv)

This mismatch means the agent could look for the wrong file or get confused about which data source to use.

Proposed fix
       <case n="r">
-        <i>Select 5 random methods from advanced-elicitation-methods.csv, present new list with same prompt format</i>
+        <i>Select 5 random methods from {{methods}}, present new list with same prompt format</i>
src/core/workflows/advanced-elicitation/workflow.md-1-5 (1)

1-5: ⚠️ Potential issue | 🟡 Minor

Inconsistent frontmatter schema across core vs. BMM workflows — pattern or oversight?

This isn't isolated to advanced-elicitation. ALL three core workflows (advanced-elicitation, brainstorming, party-mode) omit main_config from frontmatter and instead load config inline:

  • advanced-elicitation (line 8): {project-root}/_bmad/core/config.yaml
  • brainstorming (line 37): {project-root}/_bmad/core/config.yaml
  • party-mode (line 30): {project-root}/_bmad/core/config.yaml

Meanwhile, BMM workflows like create-story declare main_config in frontmatter. Either:

  1. Document this intentional architectural split (core workflows handle config differently for a reason), or
  2. Standardize the pattern across all workflows — if tooling or orchestration assumes main_config is always present, these will break silently.
src/bmm/workflows/qa/automate/workflow.md-27-33 (1)

27-33: ⚠️ Potential issue | 🟡 Minor

No guard against missing instructions.md or checklist.md at the installed path.

Steps 1 and 2 both reference files under {installed_path}/ with no existence check. If the installer fails to copy these files or the path is misconfigured, the agent hits a dead end with no diagnostic. Consider adding a preamble check (similar to handler-workflow.txt's dual-path fallback pattern) or at minimum documenting expected behavior when the files are absent.

src/utility/agent-components/handler-workflow.txt-14-18 (1)

14-18: ⚠️ Potential issue | 🟡 Minor

No validation of the workflow definition path passed as workflow-config.

Steps 5-7 load the resolved loader and pass the workflow definition path to it. But there's no check that the workflow definition file (the path from the menu item) actually exists before passing it along. If the menu references a deleted or mistyped workflow path, the agent silently proceeds into the loader with a broken config. Add a pre-check:

5b. Verify the workflow definition path from the menu item exists and is readable before passing it as 'workflow-config'.

test/test-installation-components.js-202-215 (1)

202-215: ⚠️ Potential issue | 🟡 Minor

Test 3 no longer tests actual path resolution — it tests String.replace.

The original test presumably exercised the YamlXmlBuilder's path resolution logic. Now it just does manual String.replace('{project-root}', ...) and asserts the replacement worked. The assertion on line 207 checks that builder exists and has deepMerge — which is unrelated to path resolution. This test suite is named "Path Variable Resolution" but doesn't exercise any real resolution code.

src/bmm/workflows/document-project/instructions.md-195-199 (1)

195-199: ⚠️ Potential issue | 🟡 Minor

scan_level is printed but never set for full_rescan/initial_scan.
You only set it for deep-dive. The final output will be blank/undefined in the most common paths.

🔧 Proposed fix
   <check if="user selects 1">
     <action>Set workflow_mode = "full_rescan"</action>
+    <action>Set scan_level = "standard"</action>
...
 <check if="index.md does not exist">
   <action>Set workflow_mode = "initial_scan"</action>
+  <action>Set scan_level = "standard"</action>

Also applies to: 226-229, 266-267

src/bmm/workflows/document-project/instructions.md-271-276 (1)

271-276: ⚠️ Potential issue | 🟡 Minor

Next-steps output assumes next_workflow / next_agent always exist.
Those fields are optional in status and can be empty. You’ll print incomplete guidance.

🔧 Proposed fix
 <check if="status_file_found == true AND status_update_success == true">
-  <output>**Status Updated:** Progress tracking updated.
+  <output>**Status Updated:** Progress tracking updated.
 
 **Next Steps:**
-- **Next required:** {{next_workflow}} ({{next_agent}} agent)
+- **Next required:** {{next_workflow}} ({{next_agent}} agent)</output>
+  <check if="next_workflow == '' OR next_agent == ''">
+    <output>Next workflow not specified in status. Run `bmad-help` for guidance.</output>
+  </check>
 - Run `bmad-help` if you need recommended next workflows.</output>
 </check>

@dickymoore
Copy link
Contributor Author

I hope this is helpful. I tried to progress this work as much as I could. There are lots of changes over many commits in response to coderabbitai and local adversarial reviews.

What I fixed

  • Restored empty-target short-circuit handling in tools/cli/installers/lib/ide/_config-driven.js (artifact_types: [] no longer creates empty output directories).
  • Restored split-template extension override behavior in tools/cli/installers/lib/ide/_config-driven.js (no forced .md; extension normalization added).
  • Restored defensive workflow path normalization in tools/cli/installers/lib/ide/shared/workflow-command-generator.js (separator normalization + /src/...fallback mapping before _bmad/ extraction).
  • Removed stale XML doc reference and tightened user-facing wording in migrated workflow/docs content.

Tests/validation

  • npm test passes.
  • Added regression guards in test/test-installation-components.js:
    • empty artifact target short-circuit
    • split-template extension override
    • workflow path normalization

PR size

  • PR is still large (129 files, +3327/-2176). If necessary, I could try breaking this up into multiple PRs, and would love to help in other ways if there's extra guidance for you to offer @bmadcode.

Thanks, Dicky

@dickymoore dickymoore marked this pull request as ready for review February 8, 2026 20:25
@github-actions
Copy link
Contributor

github-actions bot commented Feb 8, 2026

@coderabbitai review

@augmentcode
Copy link

augmentcode bot commented Feb 8, 2026

This pull request is too large for Augment to review. The PR exceeds the maximum size limit of 100000 tokens (approximately 400000 characters) for automated code review. Please consider breaking this PR into smaller, more focused changes.

@coderabbitai
Copy link

coderabbitai bot commented Feb 8, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
src/bmm/workflows/document-project/instructions.md (4)

34-36: ⚠️ Potential issue | 🟡 Minor

Avoid outputting empty {{suggestion}}.

When status_exists == false, suggestion is still defaulted to empty, so the first output can be blank. Guard it or remove it to prevent confusing empty output.

Suggested fix
-  <output>{{suggestion}}</output>
+  <check if="suggestion != ''">
+    <output>{{suggestion}}</output>
+  </check>

117-123: ⚠️ Potential issue | 🟠 Major

Resume path assumes cached project types always exist.

If cached_project_types is empty/missing, you skip loading project-types/architecture registries, but then try to load doc requirements per cached ID — which will be empty and break downstream steps. Add a fallback to full CSV loading when cached IDs are absent.

Suggested fix
     <action>Load cached project_type_id(s) from state file</action>
+    <check if="cached_project_types == ''">
+      <output>No cached project types found. Falling back to full CSV load.</output>
+      <action>Load project-types.csv and architecture_registry.csv</action>
+    </check>

154-159: ⚠️ Potential issue | 🟡 Minor

“Start fresh” doesn’t reset state-derived fields.

After moving the old state file, you only set resume_mode = false. Any previously loaded fields (mode, scan_level, cached_project_types, etc.) can leak into Step 4 outputs. Reset those to defaults when starting fresh.

Suggested fix
   <action>Move old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json</action>
   <action>Set resume_mode = false</action>
+  <action>Reset workflow_mode, scan_level, cached_project_types, current_step to defaults</action>
   <action>Continue to Step 3</action>

199-203: ⚠️ Potential issue | 🟡 Minor

scan_level is never set for full rescan.

Step 4 outputs scan_level, but in the full rescan branch it remains empty/undefined. Set an explicit scan_level here.

Suggested fix
   <action>Set workflow_mode = "full_rescan"</action>
+  <action>Set scan_level = "standard"</action>
   <action>Display: "Starting full project rescan..."</action>
tools/cli/installers/lib/ide/shared/workflow-command-generator.js (2)

134-145: ⚠️ Potential issue | 🟠 Major

Path transformation only handles bmm and core modules — other modules (bmb, tea, cis, gds) will retain raw source paths.

The path extraction logic on lines 134–145 only matches /src/bmm/ and /src/core/. According to docs (line 123 of commands.md), the system supports modules like bmb, tea, cis, and gds. Workflows from those modules would pass through with untransformed absolute paths, producing broken references in the generated command files.

A generic extraction would be more robust:

Proposed fix
-    if (workflowPath.includes('/src/bmm/')) {
-      // bmm is directly under src/
-      const match = workflowPath.match(/\/src\/bmm\/(.+)/);
-      if (match) {
-        workflowPath = `${this.bmadFolderName}/bmm/${match[1]}`;
-      }
-    } else if (workflowPath.includes('/src/core/')) {
-      const match = workflowPath.match(/\/src\/core\/(.+)/);
-      if (match) {
-        workflowPath = `${this.bmadFolderName}/core/${match[1]}`;
-      }
+    // Generic extraction: /src/<module>/... → <bmadFolderName>/<module>/...
+    const srcMatch = workflowPath.match(/\/src\/([^/]+)\/(.+)/);
+    if (srcMatch) {
+      workflowPath = `${this.bmadFolderName}/${srcMatch[1]}/${srcMatch[2]}`;
     }

The same pattern exists in transformWorkflowPath (lines 235–245) and collectWorkflowArtifacts (lines 80–85) and should be updated consistently.


74-85: ⚠️ Potential issue | 🟡 Minor

_bmad/ split-and-rejoin silently corrupts paths if _bmad/ appears more than once.

parts.slice(1).join('/') uses / as the joiner instead of the original _bmad/ separator. If the path contains multiple _bmad/ segments (e.g., nested install), segments are joined with a bare /, silently mangling the path. This is an edge case but the fix is trivial — take only the last segment:

Proposed fix
       if (parts.length > 1) {
-        workflowRelPath = parts.slice(1).join('/');
+        workflowRelPath = parts[parts.length - 1];
       }
🤖 Fix all issues with AI agents
In `@docs/tutorials/getting-started.md`:
- Around line 81-83: Update the Phase 1 workflow list so each workflow name is
paired with its full invocation command (e.g., show the pattern like
**brainstorming** (bmad-bmm-brainstorming) — Guided ideation); specifically add
full command forms for `brainstorming`, `research`, and `create-product-brief`
(or at minimum show one full example and clarify the naming pattern
`bmad-bmm-<workflow>`), ensuring the displayed syntax matches how users actually
invoke those workflows.
- Around line 165-175: Update the Quick Reference table so the bare workflow
names (e.g., "help", "prd", "create-architecture", "create-epics-and-stories",
"check-implementation-readiness", "sprint-planning", "create-story",
"dev-story", "code-review") are mapped to their actual slash command names from
commands.md (e.g., "bmad-help", "bmad-bmm-create-prd",
"bmad-bmm-create-architecture", etc.): either add a third column showing the
real slash command for each workflow or add a clear callout above the table
stating "Prefix with bmad- (or bmad-bmm- for module workflows) when using slash
commands", and ensure the examples for "help" include the existing parenthetical
"(bmad-help on most platforms)" for consistency.

In `@src/bmm/workflows/4-implementation/create-story/workflow.md`:
- Line 62: The GOTO targets "<action>GOTO step 2a</action>" do not match any
defined step; update either the jump targets or the step label so they match:
locate the three occurrences of the GOTO action (the lines containing
"<action>GOTO step 2a</action>") and either change them to "<action>GOTO step
2</action>" or rename the step declaration "<step n=\"2\" ...>" to "<step
n=\"2a\" ...>" so the GOTO references resolve correctly; ensure all three GOTOs
and the single step declaration use the identical label ("2" or "2a") so the
workflow is unambiguous.
- Around line 176-180: Define and set previous_story_num before using it in the
file-loading action: inside the existing conditional that checks "story_num >
1", add an explicit assignment computing previous_story_num = story_num - 1
(ensuring it's an integer) and then use {{previous_story_num}} in the Load
previous story file path; also ensure the branch skips the load when story_num
<= 1 to avoid undefined references.

In `@src/bmm/workflows/document-project/instructions.md`:
- Around line 235-239: When handling the branch where index.md does not exist
(the initial_scan path), set scan_level (e.g., scan_level = "initial") before
delegating to the full-scan workflow and before checking/setting
subworkflow_success; specifically add scan_level = "initial" alongside the
existing assignments of workflow_mode and before the action that reads
{installed_path}/workflows/full-scan-instructions.md so downstream logic that
expects scan_level won't be undefined.
- Around line 23-32: The current load of
`{output_folder}/bmm-workflow-status.yaml` silently falls back to standalone
mode on missing/unreadable/malformed files; update the load logic that sets
status_exists, status_file_found, standalone_mode, and status_file_path to catch
file-read and parse exceptions and emit a clear warning containing the failure
reason (e.g., file not found, permission error, YAML parse error) before
continuing; ensure the warning references the attempted path
(`{output_folder}/bmm-workflow-status.yaml`) and include any parser error
message so downstream uses of field_type, warning, suggestion, next_workflow,
and next_agent are traceable.
- Around line 281-287: The template block that renders the "Next Steps" uses
{{next_workflow}} and {{next_agent}} directly and can display empty placeholders
if those fields are missing; update the conditional rendering inside the check
(where status_file_found == true AND status_update_success == true) to fall back
to safe text like "unknown" or "not specified" (or hide the line) when
next_workflow or next_agent are empty/undefined, e.g., add conditional checks or
default values for next_workflow and next_agent in the same template so the
output never shows blank placeholders.
- Around line 84-90: The archive step assumes creating {output_folder}/.archive/
and moving project-scan-report-{{timestamp}}.json always succeed; add explicit
error handling around the "Create archive directory: {output_folder}/.archive/"
and "Archive old state file to:
{output_folder}/.archive/project-scan-report-{{timestamp}}.json" actions so
failures (mkdir or move) are detected, logged, and handled: if directory
creation or file move fails, log a clear error, do not discard the original
state file, set resume_mode = true (or abort the workflow) and surface the
failure to the user instead of continuing to Step 3. Ensure the implementation
checks return values/exceptions from the filesystem calls and uses the existing
variables resume_mode and {output_folder} to implement the fallback/abort
behavior.
- Around line 113-118: The workflow assigns workflow_mode directly from the
persisted state variable mode (when setting resume_mode=true and
subworkflow_success=false) without validation; update the loading logic that
sets workflow_mode so it validates mode against the canonical list of allowed
modes (e.g., ["create","update","review"] or the project's defined enum) and
only assigns it if it matches, otherwise set a safe default (e.g., "create") or
raise a clear error/flag to abort resumption; ensure the validation happens
right after "Load findings summaries from state file"/"Load cached
project_type_id(s) from state file" and refer to the workflow_mode and mode
variables to locate the change.
- Around line 79-83: The state-age computation currently trusts the state file's
last_updated value; add a parse-and-validate step when reading
project-scan-report.json: verify last_updated exists and is a valid ISO/epoch
timestamp, and if missing/invalid treat it as stale by setting age > 24 hours
(or a sentinel like null/Infinity) so the existing "Calculate age of state file"
/ "24‑hour logic" branch treats it as expired; update the extraction routine
that reads last_updated (the place implementing "Read state file and extract:
timestamps, ... last_updated") to perform this validation and fallback rather
than using the raw value.

In `@src/core/tasks/validate-workflow.md`:
- Around line 49-57: The Safe-edit protocol under "Edits (if applicable)" must
specify a deterministic backup location and cleanup behavior: update that
section to define a default backup strategy (e.g., configurable temp directory
with timestamped filenames and an optional adjacent .bak fallback) and require
recording the full backup path in the task output, and update "Finalize" (step
6) to state that backups/diff artifacts are deleted on successful apply (or
retained if user requests retention) with an explicit retention flag and a
documented rollback path; reference the "Create backup snapshot", "Record
backup/diff locations in task output", and the "Finalize" step so the markdown
clearly prescribes where backups go, how they are named, and when they are
cleaned up.
- Line 34: Update the validation sentence in validate-workflow.md that currently
lists acceptable extensions to explicitly include .md; locate the line
containing "Validate candidate existence and expected file type (`.yaml`,
`.yml`, `.json`, or checklist-defined extension)" and add `.md` to the
parenthetical list so it reads something like "`.yaml`, `.yml`, `.json`, `.md`,
or checklist-defined extension" to ensure Markdown workflows are recognized.

In `@tools/cli/installers/lib/ide/shared/workflow-command-generator.js`:
- Around line 213-222: The generated launcher instructions include an invalid
hardcoded fallback "{project-root}/src/core/tasks/workflow.md" for installed
projects; update the generator in workflow-command-generator.js (look for the
code using this.bmadFolderName, the "workflow-config" parameter and the block
that builds the two loader paths) to stop emitting the /src/... fallback for
distribution: either remove the fallback entirely for installed builds, or make
it conditional by checking whether the source fallback actually exists
(fs.accessSync or fs.existsSync) or by detecting dev vs installed mode (env flag
or presence of a src folder) and only include the fallback when present; also
update the warning/error messages so they report the resolved attempts (primary
and, if used, the valid fallback) and avoid halting on a non-existent /src path.
🧹 Nitpick comments (10)
src/bmm/workflows/document-project/instructions.md (1)

13-21: Initialize all later-used fields upfront to avoid undefined state.

Several fields are referenced later without defaults (e.g., status_file_path, field_type, workflow_mode, scan_level, subworkflow_success, status_update_success, cached_project_types). This risks empty outputs and wrong branching when prior state leaks in. Initialize them here.

Suggested fix
 <action>Initialize status defaults:
   - Set status_exists = false
   - Set status_file_found = false
   - Set standalone_mode = true
   - Set warning = ""
   - Set suggestion = ""
   - Set next_workflow = ""
   - Set next_agent = ""
+  - Set status_file_path = ""
+  - Set field_type = ""
+  - Set workflow_mode = ""
+  - Set scan_level = ""
+  - Set subworkflow_success = false
+  - Set status_update_success = false
+  - Set cached_project_types = ""
 </action>
tools/cli/installers/lib/ide/shared/workflow-command-generator.js (1)

121-123: Redundant template path calculation — this.templatePath already holds this exact value.

Line 123 reconstructs the template path by joining path.dirname(this.templatePath) with 'workflow-commander.md', which produces exactly this.templatePath (set on line 12). This is likely a leftover from when there were multiple templates selected conditionally.

Proposed fix
   async generateCommandContent(workflow, bmadDir) {
-    // Determine template based on workflow file type
-    const templatePath = path.join(path.dirname(this.templatePath), 'workflow-commander.md');
-
     // Load the appropriate template
-    const template = await fs.readFile(templatePath, 'utf8');
+    const template = await fs.readFile(this.templatePath, 'utf8');
docs/tutorials/getting-started.md (1)

68-68: Good bridging pattern — extend it beyond just help.

Line 68 shows the right approach: Run the help workflow (bmad-help on most platforms). This parenthetical mapping should be applied to at least the first occurrence of each workflow category (agent load, module workflow, core workflow) so users learn the naming convention early.

tools/cli/installers/lib/modules/manager.js (4)

815-817: Redundant require('yaml') shadows the module-level import.

yaml is already required at line 3. This inner const yaml = require('yaml') shadows it unnecessarily, adding confusion about which binding is in scope throughout the method.

Proposed fix
   try {
-      const yaml = require('yaml');
-      const parsed = yaml.parse(frontmatterMatch[1]);
+      const parsed = yaml.parse(frontmatterMatch[1]);

1169-1172: replace strips the workflow filename suffix — verify behaviour when the path has no matching suffix.

sourceWorkflowSubPath.replace(workflowSuffixPattern, '') silently returns the original string when the pattern doesn't match (e.g., if the path already ends at a directory or uses an unexpected filename). The subsequent fs.pathExists check on line 1175 will catch it, so this is safe, but be aware that an unexpected path shape will produce a confusing "Source workflow not found" warning rather than a clear "unexpected path format" message.


1189-1194: Workflow definition lookup in vendored directory assumes a flat listing.

fs.readdir(actualDestWorkflowPath) returns entries for the immediate directory only. If the workflow definition file is nested in a subdirectory (unlikely but possible given recursive copy on line 1187), find won't locate it. This appears safe given the current file layout, but worth noting if directory structures evolve.


1214-1217: replaceAll with a global regex is redundant but functional.

String.prototype.replaceAll requires the regex to have the g flag (which it does), but replace with a global regex already replaces all occurrences. Either works — just a minor readability note; replace would be the more conventional choice with a /g regex.

tools/cli/installers/lib/ide/_config-driven.js (1)

169-174: Misleading variable name finalTemplateType — it's only the fallback, not the resolved type.

finalTemplateType is always 'default-workflow' regardless of what workflowTemplateType resolved to. The name suggests it's the type that will ultimately be used, but it's only the fallback parameter passed to loadTemplateWithMetadata. Consider renaming to fallbackTemplateType for clarity.

Proposed fix
-        const finalTemplateType = 'default-workflow';
-        const { template, extension } = await this.loadTemplateWithMetadata(workflowTemplateType, 'workflow', config, finalTemplateType);
+        const fallbackType = 'default-workflow';
+        const { template, extension } = await this.loadTemplateWithMetadata(workflowTemplateType, 'workflow', config, fallbackType);
test/test-installation-components.js (2)

434-463: Temp directories leak when tests throw before cleanup.

Tests 11, 12, 13, 18 (and others) create temp directories with fs.mkdtemp and clean up with fs.remove(tmpRoot) at the end. If any assertion or intermediate operation throws, the catch block calls assert(false, ...) but never removes tmpRoot. Over repeated test runs or CI, this accumulates orphaned dirs in the system temp folder.

Consider a finally block or a cleanup helper:

Example pattern
+  const tmpRoots = [];
+  const trackTmp = async (prefix) => {
+    const dir = await fs.mkdtemp(path.join(os.tmpdir(), prefix));
+    tmpRoots.push(dir);
+    return dir;
+  };
   // ... at the end of runTests(), before summary:
+  for (const dir of tmpRoots) {
+    await fs.remove(dir).catch(() => {});
+  }

Also applies to: 472-498, 507-532, 719-744


282-310: Test 9 appears before Tests 6, 7, 8 in the source — numbering is out of order.

Tests are numbered 1, 2, 3, 4, 5, 9, 6, 7, 8, 10, 11, ... This likely happened during iterative development. It won't affect execution but makes the output confusing to read and cross-reference.

@dickymoore
Copy link
Contributor Author

Regarding the issue of this being a very large PR, here is how it could be split into multiple PRs which gives reviewable chunks, each green and mergeable, without breaking runtime behaviour. If maintainers can give me guidance on whether that would be helpful or not, I'll act accordingly.

Here's the plan:

  1. Create fresh branches from upstream/main.
  2. Pull in changes by file scope (git restore --source phase1-md-workflows-clean --), not by old commit history.
  3. Commit each scope as its own PR.
  4. Run full checks per PR (npm test, npm run validate:refs).

PRs:

1. PR A: CLI/runtime migration foundation

  • tools/cli/installers/**
  • src/utility/agent-components/**
  • src/core/tasks/workflow.md, src/core/tasks/validate-workflow.md
  • test/test-installation-components.js, test/test-file-refs-csv.js

2. PR B: Core workflow/task format clean-up

  • src/core/workflows/**
  • remove legacy XML runner/file references
  • keep only intentional YAML config files (e.g. document-project subworkflow configs)

3. PR C: BMM Phase 1–3 step-file migration

  • src/bmm/workflows/1-analysis/**
  • src/bmm/workflows/2-plan-workflows/**
  • src/bmm/workflows/3-solutioning/**
  • src/bmm/module-help.csv updates tied to those workflows

4. PR D: BMM Phase 4 implementation workflows

  • src/bmm/workflows/4-implementation/**
  • includes code-review/dev-story/create-story/correct-course contract fixes

5. PR E: Docs and onboarding alignment

  • docs/**, README.md, command/tutorial docs
  • only after behaviour/paths are already settled

…-clean

# Conflicts:
#	tools/cli/installers/lib/core/manifest-generator.js
…-clean

# Conflicts:
#	tools/cli/installers/lib/modules/manager.js
…-clean

# Conflicts:
#	src/bmm/workflows/4-implementation/correct-course/workflow.yaml
#	src/bmm/workflows/4-implementation/retrospective/workflow.yaml
#	src/bmm/workflows/4-implementation/sprint-status/workflow.yaml
@dickymoore dickymoore requested a review from bmadcode February 10, 2026 17:44
dickymoore and others added 2 commits February 11, 2026 09:57
…-clean

# Conflicts:
#	src/bmm/workflows/4-implementation/code-review/workflow.yaml
#	src/bmm/workflows/4-implementation/correct-course/workflow.yaml
#	src/bmm/workflows/4-implementation/create-story/checklist.md
#	src/bmm/workflows/4-implementation/create-story/workflow.yaml
#	src/bmm/workflows/4-implementation/dev-story/instructions.xml
#	src/bmm/workflows/4-implementation/dev-story/workflow.yaml
#	src/bmm/workflows/4-implementation/retrospective/workflow.yaml
#	src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml
#	src/bmm/workflows/4-implementation/sprint-status/workflow.yaml
#	src/bmm/workflows/document-project/instructions.md
#	src/bmm/workflows/document-project/workflow.yaml
#	src/bmm/workflows/document-project/workflows/deep-dive.yaml
#	src/bmm/workflows/document-project/workflows/full-scan.yaml
#	src/bmm/workflows/qa/automate/workflow.yaml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants