Skip to content

feat(bmm): add monorepo/multi-project support via skills#2009

Closed
serrnovik wants to merge 2 commits intobmad-code-org:mainfrom
serrnovik:tools-based-current-project
Closed

feat(bmm): add monorepo/multi-project support via skills#2009
serrnovik wants to merge 2 commits intobmad-code-org:mainfrom
serrnovik:tools-based-current-project

Conversation

@serrnovik
Copy link
Copy Markdown

What

Implemented monorepo support for BMAD-METHOD, introducing a dynamic artifact pathing mechanism based on a local project context file (.current_project). This update allows workflows to automatically route their outputs to project-specific subdirectories within _bmad-output/.

This is tools based implementation of PR based on legacy workflow Unlike the previous approach, this implementation uses skills (bmad-project-list, bmad-project-new, bmad-project-switch) instead of a single /set-project workflow, aligning with the v6.1.0 tools-based architecture.

  • Add monorepo_context config section to module.yaml for path resolution
  • Add bmad-project-list, bmad-project-new, bmad-project-switch skills
  • Config-level hook: LLM reads config and applies context before path vars
  • Inline overrides via #project:NAME or #p:NAME in invocations
  • Installer: ensure 0-context workflow dir is installed
  • Add docs/how-to/monorepo-setup.md
  • 100% backward compatible when no .current_project file

Why

This change enables cleaner organization and branch switching in monorepo environments by centralizing methodology files while isolating project artifacts. It avoids methodology duplication and re-configuration overhead when working across multiple projects in a single shared repository.

How

  • Config-level hook: Added monorepo_context section to module.yaml. The LLM reads config and applies context resolution before using any path variables. Zero changes to existing workflow files.
  • Project management skills: Created bmad-project-list, bmad-project-new, and bmad-project-switch in workflows/0-context/ for listing, creating, and switching project contexts from the IDE.
  • Inline overrides: Support #project:NAME or #p:NAME in invocations for temporary targeting without changing global context.
  • Installer: Updated to ensure the 0-context/ workflow directory is installed.
  • Compatibility: 100% backward compatible; default behavior unchanged when no context file is present.
  • Implemented with as minimal footprint as I could think of.

Directory structure (when active)

monorepo-root/ 
├── _bmad/ │ 
└── .current_project # Context marker (e.g., "app-alpha") 
├── _bmad-output/ 
│ ├── app-alpha/ 
│ │ ├── planning-artifacts/ 
│ │ └── implementation-artifacts/ 
│ └── app-beta/ 
│ └── planning-artifacts/ 
├── apps/ │ 
├── app-alpha/ 
│ └── app-beta/ 
└── package.json

Testing

  • Added Test Suite 32: Monorepo Config Generation and Test Suite 33: Context Skill Discovery in test-installation-components.js to verify monorepo context block extraction and skill discovery.
  • All existing tests pass; npm ci && npm run quality succeeds.

- Add monorepo_context config section to module.yaml for path resolution
- Add bmad-project-list, bmad-project-new, bmad-project-switch skills
- Config-level hook: LLM reads config and applies context before path vars
- Inline overrides via #project:NAME or #p:NAME in invocations
- Installer: ensure 0-context workflow dir is installed
- Add docs/how-to/monorepo-setup.md
- 100% backward compatible when no .current_project file

Made-with: Cursor
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 15, 2026

📝 Walkthrough

Walkthrough

Introduces monorepo/multi-project support enabling a single BMAD installation to serve multiple independent projects. Adds three project management workflows (list, create, switch), agent menu triggers across five agent configurations, module-level context configuration, installer enhancements for static block preservation, and related tests.

Changes

Cohort / File(s) Summary
Documentation
docs/how-to/monorepo-setup.md
Adds comprehensive guide for monorepo setup, including configuration mechanism via .current_project file, quick-start commands (list, create, switch, clear), directory structure, inline overrides, precedence rules, and security validation (path traversal, absolute paths, character whitelist).
Agent Menu Configuration
src/bmm/agents/architect.agent.yaml, src/bmm/agents/dev.agent.yaml, src/bmm/agents/pm.agent.yaml, src/bmm/agents/quick-flow-solo-dev.agent.yaml, src/bmm/agents/sm.agent.yaml
Adds identical project management triggers (PN: project-new, PS: project-switch, PL: project-list) to agent menus, each wired to corresponding bmad-project-* skills with descriptive labels.
Module Configuration
src/bmm/module.yaml
Adds monorepo_context configuration block with enabled flag, context file location, inline override patterns, and validation rules (whitelist regex, traversal/absolute path rejection) for multi-project context resolution.
Project List Workflow
src/bmm/workflows/0-context/bmad-project-list/*
New workflow that scans _bmad-output/ for project subdirectories, displays a numbered list excluding hidden dirs and standard BMAD artifact folders, marks active project, and prompts for project switching/creation.
Project New Workflow
src/bmm/workflows/0-context/bmad-project-new/*
New workflow for creating BMAD project contexts with validation (traversal prevention, absolute path rejection, whitelist pattern), existence checks, directory structure setup (_bmad-output//), and active project selector updates.
Project Switch Workflow
src/bmm/workflows/0-context/bmad-project-switch/*
New workflow for changing active project context; enumerates projects from _bmad-output/, supports numeric/path selection or CLEAR action, validates input against whitelist, and updates active project selector file.
Installer & Tests
tools/cli/installers/lib/core/installer.js, test/test-installation-components.js
Extends installer with methods (getStaticConfigBlocks, resolveModuleSchemaPath, extractMonorepoContextBlock) to preserve and inject monorepo_context blocks from module.yaml. Adds tests (Test 32, 33) validating monorepo config emission and context skills discovery.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • bmadcode
  • alexeyv
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat(bmm): add monorepo/multi-project support via skills' accurately and concisely summarizes the main change: introducing monorepo support through skills-based implementation.
Description check ✅ Passed The PR description is comprehensive and directly related to the changeset, covering what (monorepo support via skills), why (cleaner organization), how (config hooks, skills, inline overrides), testing approach, and backward compatibility details.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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

❤️ Share

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

Tip

You can customize the high-level summary generated by CodeRabbit.

Configure the reviews.high_level_summary_instructions setting to provide custom instructions for generating the high-level summary.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 17

Note

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

🟡 Minor comments (9)
src/bmm/agents/dev.agent.yaml-40-50 (1)

40-50: ⚠️ Potential issue | 🟡 Minor

Menu text should surface one-off override syntax here too.

These entries are the most visible interface; omitting #project:NAME / #p:NAME leaves a key feature undiscoverable for Dev users.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bmm/agents/dev.agent.yaml` around lines 40 - 50, Update the visible menu
descriptions for the project commands so they mention the one-off override
syntax; specifically edit the description fields for the triggers that execute
"skill:bmad-project-new", "skill:bmad-project-switch", and
"skill:bmad-project-list" to include text like "`#project:NAME` / `#p:NAME`
(one-off override)" so Dev users can discover the override syntax when using
Project New, Project Switch, and Project List.
src/bmm/workflows/0-context/bmad-project-list/SKILL.md-3-3 (1)

3-3: ⚠️ Potential issue | 🟡 Minor

Set expectation that the active project is identified in list output.

“List available projects” is incomplete UX guidance; users also need to know which one is currently active.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bmm/workflows/0-context/bmad-project-list/SKILL.md` at line 3, Update the
SKILL.md description so it explicitly states the active project will be
identified in the output: modify the description field (the "description" string
in SKILL.md for the bmad-project-list skill) to mention that the list will mark
or indicate which project is currently active (e.g., "and indicate the currently
active project"), ensuring users know the active project is highlighted when
they say "project list", "list projects", or "show projects".
src/bmm/workflows/0-context/bmad-project-switch/SKILL.md-3-3 (1)

3-3: ⚠️ Potential issue | 🟡 Minor

Document persistence semantics of project switching.

This description should explicitly state that switching updates the active project context beyond the current prompt/session scope.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bmm/workflows/0-context/bmad-project-switch/SKILL.md` at line 3, Update
the skill description string (the description field in SKILL.md) to explicitly
state the persistence semantics: clarify that invoking "project switch" changes
the active project context globally (or for the current user/agent) beyond the
current prompt/session and persists for subsequent interactions until changed
again; keep the wording concise and include examples like "switch project",
"project switch", or "choose project" to retain intent matching.
src/bmm/workflows/0-context/bmad-project-new/SKILL.md-3-3 (1)

3-3: ⚠️ Potential issue | 🟡 Minor

Clarify that this action changes persistent project context.

“Create a new project” is clear, but users also need to know this sets active context persistently (not just current message scope).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bmm/workflows/0-context/bmad-project-new/SKILL.md` at line 3, Update the
SKILL.md description string to explicitly state that creating a new project
changes and persists the active project context across sessions rather than only
for the current message; modify the existing description (the YAML key
"description") used for triggers like "project new", "new project", and "create
project" to include wording such as "creates a new project and sets it as the
persistent active project/context" so callers of the action understand it
updates persistent project state.
src/bmm/agents/quick-flow-solo-dev.agent.yaml-38-48 (1)

38-48: ⚠️ Potential issue | 🟡 Minor

Expose inline override syntax in the menu descriptions.

PR adds #project:NAME / #p:NAME, but the primary UX surface here doesn’t advertise it, so users won’t discover the feature.

Suggested description update
-      description: "[PN] Project New: Create a new project and make it the active project context"
+      description: "[PN] Project New: Create a new project and make it the active context (or use `#project`:NAME / `#p`:NAME for one-off targeting)"

-      description: "[PS] Project Switch: Switch the active project context for monorepo support"
+      description: "[PS] Project Switch: Switch active project context (or use `#project`:NAME / `#p`:NAME for one-off targeting)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bmm/agents/quick-flow-solo-dev.agent.yaml` around lines 38 - 48, Update
the menu descriptions for the project commands so they advertise the inline
override syntax (`#project`:NAME and `#p`:NAME); specifically edit the description
strings for the triggers "PN" ("skill:bmad-project-new"), "PS"
("skill:bmad-project-switch"), and "PL" ("skill:bmad-project-list") to append a
short note like "Supports inline override: `#project`:NAME or `#p`:NAME" so users
can discover the feature.
src/bmm/module.yaml-75-78 (1)

75-78: ⚠️ Potential issue | 🟡 Minor

Case-insensitive override behavior is underspecified in config.

The contract text requires case-insensitive #project:/#p: matching, but config only provides lowercase literals. Without an explicit casing rule in parsed config, runtime behavior can drift across implementations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bmm/module.yaml` around lines 75 - 78, The inline override patterns in
module.yaml (inline_override_patterns: "#project:", "#p:") don't specify
case-insensitive matching; update the config to make matching explicit—either
replace the literal patterns with case-insensitive regexes (e.g. use patterns
with (?i) or start-anchor regex like (?i)^#project: and (?i)^#p:) or add an
explicit flag such as inline_override_case_insensitive: true alongside
context_file and inline_override_patterns so runtime parsers know to match
`#project`:/#p: in a case-insensitive way.
src/bmm/workflows/0-context/bmad-project-new/workflow.md-34-41 (1)

34-41: ⚠️ Potential issue | 🟡 Minor

Yes/No branch is fragile and likely to mis-handle normal input variants.

The flow only specifies Yes/No literals. Normalize case/whitespace and accept standard affirmative/negative forms to avoid false aborts.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bmm/workflows/0-context/bmad-project-new/workflow.md` around lines 34 -
41, The Yes/No branch in the Ask/Wait for input steps is fragile because it only
matches literal "Yes"/"No"; update the input handling logic (the "Ask" -> "Wait
for input" branch that currently checks `Yes` and `No`) to normalize user input
(trim whitespace and convert to lowercase) and match against common affirmative
and negative variants (e.g., affirmative: "y", "yes", "yeah", "yep", "true",
"1"; negative: "n", "no", "nah", "false", "0"). Replace the strict `Yes`/`No`
checks with this normalized matching and add a fallback to reprompt or show a
clear invalid-response message if the input doesn't match any variant; keep the
same behavior for the affirmative branch that writes the active project selector
file and for the negative branch that instructs the user to pick another name or
use PS.
src/bmm/workflows/0-context/bmad-project-list/workflow.md-21-22 (1)

21-22: ⚠️ Potential issue | 🟡 Minor

Stale .current_project handling is missing.

If selector points to a deleted or renamed project, the workflow currently has no remediation path. It should surface that state and suggest clearing/switching context.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bmm/workflows/0-context/bmad-project-list/workflow.md` around lines 21 -
22, Detect and handle a stale selector: when reading the active project from
`.current_project` (or `monorepo_context.context_file`) and that project name is
not present in the discovered project list, surface a clear "stale context"
state in the workflow output (e.g., "CURRENT PROJECT: <name> (missing/deleted)")
and present remediation actions to the user (offer to clear the context by
removing the selector file and/or immediately switch to another project via the
existing PS/PN flow). Update the code paths that implement steps "Check whether
an active project..." and "Inform the user..." to (1) validate the selector
against the discovered projects, (2) mark the active project only when valid,
and (3) add the missing-state message and two actionable options: "Clear current
project" (delete `monorepo_context.context_file`) and "Switch/create project"
(invoke PS/PN handlers).
test/test-installation-components.js-1886-1891 (1)

1886-1891: ⚠️ Potential issue | 🟡 Minor

Test 32 is brittle because it asserts comment text instead of behavior.

Checking INLINE OVERRIDE ties test stability to prose changes in comments, not parser behavior. This will fail on harmless documentation edits.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/test-installation-components.js` around lines 1886 - 1891, Test 32 is
brittle because it asserts the literal comment text "INLINE OVERRIDE" in
extractedBlock32; instead update the assertion on extractedBlock32 to validate
preservation of comment structure/behavior (e.g., assert it contains a comment
line or comment delimiter) rather than specific prose. Locate the failing
assertion referencing extractedBlock32 in the "Installer extracts monorepo
context block from module schema" test and replace the exact-text check with a
check for a comment marker or a regex that matches one or more comment lines
(for example look for '//' or '#' or a comment-line pattern) so the test
verifies comment retention without tying to documentation wording.
🧹 Nitpick comments (3)
src/bmm/agents/quick-flow-solo-dev.agent.yaml (1)

38-48: Extract PN/PS/PL menu entries into a shared source to prevent drift.

This block is repeated across multiple agent manifests in the same PR; one text drift later, behavior/documentation diverges by agent.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bmm/agents/quick-flow-solo-dev.agent.yaml` around lines 38 - 48, Extract
the three menu entries (trigger: PN -> exec: "skill:bmad-project-new", trigger:
PS -> exec: "skill:bmad-project-switch", trigger: PL -> exec:
"skill:bmad-project-list") into a single shared manifest/snippet and replace the
duplicated blocks in each agent manifest with a reference/include/anchor to that
shared source so all agents consume the same canonical entries; ensure the
shared snippet contains the description fields and update the agent manifests to
import or reference it (and adjust any build/packaging step that assembles agent
YAMLs to include the shared snippet).
src/bmm/agents/architect.agent.yaml (1)

31-41: Project-context menu wiring is duplicated across agents and will drift.

The PN/PS/PL block is repeated in multiple agent YAMLs. Centralize shared menu entries (template/include/merge step) so trigger text and skill mappings stay consistent across agent updates.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/bmm/agents/architect.agent.yaml` around lines 31 - 41, The PN/PS/PL menu
entries (triggers "PN","PS","PL" and exec mappings
"skill:bmad-project-new","skill:bmad-project-switch","skill:bmad-project-list")
are duplicated across multiple agent YAMLs; refactor by extracting these shared
menu items into a single reusable include/template and replace the repeated
blocks with a reference to that include in each agent (or use a YAML
merge/anchor) so all agents reference the centralized definition and updates
remain consistent.
test/test-installation-components.js (1)

1938-1940: Suite 33 is non-hermetic because it copies live workflow sources.

Pulling the entire src/bmm/workflows/0-context tree makes this test sensitive to unrelated future file additions/renames. Use a minimal, explicit fixture containing only the three skills under test.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/test-installation-components.js` around lines 1938 - 1940, The test is
non-hermetic because it copies the entire live workflow tree via
sourceContextDir33/targetContextDir33 and fs.copy; replace that behavior with a
minimal explicit fixture: create a small temp fixture directory containing only
the three specific skill files needed for Suite 33 (instead of copying
src/bmm/workflows/0-context), and update the setup that uses
sourceContextDir33/targetContextDir33 to point to that minimal fixture; ensure
the files include the same names/contents required by the tests and remove the
fs.copy of the full source tree.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/how-to/monorepo-setup.md`:
- Around line 14-22: The docs fail to state that `_bmad/.current_project` is
local-only and must be excluded from version control; update the "A
`.current_project` file..." paragraph to explicitly say `.current_project`
stores mutable local state and should never be committed, add a note telling
users to add `_bmad/.current_project` to their VCS ignore (e.g., .gitignore),
and keep the existing guidance on using `skill:bmad-project-list`,
`skill:bmad-project-new`, and `skill:bmad-project-switch` while mentioning that
committing this file can flip context for other contributors and CI.

In `@src/bmm/module.yaml`:
- Around line 65-71: The current path override keys (e.g., output_folder,
planning_artifacts, implementation_artifacts, project_knowledge,
sprint_status_file) allow project_suffix values containing '/' which permits
deep nested output paths that break the project discovery expectations; either
validate and reject project_suffix values containing path separators (disallow
'/' and possibly '\' depending on OS) where project_suffix is parsed, or
normalize/resolve project_suffix to a single top-level directory and update
discovery to perform recursive scanning; implement the chosen fix by adding
validation logic around the project_suffix input (or a normalizer) where these
variables are constructed and ensure discovery code uses the standardized form.
- Around line 80-82: The whitelist_regex, reject_traversal, and reject_absolute
settings currently allow ambiguous dot-segment and trailing-separator forms
(e.g., ".", "foo/", "a/./b"); update validation to first run a
path-normalization step that collapses and canonicalizes segments (removing "."
and resolving/denying any "." segments) and then validate the normalized path,
and tighten the whitelist_regex to explicitly reject single-dot segments and
trailing slashes (e.g., disallow patterns ending with "/" or containing "/./" or
solitary "."), ensuring reject_traversal and reject_absolute continue to block
".." and absolute paths after normalization.

In `@src/bmm/workflows/0-context/bmad-project-list/workflow.md`:
- Around line 11-16: The workflow step in bmad-project-list that lists
`{project-root}/_bmad-output/` must handle the directory-not-found case: detect
whether `_bmad-output/` exists before attempting to read it and, if absent or
unreadable, return an empty project list plus the `default (root)` unset project
context instead of failing; update the listing logic (the code that enumerates
subdirectories for project contexts in this workflow) to skip hidden dirs and
standard artifact dirs as before but short-circuit to return ["default (root)"]
when `_bmad-output/` is missing or an fs/stat call throws ENOENT.

In `@src/bmm/workflows/0-context/bmad-project-new/workflow.md`:
- Around line 27-33: The workflow's validation only checks the regex
`^[-a-zA-Z0-9._/]+$` and fails to block reserved directory names; add a
reserved-name check after the regex validation (before the "Check for Existing
Project" step) that rejects project names equal to any of the special
directories (e.g., "planning-artifacts", "implementation-artifacts",
"knowledge", "docs", etc.) or any path whose final segment matches those names,
returning the same Invalid project name error and halting; reference the
sanitized path used for existence checks
(`{project-root}/_bmad-output/<sanitized_path>`) to ensure the check prevents
collisions with root artifacts or hidden listings.
- Around line 23-24: The sanitization rule under the "**Cleanup**" step
currently removes any occurrences of "_bmad-output/" and can mutate valid
project names; change the logic to only strip a single leading "_bmad-output/"
prefix (if present), continue to trim leading/trailing slashes, and keep the
"Validate - No Traversal" check that rejects names containing ".."; update the
sanitization implementation (e.g., the function handling project name cleanup
such as sanitizeProjectName or the code referenced by the "**Cleanup**" bullet)
so it performs prefix-only removal rather than replacing all occurrences of
"_bmad-output/".

In `@src/bmm/workflows/0-context/bmad-project-switch/workflow.md`:
- Around line 56-59: The "Validate Existence" step currently only checks for
path existence; update it to explicitly verify that
{project-root}/_bmad-output/<sanitized_path> is a directory (not just any
filesystem entry) before treating it as a valid project context — if the path
exists but is not a directory, output the same error message and halt; make this
change in the workflow step labeled "Validate Existence" that references
<sanitized_path> so callers validate directory-type rather than mere existence.
- Around line 47-50: The cleanup step currently strips leading slashes before
the "Validate - No Absolute" check, allowing inputs like "/tmp/app" to bypass
absolute-path protection; modify the flow so absolute-path validation runs
against the original unmodified input (or perform an absolute/path-root check
before any cleanup), ensure the "Validate - No Absolute" rule in the workflow
uses the raw input to detect leading "/" and drive-letter patterns like "C:"
(and remains after any cleanup), and keep the "Cleanup" step to run only after
all absolute/path-root validations have passed.
- Around line 47-48: The cleanup rule in the workflow's sanitizer that “Remove
any occurrences of `_bmad-output/`” is too broad; change it to only strip that
segment when it appears as a leading prefix (e.g., remove one or more leading
`_bmad-output/` segments or a single leading `_bmad-output/` using a
prefix-aware check or regex like `^(_bmad-output/)+`), while keeping the
existing steps that trim leading/trailing slashes and the traversal check that
rejects `..`; update the description in workflow.md (the Cleanup bullet) to
state “Remove leading `_bmad-output/` prefix only” so it no longer implies a
global replacement.
- Around line 22-23: The manual-input path flow allows selecting reserved
artifact folder names; update the manual input handling in the "Manual input
path" step to validate the entered path against the reserved names list
(`planning-artifacts`, `implementation-artifacts`, `test-artifacts`,
`knowledge`, `docs`, `assets`) and reject or reprompt when the basename matches
any reserved name (same check should be added to the equivalent logic used
around lines referenced in the comment for the other occurrence). Implement this
by adding an isReservedArtifactFolder(name) helper (or inline check) and
invoking it from the code that processes manual entries so users cannot set
context to those reserved folders and get a clear error message and retry
prompt.

In `@test/test-installation-components.js`:
- Around line 1909-1917: The test only checks for header and override patterns;
extend assertions on generatedConfig32 to also verify security-critical fields
by asserting presence of the monorepo security keys and values: check
generatedConfig32.includes('context_file:') and that it includes the boolean
flags 'reject_traversal: true' and 'reject_absolute: true', and add an assertion
that the exact whitelist regex string used in the template (the inline
whitelist/allowlist regex that should appear alongside inline_override_patterns)
is present via generatedConfig32.includes('<exact-whitelist-regex-string>').
Ensure these assertions reference the same generatedConfig32 variable and the
existing inline_override_patterns context so they fail if the security config is
missing or altered.
- Around line 1872-1980: Add assertions to explicitly test
backward-compatibility and precedence: after calling
Installer.extractMonorepoContextBlock and Installer.generateModuleConfigs assert
behavior when .current_project is absent (e.g., generatedConfig32 does not set a
current_project key or uses an expected default) and add checks that precedence
is respected by asserting values chosen follow inline override > file > defaults
(reference extractMonorepoContextBlock and generateModuleConfigs). For the
ManifestGenerator path, after generator33.generateManifests assert that when no
.current_project is present the generator33.skills/workflows behavior is
unchanged and add targeted precedence assertions by creating fixture files with
conflicting values (inline override marker vs file value vs generator defaults)
and confirming generator33.skills entries reflect the inline override when
present, otherwise the file, otherwise the default (reference
ManifestGenerator.generateManifests and
generator33.skills/generator33.workflows).

In `@tools/cli/installers/lib/core/installer.js`:
- Around line 2128-2136: The code currently sets block =
content.slice(headerIndex).trimEnd(), which greedily captures from the monorepo
header to EOF and will include any future keys appended after this section;
change the extraction to find the end of the monorepo YAML block instead of
slicing to EOF by locating the next section boundary (e.g., the next header
marker or a delimiter) and slice from headerIndex up to that end index; update
the logic around headerIndex and block so functions that reference them
(headerIndex, block, content.slice) use the computed endIndex (found via
searching for the next /^# ---/ or other section marker) to return only the
intended monorepo block.
- Around line 2137-2140: The current presence check uses
block.includes('monorepo_context:') which can match comments or malformed text;
instead parse or structurally validate the YAML in the variable `block` and
confirm the `monorepo_context` key actually exists (e.g. use a YAML parser like
js-yaml to safeLoad/safeParse `block` and verify typeof parsed.monorepo_context
!== 'undefined', or at minimum replace the includes check with a strict regex
that matches a top-level key like /^\s*monorepo_context\s*:/m); update the
conditional that currently inspects `block` so it only returns null when the
parsed content lacks a real `monorepo_context` key.
- Around line 2098-2100: The current logic that reads moduleSchemaPath and calls
extractMonorepoContextBlock can throw and abort the entire install; wrap the
read/parse step in a try/catch inside the same function/method (the code that
calls fs.readFile and extractMonorepoContextBlock) so failures are non-fatal: on
error log a debug/warn with context (including moduleSchemaPath and the error)
and return an empty array instead of rethrowing; keep returning [monorepoBlock]
when extraction succeeds. Ensure you update the same function that contains the
const content = await fs.readFile(moduleSchemaPath, 'utf8') line.
- Around line 2071-2074: The current append logic blindly adds
staticConfigBlocks after yamlContent, which breaks when yamlContent is the
serialized empty object '{}'; modify the code that handles staticConfigBlocks so
it first checks if yamlContent.trim() === '{}' (or yamlContent.trim() is empty)
and in that case replace yamlContent with the joined staticConfigBlocks (plus
trailing newline) instead of appending; otherwise keep the existing trimEnd() +
`\n\n${staticConfigBlocks.join('\n\n')}\n` behavior. Ensure you reference the
yamlContent and staticConfigBlocks variables when making the conditional branch.
- Around line 2109-2111: resolveModuleSchemaPath() is reading stale data from
configCollector.customModulePaths; update it to consult the live moduleManager
state (moduleManager.customModulePaths) instead of
configCollector.customModulePaths so it uses post-discovery updates that were
propagated via setCustomModulePaths(), or alternatively ensure
collectAllConfigurations() keeps configCollector.customModulePaths synced after
discovery; specifically, modify resolveModuleSchemaPath() (used by
generateModuleConfigs()) to check moduleManager.customModulePaths first (or
refresh configCollector from moduleManager) before falling back to
moduleManager.findModuleSource().

---

Minor comments:
In `@src/bmm/agents/dev.agent.yaml`:
- Around line 40-50: Update the visible menu descriptions for the project
commands so they mention the one-off override syntax; specifically edit the
description fields for the triggers that execute "skill:bmad-project-new",
"skill:bmad-project-switch", and "skill:bmad-project-list" to include text like
"`#project:NAME` / `#p:NAME` (one-off override)" so Dev users can discover the
override syntax when using Project New, Project Switch, and Project List.

In `@src/bmm/agents/quick-flow-solo-dev.agent.yaml`:
- Around line 38-48: Update the menu descriptions for the project commands so
they advertise the inline override syntax (`#project`:NAME and `#p`:NAME);
specifically edit the description strings for the triggers "PN"
("skill:bmad-project-new"), "PS" ("skill:bmad-project-switch"), and "PL"
("skill:bmad-project-list") to append a short note like "Supports inline
override: `#project`:NAME or `#p`:NAME" so users can discover the feature.

In `@src/bmm/module.yaml`:
- Around line 75-78: The inline override patterns in module.yaml
(inline_override_patterns: "#project:", "#p:") don't specify case-insensitive
matching; update the config to make matching explicit—either replace the literal
patterns with case-insensitive regexes (e.g. use patterns with (?i) or
start-anchor regex like (?i)^#project: and (?i)^#p:) or add an explicit flag
such as inline_override_case_insensitive: true alongside context_file and
inline_override_patterns so runtime parsers know to match `#project`:/#p: in a
case-insensitive way.

In `@src/bmm/workflows/0-context/bmad-project-list/SKILL.md`:
- Line 3: Update the SKILL.md description so it explicitly states the active
project will be identified in the output: modify the description field (the
"description" string in SKILL.md for the bmad-project-list skill) to mention
that the list will mark or indicate which project is currently active (e.g.,
"and indicate the currently active project"), ensuring users know the active
project is highlighted when they say "project list", "list projects", or "show
projects".

In `@src/bmm/workflows/0-context/bmad-project-list/workflow.md`:
- Around line 21-22: Detect and handle a stale selector: when reading the active
project from `.current_project` (or `monorepo_context.context_file`) and that
project name is not present in the discovered project list, surface a clear
"stale context" state in the workflow output (e.g., "CURRENT PROJECT: <name>
(missing/deleted)") and present remediation actions to the user (offer to clear
the context by removing the selector file and/or immediately switch to another
project via the existing PS/PN flow). Update the code paths that implement steps
"Check whether an active project..." and "Inform the user..." to (1) validate
the selector against the discovered projects, (2) mark the active project only
when valid, and (3) add the missing-state message and two actionable options:
"Clear current project" (delete `monorepo_context.context_file`) and
"Switch/create project" (invoke PS/PN handlers).

In `@src/bmm/workflows/0-context/bmad-project-new/SKILL.md`:
- Line 3: Update the SKILL.md description string to explicitly state that
creating a new project changes and persists the active project context across
sessions rather than only for the current message; modify the existing
description (the YAML key "description") used for triggers like "project new",
"new project", and "create project" to include wording such as "creates a new
project and sets it as the persistent active project/context" so callers of the
action understand it updates persistent project state.

In `@src/bmm/workflows/0-context/bmad-project-new/workflow.md`:
- Around line 34-41: The Yes/No branch in the Ask/Wait for input steps is
fragile because it only matches literal "Yes"/"No"; update the input handling
logic (the "Ask" -> "Wait for input" branch that currently checks `Yes` and
`No`) to normalize user input (trim whitespace and convert to lowercase) and
match against common affirmative and negative variants (e.g., affirmative: "y",
"yes", "yeah", "yep", "true", "1"; negative: "n", "no", "nah", "false", "0").
Replace the strict `Yes`/`No` checks with this normalized matching and add a
fallback to reprompt or show a clear invalid-response message if the input
doesn't match any variant; keep the same behavior for the affirmative branch
that writes the active project selector file and for the negative branch that
instructs the user to pick another name or use PS.

In `@src/bmm/workflows/0-context/bmad-project-switch/SKILL.md`:
- Line 3: Update the skill description string (the description field in
SKILL.md) to explicitly state the persistence semantics: clarify that invoking
"project switch" changes the active project context globally (or for the current
user/agent) beyond the current prompt/session and persists for subsequent
interactions until changed again; keep the wording concise and include examples
like "switch project", "project switch", or "choose project" to retain intent
matching.

In `@test/test-installation-components.js`:
- Around line 1886-1891: Test 32 is brittle because it asserts the literal
comment text "INLINE OVERRIDE" in extractedBlock32; instead update the assertion
on extractedBlock32 to validate preservation of comment structure/behavior
(e.g., assert it contains a comment line or comment delimiter) rather than
specific prose. Locate the failing assertion referencing extractedBlock32 in the
"Installer extracts monorepo context block from module schema" test and replace
the exact-text check with a check for a comment marker or a regex that matches
one or more comment lines (for example look for '//' or '#' or a comment-line
pattern) so the test verifies comment retention without tying to documentation
wording.

---

Nitpick comments:
In `@src/bmm/agents/architect.agent.yaml`:
- Around line 31-41: The PN/PS/PL menu entries (triggers "PN","PS","PL" and exec
mappings
"skill:bmad-project-new","skill:bmad-project-switch","skill:bmad-project-list")
are duplicated across multiple agent YAMLs; refactor by extracting these shared
menu items into a single reusable include/template and replace the repeated
blocks with a reference to that include in each agent (or use a YAML
merge/anchor) so all agents reference the centralized definition and updates
remain consistent.

In `@src/bmm/agents/quick-flow-solo-dev.agent.yaml`:
- Around line 38-48: Extract the three menu entries (trigger: PN -> exec:
"skill:bmad-project-new", trigger: PS -> exec: "skill:bmad-project-switch",
trigger: PL -> exec: "skill:bmad-project-list") into a single shared
manifest/snippet and replace the duplicated blocks in each agent manifest with a
reference/include/anchor to that shared source so all agents consume the same
canonical entries; ensure the shared snippet contains the description fields and
update the agent manifests to import or reference it (and adjust any
build/packaging step that assembles agent YAMLs to include the shared snippet).

In `@test/test-installation-components.js`:
- Around line 1938-1940: The test is non-hermetic because it copies the entire
live workflow tree via sourceContextDir33/targetContextDir33 and fs.copy;
replace that behavior with a minimal explicit fixture: create a small temp
fixture directory containing only the three specific skill files needed for
Suite 33 (instead of copying src/bmm/workflows/0-context), and update the setup
that uses sourceContextDir33/targetContextDir33 to point to that minimal
fixture; ensure the files include the same names/contents required by the tests
and remove the fs.copy of the full source tree.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4899f471-2803-4097-ac21-16616426a876

📥 Commits

Reviewing files that changed from the base of the PR and between 42b1d0f and fad8a79.

📒 Files selected for processing (18)
  • docs/how-to/monorepo-setup.md
  • src/bmm/agents/architect.agent.yaml
  • src/bmm/agents/dev.agent.yaml
  • src/bmm/agents/pm.agent.yaml
  • src/bmm/agents/quick-flow-solo-dev.agent.yaml
  • src/bmm/agents/sm.agent.yaml
  • src/bmm/module.yaml
  • src/bmm/workflows/0-context/bmad-project-list/SKILL.md
  • src/bmm/workflows/0-context/bmad-project-list/bmad-skill-manifest.yaml
  • src/bmm/workflows/0-context/bmad-project-list/workflow.md
  • src/bmm/workflows/0-context/bmad-project-new/SKILL.md
  • src/bmm/workflows/0-context/bmad-project-new/bmad-skill-manifest.yaml
  • src/bmm/workflows/0-context/bmad-project-new/workflow.md
  • src/bmm/workflows/0-context/bmad-project-switch/SKILL.md
  • src/bmm/workflows/0-context/bmad-project-switch/bmad-skill-manifest.yaml
  • src/bmm/workflows/0-context/bmad-project-switch/workflow.md
  • test/test-installation-components.js
  • tools/cli/installers/lib/core/installer.js

Comment on lines +2071 to +2074
if (staticConfigBlocks.length > 0) {
yamlContent = yamlContent.trimEnd();
yamlContent += `\n\n${staticConfigBlocks.join('\n\n')}\n`;
}
Copy link
Copy Markdown

@coderabbitai coderabbitai bot Mar 15, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Appending static blocks after {} can generate invalid YAML.

At Line 2072, empty configs serialize to {}. Appending another top-level block afterward can make config.yaml unparsable.

Proposed fix
-        if (staticConfigBlocks.length > 0) {
-          yamlContent = yamlContent.trimEnd();
+        if (staticConfigBlocks.length > 0) {
+          yamlContent = yamlContent.trim();
+          if (yamlContent === '{}') {
+            yamlContent = '';
+          }
           yamlContent += `\n\n${staticConfigBlocks.join('\n\n')}\n`;
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/cli/installers/lib/core/installer.js` around lines 2071 - 2074, The
current append logic blindly adds staticConfigBlocks after yamlContent, which
breaks when yamlContent is the serialized empty object '{}'; modify the code
that handles staticConfigBlocks so it first checks if yamlContent.trim() ===
'{}' (or yamlContent.trim() is empty) and in that case replace yamlContent with
the joined staticConfigBlocks (plus trailing newline) instead of appending;
otherwise keep the existing trimEnd() +
`\n\n${staticConfigBlocks.join('\n\n')}\n` behavior. Ensure you reference the
yamlContent and staticConfigBlocks variables when making the conditional branch.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

done

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Rate Limit Exceeded

@serrnovik have exceeded the limit for the number of chat messages per hour. Please wait 0 minutes and 50 seconds before sending another message.

Comment on lines +2109 to +2111
if (this.configCollector.customModulePaths?.has(moduleName)) {
return path.join(this.configCollector.customModulePaths.get(moduleName), 'module.yaml');
}
Copy link
Copy Markdown

@coderabbitai coderabbitai bot Mar 15, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "1) Find all reads/writes of customModulePaths in installer/config-collector:"
rg -n -C2 '\bcustomModulePaths\b' tools/cli/installers/lib/core/installer.js tools/cli/installers/lib/core/config-collector.js

echo
echo "2) Confirm whether ConfigCollector defines and updates customModulePaths:"
rg -n -C3 'class ConfigCollector|this\.customModulePaths|customModulePaths\s*=' tools/cli/installers/lib/core/config-collector.js

echo
echo "Expected:"
echo "- If ConfigCollector does not persist/update customModulePaths, resolveModuleSchemaPath should use Installer/moduleManager state instead."

Repository: bmad-code-org/BMAD-METHOD

Length of output: 15232


🏁 Script executed:

echo "1) Find all calls to resolveModuleSchemaPath():"
rg -n 'resolveModuleSchemaPath' tools/cli/installers/lib/core/installer.js

echo
echo "2) Check the context around these calls (look for usage patterns):"
rg -n -B5 -A5 'resolveModuleSchemaPath' tools/cli/installers/lib/core/installer.js | head -100

echo
echo "3) Check if moduleManager has a method to get custom module paths:"
rg -n 'setCustomModulePaths|getCustomModulePaths|customModulePaths' tools/cli/installers/lib/core/module-manager.js | head -30

Repository: bmad-code-org/BMAD-METHOD

Length of output: 1560


🏁 Script executed:

echo "1) Find all calls to getStaticConfigBlocks():"
rg -n 'getStaticConfigBlocks' tools/cli/installers/

echo
echo "2) Locate moduleManager file:"
fd -name '*module*manager*' tools/cli/installers/

echo
echo "3) Check ModuleManager for customModulePaths access methods:"
fd -name '*module*manager*' tools/cli/installers/ -x cat {} \; | grep -n 'customModulePaths\|setCustomModulePaths\|getCustomModulePaths' | head -20

Repository: bmad-code-org/BMAD-METHOD

Length of output: 907


🏁 Script executed:

echo "1) Find moduleManager instantiation in installer.js:"
rg -n 'this\.moduleManager\s*=' tools/cli/installers/lib/core/installer.js | head -5

echo
echo "2) Find class ModuleManager definition:"
rg -n 'class ModuleManager' tools/cli/installers/

echo
echo "3) Look at context around line 2070 where getStaticConfigBlocks is called:"
sed -n '2055,2085p' tools/cli/installers/lib/core/installer.js

Repository: bmad-code-org/BMAD-METHOD

Length of output: 1545


🏁 Script executed:

echo "1) Find what method contains line 2070:"
sed -n '2000,2070p' tools/cli/installers/lib/core/installer.js | grep -n '^  [a-zA-Z]' | tail -5

echo
echo "2) Get broader context - find method definition before line 2070:"
rg -n '^\s{2}[a-zA-Z_][a-zA-Z0-9_]*\s*\(' tools/cli/installers/lib/core/installer.js | awk -F: '{print $1}' | awk '$1 < 2070 {max=$1} END {print max}' | xargs -I {} sed -n '{}p' tools/cli/installers/lib/core/installer.js

echo
echo "3) Check ModuleManager.setCustomModulePaths and see if there's a getter:"
sed -n '1,100p' tools/cli/installers/lib/modules/manager.js

echo
echo "4) Search for customModulePaths in manager.js:"
rg -n 'customModulePaths' tools/cli/installers/lib/modules/manager.js

Repository: bmad-code-org/BMAD-METHOD

Length of output: 4614


🏁 Script executed:

echo "1) Find the method containing line 2070 by searching backwards:"
awk 'NR<=2070 && /^  async [a-zA-Z_]/ {last=$0; lastNR=NR} NR==2070 {print lastNR": "last; exit}' tools/cli/installers/lib/core/installer.js

echo
echo "2) Get the full method signature:"
rg -n '^\s{2}async install\(' tools/cli/installers/lib/core/installer.js

echo
echo "3) Find where install() is called:"
rg -n '\.install\(' tools/cli/installers/lib/core/installer.js | grep -v 'installVerbatim\|installToMultiple\|isCustomModule\|isInstalled' | head -10

echo
echo "4) Check the timeline - find all customModulePaths updates and when getStaticConfigBlocks is called:"
rg -n 'customModulePaths\.set|getStaticConfigBlocks|await this\.install' tools/cli/installers/lib/core/installer.js | grep -E '^[0-9]+:' | sort -t: -k1 -n | tail -20

Repository: bmad-code-org/BMAD-METHOD

Length of output: 1858


🏁 Script executed:

echo "1) Find where generateModuleConfigs is called in install():"
rg -n 'generateModuleConfigs' tools/cli/installers/lib/core/installer.js

echo
echo "2) Look at the install() method structure around those calls:"
sed -n '2050,2100p' tools/cli/installers/lib/core/installer.js

echo
echo "3) Get broader view of install() to see the order of operations:"
sed -n '900,1100p' tools/cli/installers/lib/core/installer.js | grep -n 'customModulePaths\|generateModuleConfigs\|setCustomModulePaths'

Repository: bmad-code-org/BMAD-METHOD

Length of output: 2913


🏁 Script executed:

echo "1) Show the full install() method structure to understand flow:"
sed -n '229,450p' tools/cli/installers/lib/core/installer.js

echo
echo "2) Find where customModulePaths gets used - track the flow:"
sed -n '260,380p' tools/cli/installers/lib/core/installer.js

Repository: bmad-code-org/BMAD-METHOD

Length of output: 16123


🏁 Script executed:

echo "1) Look at context around line 553 to understand when it's updated:"
sed -n '500,570p' tools/cli/installers/lib/core/installer.js

echo
echo "2) Look at context around line 922 where generateModuleConfigs is first called:"
sed -n '880,950p' tools/cli/installers/lib/core/installer.js

Repository: bmad-code-org/BMAD-METHOD

Length of output: 6759


🏁 Script executed:

echo "Check lines 2118-2119 mentioned in 'Also applies to':"
sed -n '2115,2125p' tools/cli/installers/lib/core/installer.js

Repository: bmad-code-org/BMAD-METHOD

Length of output: 549


🏁 Script executed:

echo "1) Verify the full resolveModuleSchemaPath method:"
sed -n '2108,2125p' tools/cli/installers/lib/core/installer.js

echo
echo "2) Check when findModuleSource is used and if it includes customModulePaths:"
rg -n 'findModuleSource' tools/cli/installers/lib/modules/manager.js -A 15 | head -40

Repository: bmad-code-org/BMAD-METHOD

Length of output: 2542


resolveModuleSchemaPath() reads from stale configCollector.customModulePaths instead of current moduleManager state.

After collectAllConfigurations() stores customModulePaths in configCollector (line 363/369), the local customModulePaths variable continues to be updated via cache discovery (line 553) and other sources (lines 637, 832, 998). These updates are synced to moduleManager via setCustomModulePaths() calls, but never propagated back to configCollector.

When resolveModuleSchemaPath() is called from generateModuleConfigs() (line 2093), it checks configCollector.customModulePaths first (lines 2109–2110), which is now stale. While a fallback to moduleManager.findModuleSource() exists (lines 2118–2119), consulting the stale source first is inefficient and loses the validation guarantee that configCollector provides during collectAllConfigurations().

Update resolveModuleSchemaPath() to check moduleManager.customModulePaths directly instead of configCollector.customModulePaths, or keep configCollector synced with post-discovery updates.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/cli/installers/lib/core/installer.js` around lines 2109 - 2111,
resolveModuleSchemaPath() is reading stale data from
configCollector.customModulePaths; update it to consult the live moduleManager
state (moduleManager.customModulePaths) instead of
configCollector.customModulePaths so it uses post-discovery updates that were
propagated via setCustomModulePaths(), or alternatively ensure
collectAllConfigurations() keeps configCollector.customModulePaths synced after
discovery; specifically, modify resolveModuleSchemaPath() (used by
generateModuleConfigs()) to check moduleManager.customModulePaths first (or
refresh configCollector from moduleManager) before falling back to
moduleManager.findModuleSource().

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

done

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Rate Limit Exceeded

@serrnovik have exceeded the limit for the number of chat messages per hour. Please wait 2 minutes and 13 seconds before sending another message.

Comment on lines +2128 to +2136
// Capture from the header comment through to the end of the monorepo_context YAML block.
// The block is expected at the end of the file, after any other config sections.
const headerIndex = content.indexOf('# --- Monorepo / Multi-Project Context Support ---');
if (headerIndex === -1) {
return null;
}

const block = content.slice(headerIndex).trimEnd();

Copy link
Copy Markdown

@coderabbitai coderabbitai bot Mar 15, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Block extraction is brittle because it captures from marker to EOF.

If future keys are added after the monorepo section in module.yaml, they will be unintentionally injected into generated config.yaml.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/cli/installers/lib/core/installer.js` around lines 2128 - 2136, The
code currently sets block = content.slice(headerIndex).trimEnd(), which greedily
captures from the monorepo header to EOF and will include any future keys
appended after this section; change the extraction to find the end of the
monorepo YAML block instead of slicing to EOF by locating the next section
boundary (e.g., the next header marker or a delimiter) and slice from
headerIndex up to that end index; update the logic around headerIndex and block
so functions that reference them (headerIndex, block, content.slice) use the
computed endIndex (found via searching for the next /^# ---/ or other section
marker) to return only the intended monorepo block.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

done

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Rate Limit Exceeded

@serrnovik have exceeded the limit for the number of chat messages per hour. Please wait 2 minutes and 8 seconds before sending another message.

Comment on lines +2137 to +2140
// Sanity check: the block must contain the structured YAML key
if (!block.includes('monorepo_context:')) {
return null;
}
Copy link
Copy Markdown

@coderabbitai coderabbitai bot Mar 15, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Substring presence is not structural validation of monorepo_context.

block.includes('monorepo_context:') can pass on comments or malformed text. This can append invalid/non-structured content to config output.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/cli/installers/lib/core/installer.js` around lines 2137 - 2140, The
current presence check uses block.includes('monorepo_context:') which can match
comments or malformed text; instead parse or structurally validate the YAML in
the variable `block` and confirm the `monorepo_context` key actually exists
(e.g. use a YAML parser like js-yaml to safeLoad/safeParse `block` and verify
typeof parsed.monorepo_context !== 'undefined', or at minimum replace the
includes check with a strict regex that matches a top-level key like
/^\s*monorepo_context\s*:/m); update the conditional that currently inspects
`block` so it only returns null when the parsed content lacks a real
`monorepo_context` key.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

done

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Rate Limit Exceeded

@serrnovik have exceeded the limit for the number of chat messages per hour. Please wait 2 minutes and 7 seconds before sending another message.

@alexeyv
Copy link
Copy Markdown
Collaborator

alexeyv commented Mar 16, 2026

Thanks, but. For BMAD proper it's too much extra complexity for what it's worth. What we need to do is figure out a good enough customization story to enable things like that in the customization layer. Closing.

@alexeyv alexeyv closed this Mar 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants