-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Remove legacy workflow.xml/yaml references and complete workflow.md migration #1567
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Remove legacy workflow.xml/yaml references and complete workflow.md migration #1567
Conversation
📝 WalkthroughWalkthroughMigrates 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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this 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 | 🟠 MajorRegex doesn't match hardcoded
bmaddespite the comment claiming it does.Lines 1096–1097 state the regex handles both
_bmadand hardcodedbmad, 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 | 🟡 MinorStale XML reference:
advanced-elicitation.xmlnot 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.mdformat for consistency.Note: This stale reference won't be caught by the new guard tests (Test 6) since they check for
advanced-elicitation/workflow.xmlspecifically, notadvanced-elicitation.xml.Proposed fix
-- Execute advanced-elicitation.xml with current category rules +- Execute advanced-elicitation workflow with current category rulestools/cli/installers/lib/ide/_base-ide.js (1)
290-299:⚠️ Potential issue | 🔴 CriticalBug:
findWorkflowYamlFilesno longer exists — core workflow discovery will crash.Line 292 still calls
this.findWorkflowYamlFiles(coreWorkflowsPath), but the method was renamed tofindWorkflowFileson Line 331. This will throwTypeError: this.findWorkflowYamlFiles is not a functionat 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 | 🔴 CriticalBug:
transformWorkflowPathnever handles/src/core/paths and returnsundefinedfor them.The
else ifon line 228 is nested inside theif (workflowPath.includes('/src/bmm/'))block, making it unreachable for core-only paths. When a path contains/src/core/but not/src/bmm/, the outerifisfalse, the function falls through with noreturn, and returnsundefined. Thereturn transformedon line 235 is also only reachable inside the outerif.Additionally, line 228's
else ifis dead code: ifincludes('/src/bmm/')is true, the regex on line 225 will always match, so theelsebranch 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 | 🟠 MajorWorkflow template name is doubled:
${templateType}-workflow-workflow.md.Line 163 builds
workflowTemplateType = \${templateType}-workflow`and then line 167 passes it toloadTemplate(workflowTemplateType, 'workflow', ...). InsideloadTemplate(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.mdfallback. This means per-IDE workflow template customization is broken.Either pass just
templateTypetoloadTemplate, or don't append-workflowon 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:processAgentFilesis 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--productionflag with--omit=dev.The
--productionflag 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 duplicatedwalkfunction 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-opreplaceAll.Two issues in
generateCommandContent:
Line 117:
templatePathis re-derived fromthis.templatePathbut resolves to the exact same file (workflow-commander.md). This is dead code left from when multiple templates existed.Lines 147–148: The second
.replaceAll('_bmad', '_bmad')is a no-op — it replaces_bmadwith itself. If the intent was to prevent the first replacement from touching certain occurrences, it doesn't achieve that becausereplaceAllon 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:cleanForCSVis redefined on every loop iteration.The helper is a pure function with no closure over per-iteration state. Defining it once outside the
forloop (or as a module-level/static helper) avoids unnecessary re-creation.
src/bmm/workflows/2-plan-workflows/create-prd/steps-e/step-e-01-discovery.md
Outdated
Show resolved
Hide resolved
src/bmm/workflows/excalidraw-diagrams/create-dataflow/instructions.md
Outdated
Show resolved
Hide resolved
bmadcode
left a comment
There was a problem hiding this 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.
|
@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. |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
Process update (clean):
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. |
There was a problem hiding this 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 | 🟠 MajorPlaceholder 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 | 🟠 MajorMismatched 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 | 🟠 MajorYou 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 | 🟠 MajorNo 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 | 🟡 MinorWeb 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 | 🟠 MajorMenu 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 | 🟠 MajorSaving 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 | 🟡 MinorShell command in a workflow step assumes Unix environment and relies on
lswith 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 usels -twith glob patterns and pipe toheadpresumes 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. The2>/dev/nullsuppression 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 | 🟡 MinorSteps 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 | 🟠 MajorNo 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 | 🟠 MajorArchitecture 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
optionsis not defined inupdate()— will throwReferenceErrorat runtime.Line 607 references
options.installer, but the method signature on line 584 isasync update(moduleName, bmadDir, force = false)— there is nooptionsparameter. This will crash whenever a non-force update triggers theelsebranch.Proposed fix
- async update(moduleName, bmadDir, force = false) { + async update(moduleName, bmadDir, force = false, options = {}) {
999-1017:⚠️ Potential issue | 🟠 Major
processAgentFilesis 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 | 🟡 MinorVendoring regex only matches
bmador_bmad— won't work with custom folder names.The regex
(?:_?bmad)on lines 1097 and 1109 matches exactlybmador_bmad. If the user configured a differentbmadFolderName(e.g.,.bmad-custom), these patterns silently fail to match, and vendored workflows are skipped with a warning. Consider building the regex dynamically fromthis.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 | 🟠 MajorAdd
validationReportPathto 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 | 🟡 MinorStep total count mismatch with sibling step file.
Line 19 states "Step 6 of 11", but
step-05-domain.md(in the samesteps-cdirectory) 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 | 🟠 MajorSecurity 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:
- Whitelist allowed Markdown features: Restrict to headers, lists, code blocks, emphasis — no raw HTML or JavaScript
- Sanitize frontmatter: Validate YAML frontmatter doesn't contain executable directives (e.g.,
!!python/objecttags)- Path traversal protection: Ensure path interpolation can't escape repository root (
{project-root}/../../../etc/passwd)- 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 | 🟠 MajorMenu 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 | 🟠 MajorMissing guard when workflow-status is unavailable.
You invoke
{project-root}/_bmad/bmm/workflows/workflow-statuswithout 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., setstandalone_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 | 🟠 MajorAmbiguous condition uses implicit boolean.
status_exists == falseis referenced without defining howstatus_existsis 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 | 🟠 MajorGreenfield 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 | 🟡 MinorWarning 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. Persistwarning/suggestionto 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. Defineresume_mode = falsewhen 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 | 🟠 MajorConflicting 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 | 🟠 MajorNo 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 | 🟠 MajorStatus output block has mismatched templating scope.
You open
{{#ifstatus_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 | 🟠 MajorMenu 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 | 🟠 MajorPotential 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 | 🟠 MajorDuplicate
epicsTemplatekey in frontmatter.
epicsTemplateis 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 | 🟠 MajorDocument 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 | 🟡 MinorInstruction 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 | 🟡 MinorMenu 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 | 🟡 MinorTest 3 is a permanent placeholder that always passes — this silently inflates the pass count.
Line 192 asserts
trueunconditionally. 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.
src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md
Outdated
Show resolved
Hide resolved
src/bmm/workflows/2-plan-workflows/create-ux-design/steps/step-04-emotional-response.md
Show resolved
Hide resolved
src/bmm/workflows/4-implementation/code-review/steps/step-03-execute-review.md
Show resolved
Hide resolved
src/bmm/workflows/4-implementation/code-review/steps/step-03-execute-review.md
Show resolved
Hide resolved
tools/cli/installers/lib/ide/shared/workflow-command-generator.js
Outdated
Show resolved
Hide resolved
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.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this 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
readdirwithoutwithFileTypeswill blow up on subdirectories.
getAgentsFromDir(line 87) correctly uses{ withFileTypes: true }and checksentry.isDirectory(). Here,getTasksFromDirdoes a barereaddir— if a subdirectory happens to end with.mdor.xml(or even if it doesn't, it's fragile),fs.readFileon a directory path will throw an unhandled error. At minimum, stat the entry or usewithFileTypes.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 | 🟠 MajorSpecify 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 ofbmad-help.csvis 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 | 🟠 MajorDefine "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 | 🟠 MajorAdd validation and error handling for config file scanning.
Step 2 instructs scanning each folder under
_bmad/forconfig.yamland extracting specific fields, but provides no error handling or validation:
- What if a
config.yamlis missing or malformed?- What if
communication_languageorproject_knowledgefields are absent?- What if
output-locationvariables 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 | 🔴 CriticalDocument 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 possiblyagent-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 | 🟠 MajorAdd 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
outputspattern, 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
outputspatterns, 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 | 🟠 MajorMissing 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.mddoesn'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
relativePathloses directory nesting in recursive calls — all nested workflows get a flat filename.
findWorkflowFiles(dir)recurses by callingthis.findWorkflowFiles(fullPath)(line 345), wherefullPathis 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 atcore/workflows/advanced-elicitation/workflow.mdwould haverelativePath: "workflow.md"instead of"advanced-elicitation/workflow.md".Compare with
manifest-generator.js(line 146), which correctly threads arelativePathparameter 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.mdfiles 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 | 🟠 MajorVendoring 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.bmadFolderNamecan be any user-configured value (it's settable viasetBmadFolderName). If a project uses a custom folder name (e.g.,.bmadormy-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.bmadFolderNameor 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 | 🟡 MinorBroad
_bmadstring replacement risks corrupting template content.Line 387 does
replaceAll('_bmad', this.bmadFolderName). This replaces every occurrence of the literal_bmadin the rendered template — including inside prose, comments, or path documentation that mentions_bmaddescriptively. Line 390 already handles the proper{{bmadFolderName}}placeholder. Ifthis.bmadFolderNameis actually_bmad(which it is by default fromBMAD_FOLDER_NAME), it's a no-op, but if a user customizes the folder name, legitimate_bmadreferences 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 | 🟠 MajorResume 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_successis never initialized in non-resume flows.
You check it right after delegated workflows, but only the resume branch sets it tofalsefirst. 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 | 🟠 MajorNo 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 | 🟠 MajorNo 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 | 🟠 MajorDefine
agent-commandand specify default forcommunication_language.Line 74 references "the platform's command format for
agent-command," butagent-commandis never defined in this file, nor is it included in the documented CSV schema (which is also missing). It's unclear ifagent-commandis a CSV column, a computed value, or a typo foragent.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-commandin the CSV schema section and specify the default language behavior.src/core/tasks/help.md-48-77 (1)
48-77: 🛠️ Refactor suggestion | 🟠 MajorProvide 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 | 🟠 MajorDefine
standalone: trueand 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
standalonefield is not documented anywhere in this file. Specify whatstandalone: truemeans, how it differs fromstandalone: 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 | 🟠 MajorEliminate 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.mdexists" 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 | 🟠 MajorAvoid platform-specific syntax in examples and generalize instructions.
The example in lines 66-68 uses
/tech-writersyntax, 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 | 🟠 MajorValidate 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 | 🟠 MajorSpecify 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.yamlis 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 | 🟠 MajorStep 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 | 🟠 MajorDeclare
checklist.mdininput_file_patternsand specify task error handling.Line 68 references
{{workflow_path}}/checklist.mdbutchecklist.mdis not declared in theinput_file_patternssection (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 ifvalidate-workflow.mdtask 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 | 🟠 MajorStrengthen path resolution logic and clarify precedence.
The path resolution in lines 58-62 has several ambiguities:
- "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.
- 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.
- No check for both paths existing: If both
{installed_path}/instructions.mdand{source_path}/instructions.mdexist, the code silently prefersinstalled_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 | 🟠 MajorUnderspecified 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 | 🟠 MajorForced 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 | 🟠 MajorFallback path
src/core/tasks/workflow.mdwon'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/, notsrc/. 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 | 🟠 MajorRedundant template path computation —
templatePathis identical tothis.templatePath.Line 117 computes
path.join(path.dirname(this.templatePath), 'workflow-commander.md'), which resolves to the exact same value asthis.templatePathset 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) definesstory_dir,epic_num,story_num, etc., butprevious_story_numis absent. The agent would need to derive this asstory_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 | 🟠 MajorAgent manifest CSV fields written without quote escaping — injection risk.
writeAgentManifest(line 763) interpolatesagent.name,agent.displayName,agent.title, andagent.icondirectly 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 usesescapeCsv()for every field. The same inconsistency applies towriteTaskManifest(line 781) andwriteToolManifest(line 799), wherenameanddisplayNameare 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
writeTaskManifestandwriteToolManifest.tools/cli/installers/lib/core/manifest-generator.js-386-404 (1)
386-404:⚠️ Potential issue | 🟠 MajorMD tasks without frontmatter are accepted with unsafe defaults, inconsistent with workflow handling elsewhere.
For
.mdtasks ingetTasksFromDir(), when the frontmatter regex doesn't match (line 391), the code falls through without acontinuestatement. The task is added with defaultstandalone = trueand an empty description. This differs fromfindWorkflowFiles()in the same file (line 356) and_base-ide.js(line 357), which bothcontinuepast MD files without frontmatter.This creates a vulnerability: stray
.mdfiles 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:
- Add
continueafter the frontmatter check fails to align with workflow handling, or- Document why tasks intentionally default to
standalone = trueand justify the differencesrc/utility/agent-components/handler-workflow.txt-4-6 (1)
4-6:⚠️ Potential issue | 🟠 MajorFallback 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 | 🟠 MajorValidation target file types omit
.md— the very format this PR canonicalizes.Line 34 lists
.yaml,.yml,.jsonas expected file types for validation candidates, but.mdis 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 | 🟠 MajorState-file existence checks use inconsistent paths.
You check{output_folder}/project-scan-report.jsonin the action, but the condition uses bareproject-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 | 🟠 MajorAge calculation assumes
last_updatedexists and is valid.
Iflast_updatedis 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 | 🟠 MajorDon’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 | 🟠 MajorNo 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 | 🟡 MinorFrontmatter parsing has a few fragility concerns.
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.Regex won't match a BOM-prefixed file: If any
.mdfile has a UTF-8 BOM (\uFEFF), the^---anchor fails. This is an edge case butfs.readFilewithutf8encoding does not strip BOM on all Node versions.No type guard on
yaml.parseresult: If frontmatter contains only a scalar (e.g.,---\ntrue\n---),yaml.parsereturns a non-object. Accessing.internalon a boolean won't throw but also won't match — defaults kick in, silently including the file. A quicktypeof frontmatter === 'object' && frontmatter !== nullguard would make intent explicit.src/core/tasks/help.md-46-51 (1)
46-51:⚠️ Potential issue | 🟡 MinorComplete 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 | 🟡 MinorClarify 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_knowledgedefaults 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 | 🟡 MinorFix misleading "sharded" key for single-file input.
The
document_projectpattern usessharded: "{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 | 🟡 MinorAdd version and metadata fields to support schema evolution and audit trails.
The YAML front matter lacks:
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.author: No accountability for who created this workflow.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 | 🟡 MinorResolve 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:
- Standardize on single braces and document that all variables resolve at runtime, OR
- 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 | 🟡 MinorDefine an explicit
outputssection to document workflow artifacts.The workflow produces at least one output file (
{planning_artifacts}/sprint-change-proposal-{date}.mdfrom line 52) but has no structuredoutputssection in the front matter. This is inconsistent with the detailedinput_file_patternssection (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
outputssection 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 | 🟡 MinorSpecify the date format for
default_output_fileto avoid filename ambiguity.Line 52 interpolates
{date}into the output filenamesprint-change-proposal-{date}.mdbut 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 | 🟡 MinorAdd explicit error handling in Initialization for
main_configto 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 validatesinstructions.mdexistence 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.yamlfirst (if different from source path)- Fall back to
{source_path}/../config.yaml- Emit error and HALT if both are unreadable
Regarding
web_bundle: falseon 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 | 🟡 MinorAssumption 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 | 🟡 MinorTemplate 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 | 🟡 MinorOverly broad glob
{planning_artifacts}/*.mdwill match epics, architecture, and PRD files.The
document_projectinput pattern at line 30 ({planning_artifacts}/*.md) overlaps with the globs forepics,architecture, andprddefined above. WithINDEX_GUIDEDload 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_contextglob may match multiple files with no disambiguation rule.
**/project-context.mdcould 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 | 🟡 MinorFrontmatter variable chaining is inconsistent with peer workflows and likely unresolvable.
Line 4 sets
projectRoot: '{project-root}'and line 5 references it asmain_config: '{projectRoot}/...'. Frontmatter is static YAML metadata — it cannot perform variable interpolation, somain_configwill contain the literal string{projectRoot}/_bmad/bmm/config.yamlrather than a resolved path.Compare with the
retrospective/workflow.mdin this PR, which usesmain_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 | 🟡 MinorProfanity 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
stripWebBundleFromFrontmatterintroduces 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 | 🟡 MinorHardcoded
create-doc.mdcaller 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.mdin 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 | 🟡 MinorMissing 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., alreadyready-for-dev,in-progress, ordone). 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 | 🟡 MinorIncorrect filename reference:
advanced-elicitation-methods.csvvsmethods.csv.Line 81 instructs the agent to "Select 5 random methods from advanced-elicitation-methods.csv", but the variable
methodsdefined in the Initialization section (line 11) resolves tomethods.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 | 🟡 MinorInconsistent 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) omitmain_configfrom frontmatter and instead load config inline:
advanced-elicitation(line 8):{project-root}/_bmad/core/config.yamlbrainstorming(line 37):{project-root}/_bmad/core/config.yamlparty-mode(line 30):{project-root}/_bmad/core/config.yamlMeanwhile, BMM workflows like
create-storydeclaremain_configin frontmatter. Either:
- Document this intentional architectural split (core workflows handle config differently for a reason), or
- Standardize the pattern across all workflows — if tooling or orchestration assumes
main_configis always present, these will break silently.src/bmm/workflows/qa/automate/workflow.md-27-33 (1)
27-33:⚠️ Potential issue | 🟡 MinorNo guard against missing
instructions.mdorchecklist.mdat 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 tohandler-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 | 🟡 MinorNo 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 | 🟡 MinorTest 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 thatbuilderexists and hasdeepMerge— 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_levelis 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 | 🟡 MinorNext-steps output assumes
next_workflow/next_agentalways 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>
tools/cli/installers/lib/ide/templates/combined/kiro-workflow-yaml.md
Outdated
Show resolved
Hide resolved
|
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
Tests/validation
PR size
Thanks, Dicky |
|
@coderabbitai review |
|
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. |
✅ Actions performedReview triggered.
|
There was a problem hiding this 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 | 🟡 MinorAvoid outputting empty
{{suggestion}}.When
status_exists == false,suggestionis 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 | 🟠 MajorResume path assumes cached project types always exist.
If
cached_project_typesis 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_levelis never set for full rescan.Step 4 outputs
scan_level, but in the full rescan branch it remains empty/undefined. Set an explicitscan_levelhere.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 | 🟠 MajorPath transformation only handles
bmmandcoremodules — 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 ofcommands.md), the system supports modules likebmb,tea,cis, andgds. 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) andcollectWorkflowArtifacts(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.templatePathalready holds this exact value.Line 123 reconstructs the template path by joining
path.dirname(this.templatePath)with'workflow-commander.md', which produces exactlythis.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 justhelp.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: Redundantrequire('yaml')shadows the module-level import.
yamlis already required at line 3. This innerconst 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:replacestrips 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 subsequentfs.pathExistscheck 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),findwon't locate it. This appears safe given the current file layout, but worth noting if directory structures evolve.
1214-1217:replaceAllwith a global regex is redundant but functional.
String.prototype.replaceAllrequires the regex to have thegflag (which it does), butreplacewith a global regex already replaces all occurrences. Either works — just a minor readability note;replacewould be the more conventional choice with a/gregex.tools/cli/installers/lib/ide/_config-driven.js (1)
169-174: Misleading variable namefinalTemplateType— it's only the fallback, not the resolved type.
finalTemplateTypeis always'default-workflow'regardless of whatworkflowTemplateTyperesolved to. The name suggests it's the type that will ultimately be used, but it's only the fallback parameter passed toloadTemplateWithMetadata. Consider renaming tofallbackTemplateTypefor 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.mkdtempand clean up withfs.remove(tmpRoot)at the end. If any assertion or intermediate operation throws, thecatchblock callsassert(false, ...)but never removestmpRoot. Over repeated test runs or CI, this accumulates orphaned dirs in the system temp folder.Consider a
finallyblock 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.
tools/cli/installers/lib/ide/shared/workflow-command-generator.js
Outdated
Show resolved
Hide resolved
|
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:
PRs:1. PR A: CLI/runtime migration foundation
2. PR B: Core workflow/task format clean-up
3. PR C: BMM Phase 1–3 step-file migration
4. PR D: BMM Phase 4 implementation workflows
5. PR E: Docs and onboarding alignment
|
…-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
…-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
What
Migrated workflows to the Markdown-based
workflow.mdformat 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
workflow.mdand removedworkflow.yaml/workflow.xmlartifacts.workflow.mdas the canonical workflow definition format.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
workflow.mdand eliminatedworkflow.yamlreferences (including the QA automate workflow).Scope/Overlap Check
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/**.Potential Conflicts
tools/cli/installers/lib/ide/**and workflow manifest generation intools/cli/installers/lib/core/**.upstream/mainbefore merge to pick up recent CLI/IDE template updates.Migration Note
workflow.mdis supported; legacyworkflow.xml/workflow.yamlfiles should be converted to Markdown-based workflows.Compatibility Notes
bmm-workflow-status.yaml/workflow-status) are preserved; status tracking behavior not changed.Commit Breakdown
Notes / Breaking Changes
workflow.xmlandworkflow.yamlartifacts are no longer supported; workflows should useworkflow.md.Note for maintainers:
Tracking
Refs #1585