This commit is contained in:
Sergey Novikov 2026-02-22 14:10:09 +00:00 committed by GitHub
commit 9ce6ef31e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
50 changed files with 866 additions and 65 deletions

View File

@ -0,0 +1,82 @@
---
title: "Set Up Monorepo Support"
description: Manage multiple projects in a single repository with isolated artifacts
sidebar:
order: 8
---
BMad Method supports working in monorepo environments where multiple projects share a single repository. This allows you to centralize methodology files while keeping project artifacts isolated and organized.
:::note[Prerequisites]
- BMad Method v6.0.1+
- A repository containing multiple projects
:::
## Why Use Monorepo Support?
In a standard setup, BMad expects one project per repository. In a monorepo, you might have `apps/frontend`, `apps/backend`, and `packages/shared`. Without monorepo support, BMad's artifacts (plans, architecture, stories) would be mixed or require installing BMad in every sub-directory.
Monorepo support allows you to:
- **Centralize Methodology**: Install BMad once at the root based on your team's process.
- **Isolate Artifacts**: Automatically route outputs to project-specific folders (e.g., `_bmad-output/frontend/`).
- **Context Switch Easily**: Switch between projects without reinstalling or reconfiguring.
## Project Structure
When monorepo support is active, the structure changes slightly to accommodate multiple projects:
```
monorepo-root/
├── _bmad/ # Methodology (installed core & modules)
│ └── .current_project # Context marker (e.g., "app-alpha")
├── _bmad-output/ # Unified output directory
│ ├── app-alpha/ # Sub-project artifacts
│ │ ├── planning-artifacts/
│ │ └── implementation-artifacts/
│ └── app-beta/ # Sub-project artifacts
│ └── planning-artifacts/
├── apps/ # Actual source code
│ ├── app-alpha/
│ └── app-beta/
└── package.json
```
## How It Works
### Context Injection
Core and BMM workflows automatically check for the existence of `{project-root}/_bmad/.current_project`.
- **If found**: It reads the content (e.g., "app-alpha") and overrides the `output_folder` to `_bmad-output/app-alpha`.
- **If not found**: It behaves like a standard single-project installation, outputting to `_bmad-output` root.
### The /list-envs Command
You can view all available environments created in your monorepo by running the `/list-envs` command. This will scan your `_bmad-output/` directory and display all existing project environments, as well as indicate which one is currently active.
### The /set-project Command
You can easily manage the active project context using the `/set-project` workflow.
**To set a context:**
1. Run `/set-project <env_name>` in your chat.
2. If the environment does not exist, you will be prompted to create it interactively.
3. If you run `/set-project` without an argument, it will automatically list available environments and prompt you to select one or create a new one.
**To clear context (return to single-project mode):**
1. Run `/set-project CLEAR`.
### Inline Override
You can temporarily override the project context for a specific command without changing the global `.current_project` state. This is useful for one-off tasks in a different project.
Use the `#project:` syntax (or `#p:` for short) anywhere in your prompt:
```bash
# Full syntax
/create-prd #project:myproject_name
# Short alias
/create-story #p:frontend
```
**Note:** The inline override takes precedence over the `.current_project` file. If no project is specified via `#` or `.current_project`, BMad defaults to the root `_bmad-output` folder.

View File

@ -18,6 +18,12 @@ The fastest way to understand BMad is to try it.
Install BMad and run `/bmad-help` — it will guide you through everything based on your project and installed modules. Install BMad and run `/bmad-help` — it will guide you through everything based on your project and installed modules.
::: :::
## Advanced Setup
- **[Monorepo Support](./how-to/monorepo-setup.md)** — Manage multiple projects in a single repository.
- **[Non-Interactive Installation](./how-to/non-interactive-installation.md)** — Automate BMad installation for CI/CD.
## How to Use These Docs ## How to Use These Docs
These docs are organized into four sections based on what you're trying to do: These docs are organized into four sections based on what you're trying to do:

View File

@ -43,6 +43,7 @@
"test": "npm run test:schemas && npm run test:refs && npm run test:install && npm run validate:schemas && npm run lint && npm run lint:md && npm run format:check", "test": "npm run test:schemas && npm run test:refs && npm run test:install && npm run validate:schemas && npm run lint && npm run lint:md && npm run format:check",
"test:coverage": "c8 --reporter=text --reporter=html npm run test:schemas", "test:coverage": "c8 --reporter=text --reporter=html npm run test:schemas",
"test:install": "node test/test-installation-components.js", "test:install": "node test/test-installation-components.js",
"test:monorepo": "node test/test-monorepo-validation.js",
"test:refs": "node test/test-file-refs-csv.js", "test:refs": "node test/test-file-refs-csv.js",
"test:schemas": "node test/test-agent-schema.js", "test:schemas": "node test/test-agent-schema.js",
"validate:refs": "node tools/validate-file-refs.js --strict", "validate:refs": "node tools/validate-file-refs.js --strict",

View File

@ -28,4 +28,5 @@ bmm,4-implementation,Create Story,CS,30,_bmad/bmm/workflows/4-implementation/cre
bmm,4-implementation,Dev Story,DS,40,_bmad/bmm/workflows/4-implementation/dev-story/workflow.yaml,bmad-bmm-dev-story,true,dev,Create Mode,"Story cycle: Execute story implementation tasks and tests then CR then back to DS if fixes needed",,, bmm,4-implementation,Dev Story,DS,40,_bmad/bmm/workflows/4-implementation/dev-story/workflow.yaml,bmad-bmm-dev-story,true,dev,Create Mode,"Story cycle: Execute story implementation tasks and tests then CR then back to DS if fixes needed",,,
bmm,4-implementation,Code Review,CR,50,_bmad/bmm/workflows/4-implementation/code-review/workflow.yaml,bmad-bmm-code-review,false,dev,Create Mode,"Story cycle: If issues back to DS if approved then next CS or ER if epic complete",,, bmm,4-implementation,Code Review,CR,50,_bmad/bmm/workflows/4-implementation/code-review/workflow.yaml,bmad-bmm-code-review,false,dev,Create Mode,"Story cycle: If issues back to DS if approved then next CS or ER if epic complete",,,
bmm,4-implementation,QA Automation Test,QA,45,_bmad/bmm/workflows/qa/automate/workflow.yaml,bmad-bmm-qa-automate,false,qa,Create Mode,"Generate automated API and E2E tests for implemented code using the project's existing test framework (detects existing well known in use test frameworks). Use after implementation to add test coverage. NOT for code review or story validation - use CR for that.",implementation_artifacts,"test suite", bmm,4-implementation,QA Automation Test,QA,45,_bmad/bmm/workflows/qa/automate/workflow.yaml,bmad-bmm-qa-automate,false,qa,Create Mode,"Generate automated API and E2E tests for implemented code using the project's existing test framework (detects existing well known in use test frameworks). Use after implementation to add test coverage. NOT for code review or story validation - use CR for that.",implementation_artifacts,"test suite",
bmm,anytime,Set Project,SPJ,05,_bmad/bmm/workflows/0-context/set-project/workflow.md,bmad-set-project,false,bmad-master,Anytime,"Set or clear the current project context for monorepo support.",_bmad,.current_project,
bmm,4-implementation,Retrospective,ER,60,_bmad/bmm/workflows/4-implementation/retrospective/workflow.yaml,bmad-bmm-retrospective,false,sm,Create Mode,"Optional at epic end: Review completed work lessons learned and next epic or if major issues consider CC",implementation_artifacts,retrospective, bmm,4-implementation,Retrospective,ER,60,_bmad/bmm/workflows/4-implementation/retrospective/workflow.yaml,bmad-bmm-retrospective,false,sm,Create Mode,"Optional at epic end: Review completed work lessons learned and next epic or if major issues consider CC",implementation_artifacts,retrospective,

1 module phase name code sequence workflow-file command required agent options description output-location outputs
28 bmm 4-implementation Dev Story DS 40 _bmad/bmm/workflows/4-implementation/dev-story/workflow.yaml bmad-bmm-dev-story true dev Create Mode Story cycle: Execute story implementation tasks and tests then CR then back to DS if fixes needed
29 bmm 4-implementation Code Review CR 50 _bmad/bmm/workflows/4-implementation/code-review/workflow.yaml bmad-bmm-code-review false dev Create Mode Story cycle: If issues back to DS if approved then next CS or ER if epic complete
30 bmm 4-implementation QA Automation Test QA 45 _bmad/bmm/workflows/qa/automate/workflow.yaml bmad-bmm-qa-automate false qa Create Mode Generate automated API and E2E tests for implemented code using the project's existing test framework (detects existing well known in use test frameworks). Use after implementation to add test coverage. NOT for code review or story validation - use CR for that. implementation_artifacts test suite
31 bmm anytime Set Project SPJ 05 _bmad/bmm/workflows/0-context/set-project/workflow.md bmad-set-project false bmad-master Anytime Set or clear the current project context for monorepo support. _bmad .current_project
32 bmm 4-implementation Retrospective ER 60 _bmad/bmm/workflows/4-implementation/retrospective/workflow.yaml bmad-bmm-retrospective false sm Create Mode Optional at epic end: Review completed work lessons learned and next epic or if major issues consider CC implementation_artifacts retrospective

View File

@ -0,0 +1,28 @@
---
name: list-envs
description: List available project environments for monorepo support
main_config: '{project-root}/_bmad/bmm/config.yaml'
---
# List Project Environments
**Goal:** List the available project context environments for BMAD artifacts.
**Your Role:** Configuration Assistant.
## WORKFLOW ARCHITECTURE
### 1. Identify Environments
- Use your file listing/system capabilities to examine the `{project-root}/_bmad-output/` directory.
- Identify all subdirectories within this path. Each subdirectory represents an available environment, EXCEPT:
- Ignore hidden directories starting with `.`
- Ignore standard BMAD artifact directories: `planning-artifacts`, `implementation-artifacts`, `test-artifacts`, `knowledge`, `docs`, `assets`
- The root `_bmad-output/` directory itself represents the `default (root)` unset environment.
### 2. Output Results
1. Display a formatted numbered list of the existing environments you found.
2. Clearly indicate the `default (root)` environment (usually [0]).
3. Check if there is an active environment currently set. Read `{project-root}/{{bmadFolderName}}/.current_project`. If it exists, indicate which environment from the list is currently active (e.g. by adding `(ACTIVE)` next to the bullet point).
4. Inform the user that they can switch to another environment or create a new one using the `/set-project <env_name>` command.

View File

@ -0,0 +1,84 @@
---
name: set-project
description: Set the current project context for monorepo support
main_config: '{project-root}/_bmad/bmm/config.yaml'
---
# Set Project Context
**Goal:** Configure the active project path for BMAD artifacts.
**Your Role:** Configuration Assistant.
## WORKFLOW ARCHITECTURE
This is a single-step workflow that updates a local state file.
### 1. Configuration Loading
Load and read full config from {main_config} and resolve variables and artifact paths.
### 2. Context Management
1. **Analyze Request**: Determine the requested project name from the user's initial invocation (e.g., `/set-project my-app`).
2. **Wait for Input (If Missing)**: If the user did NOT provide a project name:
- Use your file listing capabilities to examine the `{project-root}/_bmad-output/` directory.
- Output: A formatted list of the existing environments (subdirectories) you found, explicitly noting the `default (root)` environment.
*(Exclude hidden directories and standard BMAD artifact folders like `planning-artifacts`, `implementation-artifacts`, `test-artifacts`, `knowledge`, `docs`, `assets`)*
- Present options in a numbered list format and ask the user to select by number or type a new project name:
```
Select a project environment:
[0] default (root) - Current location for standard artifacts
[1] project-name-1
[2] project-name-2
...
Enter a number to select, type a new project name, or enter 'CLEAR' to reset to root:
```
- **Wait for Input.**
3. **Process Input**: Once a project name is established:
- **Case: CLEAR**:
- Delete file: `{project-root}/{{bmadFolderName}}/.current_project`
- Output: "✅ Project context cleared. Artifacts will go to root `_bmad-output/`."
- **HALT**
- **Case: Numeric Selection**: If input is a number (0, 1, 2, etc.):
- Map the number to the corresponding environment from your earlier listing
- If number 0, treat as "CLEAR" case above
- If valid number but out of range, show error and ask again
- If valid selection, use that environment name as the path
- **Case: Path Provided** (text input):
- **1. Cleanup**: Remove leading/trailing slashes and any occurrences of `_bmad-output/`.
- **2. Validate Existence**: Check if `{project-root}/_bmad-output/<sanitized_path>` exists on the file system.
- **If it DOES NOT exist**:
- Ask: "The environment `<sanitized_path>` is not present. Do you want to create a new one? (Yes/No)"
- **Wait for Input.**
- **If No**: Inform the user to run `/list-envs` to see available environments or `/set-project` to try again. **HALT**.
- **If Yes**: Proceed to validation.
- **3. Validate - No Traversal**: Reject if path contains `..`.
- **4. Validate - No Absolute**: Reject if path starts with `/` or drive letter (e.g., `C:`).
- **5. Validate - Empty/Whitespace**: Reject if empty or only whitespace.
- **6. Validate - Whitelist**: Match against regex `^[a-zA-Z0-9._-/]+$`.
- **Check Results**:
- **If Invalid**:
- Output: "❌ Error: Invalid project context — must be a relative path and contain only alphanumeric characters, dots, dashes, underscores, or slashes. Traversal (..) is strictly forbidden."
- **HALT**
- **If Valid**:
- Write file: `{project-root}/{{bmadFolderName}}/.current_project` with content `<sanitized_path>`
- Output: "✅ Project context set to: `<sanitized_path>`. Artifacts will go to `_bmad-output/<sanitized_path>/`."
### 3. Verification
- Display the full resolved output path for confirmation.
## Inline Project Overrides
You can also temporarily run a command against a different project without changing the global context file. Use the `#project:NAME` or `#p:NAME` syntax in your command invocation.
**Examples:**
- `/create-prd #project:my-app`
- `/sprint-planning #p:admin-portal`
**Precedence:**
1. **Inline Override** (`#p:NAME`)
2. **Global Context File** (`{project-root}/_bmad/.current_project`)
3. **Default Config** (if neither is present)

View File

@ -1,6 +1,7 @@
--- ---
name: create-product-brief name: create-product-brief
description: Create comprehensive product briefs through collaborative step-by-step discovery as creative Business Analyst working with the user as peers. description: Create comprehensive product briefs through collaborative step-by-step discovery as creative Business Analyst working with the user as peers.
main_config: '{project-root}/_bmad/bmm/config.yaml'
--- ---
# Product Brief Workflow # Product Brief Workflow
@ -48,7 +49,7 @@ This uses **step-file architecture** for disciplined execution:
### 1. Configuration Loading ### 1. Configuration Loading
Load and read full config from {project-root}/_bmad/bmm/config.yaml and resolve: Load and read full config from {main_config} and resolve variables and artifact paths.
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`, `communication_language`, `document_output_language`, `user_skill_level` - `project_name`, `output_folder`, `planning_artifacts`, `user_name`, `communication_language`, `document_output_language`, `user_skill_level`

View File

@ -1,6 +1,7 @@
--- ---
name: domain-research name: domain-research
description: Conduct domain research covering industry analysis, regulations, technology trends, and ecosystem dynamics using current web data and verified sources. description: Conduct domain research covering industry analysis, regulations, technology trends, and ecosystem dynamics using current web data and verified sources.
main_config: '{project-root}/_bmad/bmm/config.yaml'
--- ---
# Domain Research Workflow # Domain Research Workflow
@ -15,7 +16,11 @@ description: Conduct domain research covering industry analysis, regulations, te
## CONFIGURATION ## CONFIGURATION
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: ### 1. Configuration Loading
Load and read full config from {main_config} and resolve variables and artifact paths.
- `project_name`, `output_folder`, `planning_artifacts`, `user_name` - `project_name`, `output_folder`, `planning_artifacts`, `user_name`
- `communication_language`, `document_output_language`, `user_skill_level` - `communication_language`, `document_output_language`, `user_skill_level`
- `date` as a system-generated value - `date` as a system-generated value

View File

@ -1,6 +1,7 @@
--- ---
name: market-research name: market-research
description: Conduct market research covering market size, growth, competition, and customer insights using current web data and verified sources. description: Conduct market research covering market size, growth, competition, and customer insights using current web data and verified sources.
main_config: '{project-root}/_bmad/bmm/config.yaml'
--- ---
# Market Research Workflow # Market Research Workflow
@ -15,7 +16,11 @@ description: Conduct market research covering market size, growth, competition,
## CONFIGURATION ## CONFIGURATION
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: ### 1. Configuration Loading
Load and read full config from {main_config} and resolve variables and artifact paths.
- `project_name`, `output_folder`, `planning_artifacts`, `user_name` - `project_name`, `output_folder`, `planning_artifacts`, `user_name`
- `communication_language`, `document_output_language`, `user_skill_level` - `communication_language`, `document_output_language`, `user_skill_level`
- `date` as a system-generated value - `date` as a system-generated value

View File

@ -1,6 +1,7 @@
--- ---
name: technical-research name: technical-research
description: Conduct technical research covering technology evaluation, architecture decisions, and implementation approaches using current web data and verified sources. description: Conduct technical research covering technology evaluation, architecture decisions, and implementation approaches using current web data and verified sources.
main_config: '{project-root}/_bmad/bmm/config.yaml'
--- ---
# Technical Research Workflow # Technical Research Workflow
@ -15,7 +16,11 @@ description: Conduct technical research covering technology evaluation, architec
## CONFIGURATION ## CONFIGURATION
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: ### 1. Configuration Loading
Load and read full config from {main_config} and resolve variables and artifact paths.
- `project_name`, `output_folder`, `planning_artifacts`, `user_name` - `project_name`, `output_folder`, `planning_artifacts`, `user_name`
- `communication_language`, `document_output_language`, `user_skill_level` - `communication_language`, `document_output_language`, `user_skill_level`
- `date` as a system-generated value - `date` as a system-generated value

View File

@ -46,10 +46,6 @@ This uses **step-file architecture** for disciplined execution:
## INITIALIZATION SEQUENCE ## INITIALIZATION SEQUENCE
### 1. Configuration Loading
Load and read full config from {main_config} and resolve:
- `project_name`, `output_folder`, `planning_artifacts`, `user_name` - `project_name`, `output_folder`, `planning_artifacts`, `user_name`
- `communication_language`, `document_output_language`, `user_skill_level` - `communication_language`, `document_output_language`, `user_skill_level`
- `date` as system-generated current datetime - `date` as system-generated current datetime

View File

@ -48,7 +48,7 @@ This uses **step-file architecture** for disciplined execution:
### 1. Configuration Loading ### 1. Configuration Loading
Load and read full config from {main_config} and resolve: Load and read full config from {main_config} and resolve variables and artifact paths.
- `project_name`, `output_folder`, `planning_artifacts`, `user_name` - `project_name`, `output_folder`, `planning_artifacts`, `user_name`
- `communication_language`, `document_output_language`, `user_skill_level` - `communication_language`, `document_output_language`, `user_skill_level`

View File

@ -48,7 +48,8 @@ This uses **step-file architecture** for disciplined execution:
### 1. Configuration Loading ### 1. Configuration Loading
Load and read full config from {main_config} and resolve: Load and read full config from {main_config} and resolve variables and artifact paths.
- `project_name`, `output_folder`, `planning_artifacts`, `user_name` - `project_name`, `output_folder`, `planning_artifacts`, `user_name`
- `communication_language`, `document_output_language`, `user_skill_level` - `communication_language`, `document_output_language`, `user_skill_level`

View File

@ -22,9 +22,10 @@ This uses **micro-file architecture** for disciplined execution:
## INITIALIZATION ## INITIALIZATION
### Configuration Loading ### 1. Configuration Loading
Load and read full config from {main_config} and resolve variables and artifact paths.
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
- `project_name`, `output_folder`, `planning_artifacts`, `user_name` - `project_name`, `output_folder`, `planning_artifacts`, `user_name`
- `communication_language`, `document_output_language`, `user_skill_level` - `communication_language`, `document_output_language`, `user_skill_level`

View File

@ -42,9 +42,9 @@ description: 'Critical validation workflow that assesses PRD, Architecture, and
## INITIALIZATION SEQUENCE ## INITIALIZATION SEQUENCE
### 1. Module Configuration Loading ### 1. Configuration Loading
Load and read full config from {project-root}/_bmad/bmm/config.yaml and resolve: Load and read full config from {main_config} and resolve variables and artifact paths.
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`, `communication_language`, `document_output_language` - `project_name`, `output_folder`, `planning_artifacts`, `user_name`, `communication_language`, `document_output_language`
- ✅ 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}`

View File

@ -25,7 +25,9 @@ This uses **micro-file architecture** for disciplined execution:
## INITIALIZATION ## INITIALIZATION
### Configuration Loading ### 1. Configuration Loading
Load and read full config from {main_config} and resolve variables and artifact paths.
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:

View File

@ -48,7 +48,8 @@ This uses **step-file architecture** for disciplined execution:
### 1. Configuration Loading ### 1. Configuration Loading
Load and read full config from {project-root}/_bmad/bmm/config.yaml and resolve: Load and read full config from {main_config} and resolve variables and artifact paths.
- `project_name`, `output_folder`, `planning_artifacts`, `user_name`, `communication_language`, `document_output_language` - `project_name`, `output_folder`, `planning_artifacts`, `user_name`, `communication_language`, `document_output_language`
- ✅ 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}`

View File

@ -16,6 +16,23 @@
<step n="1" goal="Load story and discover changes"> <step n="1" goal="Load story and discover changes">
<check if="{project-root}/_bmad/.current_project exists">
<action>Read content as project_suffix</action>
<!-- Security: Reject traversal, absolute paths, and invalid patterns -->
<check if="project_suffix is empty OR project_suffix contains '..' or starts with '/' or starts with '\'">
<output>🚫 Security Error: Invalid project context path detected — path traversal or absolute path detected.</output>
<action>HALT</action>
</check>
<!-- Whitelist: Alphanumeric, dots, dashes, underscores, AND slashes (for nested segments) -->
<check if="project_suffix matches regex '[^a-zA-Z0-9._-/]|^\s*$'">
<output>🚫 Error: Project context must only contain alphanumeric characters, dots, dashes, underscores, or slashes.</output>
<action>HALT</action>
</check>
<action>Override project_name to {project_suffix}</action>
<action>Override output_folder to {project-root}/_bmad-output/{project_suffix}</action>
</check>
<action>Use provided {{story_path}} or ask user which story file to review</action> <action>Use provided {{story_path}} or ask user which story file to review</action>
<action>Read COMPLETE story file</action> <action>Read COMPLETE story file</action>
<action>Set {{story_key}} = extracted key from filename (e.g., "1-2-user-authentication.md" → "1-2-user-authentication") or story <action>Set {{story_key}} = extracted key from filename (e.g., "1-2-user-authentication.md" → "1-2-user-authentication") or story
@ -41,6 +58,7 @@
<invoke-protocol name="discover_inputs" /> <invoke-protocol name="discover_inputs" />
<action>Load {project_context} for coding standards (if exists)</action> <action>Load {project_context} for coding standards (if exists)</action>
</step> </step>
<step n="2" goal="Build review attack plan"> <step n="2" goal="Build review attack plan">

View File

@ -40,7 +40,7 @@
- [x] Done - Item completed successfully - [x] Done - Item completed successfully
- [N/A] Skip - Item not applicable to this change - [N/A] Skip - Item not applicable to this change
- [!] Action-needed - Item requires attention or follow-up - [!] Action-needed - Item requires attention or follow-up
<action>Maintain running notes of findings and impacts discovered</action>
<action>Present checklist progress after each major section</action> <action>Present checklist progress after each major section</action>
<action if="checklist cannot be completed">Identify blocking issues and work with user to resolve before continuing</action> <action if="checklist cannot be completed">Identify blocking issues and work with user to resolve before continuing</action>

View File

@ -18,6 +18,7 @@
<critical>🎯 ZERO USER INTERVENTION: Process should be fully automated except for initial epic/story selection or missing documents</critical> <critical>🎯 ZERO USER INTERVENTION: Process should be fully automated except for initial epic/story selection or missing documents</critical>
<step n="1" goal="Determine target story"> <step n="1" goal="Determine target story">
<check if="{{story_path}} is provided by user or user provided the epic and story number such as 2-4 or 1.6 or epic 1 story 5"> <check if="{{story_path}} is provided by user or user provided the epic and story number such as 2-4 or 1.6 or epic 1 story 5">
<action>Parse user-provided story path: extract epic_num, story_num, story_title from format like "1-2-user-auth"</action> <action>Parse user-provided story path: extract epic_num, story_num, story_title from format like "1-2-user-auth"</action>
<action>Set {{epic_num}}, {{story_num}}, {{story_key}} from user input</action> <action>Set {{epic_num}}, {{story_num}}, {{story_key}} from user input</action>
@ -260,48 +261,52 @@
<step n="5" goal="Create comprehensive story file"> <step n="5" goal="Create comprehensive story file">
<critical>📝 CREATE ULTIMATE STORY FILE - The developer's master implementation guide!</critical> <critical>📝 CREATE ULTIMATE STORY FILE - The developer's master implementation guide!</critical>
<!-- Recompute output file path with correct output_folder and story_key -->
<action>Set {target_story_file} = {output_folder}/{{story_key}}.md</action>
<action>Output "Generating story file at: {target_story_file}"</action>
<action>Initialize from template.md: <action>Initialize from template.md:
{default_output_file}</action> {target_story_file}</action>
<template-output file="{default_output_file}">story_header</template-output> <template-output file="{target_story_file}">story_header</template-output>
<!-- Story foundation from epics analysis --> <!-- Story foundation from epics analysis -->
<template-output <template-output
file="{default_output_file}">story_requirements</template-output> file="{target_story_file}">story_requirements</template-output>
<!-- Developer context section - MOST IMPORTANT PART --> <!-- Developer context section - MOST IMPORTANT PART -->
<template-output file="{default_output_file}"> <template-output file="{target_story_file}">
developer_context_section</template-output> **DEV AGENT GUARDRAILS:** <template-output file="{default_output_file}"> developer_context_section</template-output> **DEV AGENT GUARDRAILS:** <template-output file="{target_story_file}">
technical_requirements</template-output> technical_requirements</template-output>
<template-output file="{default_output_file}">architecture_compliance</template-output> <template-output file="{target_story_file}">architecture_compliance</template-output>
<template-output <template-output
file="{default_output_file}">library_framework_requirements</template-output> file="{target_story_file}">library_framework_requirements</template-output>
<template-output file="{default_output_file}"> <template-output file="{target_story_file}">
file_structure_requirements</template-output> file_structure_requirements</template-output>
<template-output file="{default_output_file}">testing_requirements</template-output> <template-output file="{target_story_file}">testing_requirements</template-output>
<!-- Previous story intelligence --> <!-- Previous story intelligence -->
<check <check
if="previous story learnings available"> if="previous story learnings available">
<template-output file="{default_output_file}">previous_story_intelligence</template-output> <template-output file="{target_story_file}">previous_story_intelligence</template-output>
</check> </check>
<!-- Git intelligence --> <!-- Git intelligence -->
<check <check
if="git analysis completed"> if="git analysis completed">
<template-output file="{default_output_file}">git_intelligence_summary</template-output> <template-output file="{target_story_file}">git_intelligence_summary</template-output>
</check> </check>
<!-- Latest technical specifics --> <!-- Latest technical specifics -->
<check if="web research completed"> <check if="web research completed">
<template-output file="{default_output_file}">latest_tech_information</template-output> <template-output file="{target_story_file}">latest_tech_information</template-output>
</check> </check>
<!-- Project context reference --> <!-- Project context reference -->
<template-output <template-output
file="{default_output_file}">project_context_reference</template-output> file="{target_story_file}">project_context_reference</template-output>
<!-- Final status update --> <!-- Final status update -->
<template-output file="{default_output_file}"> <template-output file="{target_story_file}">
story_completion_status</template-output> story_completion_status</template-output>
<!-- CRITICAL: Set status to ready-for-dev --> <!-- CRITICAL: Set status to ready-for-dev -->

View File

@ -13,6 +13,7 @@
<critical>User skill level ({user_skill_level}) affects conversation style ONLY, not code updates.</critical> <critical>User skill level ({user_skill_level}) affects conversation style ONLY, not code updates.</critical>
<step n="1" goal="Find next ready story and load it" tag="sprint-status"> <step n="1" goal="Find next ready story and load it" tag="sprint-status">
<check if="{{story_path}} is provided"> <check if="{{story_path}} is provided">
<action>Use {{story_path}} directly</action> <action>Use {{story_path}} directly</action>
<action>Read COMPLETE story file</action> <action>Read COMPLETE story file</action>
@ -376,8 +377,6 @@
<action>Communicate to {user_name} that story implementation is complete and ready for review</action> <action>Communicate to {user_name} that story implementation is complete and ready for review</action>
<action>Summarize key accomplishments: story ID, story key, title, key changes made, tests added, files modified</action> <action>Summarize key accomplishments: story ID, story key, title, key changes made, tests added, files modified</action>
<action>Provide the story file path and current status (now "review")</action>
<action>Based on {user_skill_level}, ask if user needs any explanations about: <action>Based on {user_skill_level}, ask if user needs any explanations about:
- What was implemented and how it works - What was implemented and how it works
- Why certain technical decisions were made - Why certain technical decisions were made

View File

@ -1,7 +1,9 @@
# Retrospective - Epic Completion Review Instructions # Retrospective - Epic Completion Review Instructions
<critical>The workflow execution engine is governed by: {project-root}/_bmad/core/tasks/workflow.xml</critical> <critical>The workflow execution engine is governed by: {project-root}/_bmad/core/tasks/workflow.xml</critical>
<critical>You MUST have already loaded and processed: {project-root}/_bmad/bmm/workflows/4-implementation/retrospective/workflow.yaml</critical> <critical>You MUST have already loaded and processed: {installed_path}/workflow.yaml</critical>
<critical>Communicate all responses in {communication_language} and language MUST be tailored to {user_skill_level}</critical> <critical>Communicate all responses in {communication_language} and language MUST be tailored to {user_skill_level}</critical>
<critical>Generate all documents in {document_output_language}</critical> <critical>Generate all documents in {document_output_language}</critical>
<critical>⚠️ ABSOLUTELY NO TIME ESTIMATES - NEVER mention hours, days, weeks, months, or ANY time-based predictions. AI has fundamentally changed development speed - what once took teams weeks/months can now be done by one person in hours. DO NOT give ANY time estimates whatsoever.</critical> <critical>⚠️ ABSOLUTELY NO TIME ESTIMATES - NEVER mention hours, days, weeks, months, or ANY time-based predictions. AI has fundamentally changed development speed - what once took teams weeks/months can now be done by one person in hours. DO NOT give ANY time estimates whatsoever.</critical>

View File

@ -3,7 +3,9 @@
<critical>The workflow execution engine is governed by: {project-root}/_bmad/core/tasks/workflow.xml</critical> <critical>The workflow execution engine is governed by: {project-root}/_bmad/core/tasks/workflow.xml</critical>
<critical>You MUST have already loaded and processed: {project-root}/_bmad/bmm/workflows/4-implementation/sprint-planning/workflow.yaml</critical> <critical>You MUST have already loaded and processed: {project-root}/_bmad/bmm/workflows/4-implementation/sprint-planning/workflow.yaml</critical>
## 📚 Document Discovery - Full Epic Loading ## 📚 Document Discovery
- Full Epic Loading
**Strategy**: Sprint planning needs ALL epics and stories to build complete status tracking. **Strategy**: Sprint planning needs ALL epics and stories to build complete status tracking.

View File

@ -1,6 +1,7 @@
# Sprint Status - Multi-Mode Service # Sprint Status - Multi-Mode Service
<critical>The workflow execution engine is governed by: {project-root}/_bmad/core/tasks/workflow.xml</critical> <critical>The workflow execution engine is governed by: {project-root}/_bmad/core/tasks/workflow.xml</critical>
<critical>You MUST have already loaded and processed: {project-root}/_bmad/bmm/workflows/4-implementation/sprint-status/workflow.yaml</critical> <critical>You MUST have already loaded and processed: {project-root}/_bmad/bmm/workflows/4-implementation/sprint-status/workflow.yaml</critical>
<critical>Modes: interactive (default), validate, data</critical> <critical>Modes: interactive (default), validate, data</critical>
<critical>⚠️ ABSOLUTELY NO TIME ESTIMATES. Do NOT mention hours, days, weeks, or timelines.</critical> <critical>⚠️ ABSOLUTELY NO TIME ESTIMATES. Do NOT mention hours, days, weeks, or timelines.</critical>
@ -24,17 +25,26 @@
</step> </step>
<step n="1" goal="Locate sprint status file"> <step n="1" goal="Locate sprint status file">
<!-- Runtime Validation Gate -->
<check if="{sprint_status_file} is not defined OR {sprint_status_file} == ''">
<output>🚫 Error: Workflow configuration not loaded properly ({sprint_status_file} is undefined).</output>
<action>HALT</action>
</check>
<action>Load {project_context} for project-wide patterns and conventions (if exists)</action> <action>Load {project_context} for project-wide patterns and conventions (if exists)</action>
<action>Try {sprint_status_file}</action> <action>Try {sprint_status_file}</action>
<check if="file not found"> <check if="file not found">
<output>❌ sprint-status.yaml not found. <output>❌ sprint-status.yaml not found at: {sprint_status_file}
Run `/bmad:bmm:workflows:sprint-planning` to generate it, then rerun sprint-status.</output> Run `/bmad:bmm:workflows:sprint-planning` to generate it, then rerun sprint-status.</output>
<action>Exit workflow</action> <action>HALT</action>
</check> </check>
<action>Continue to Step 2</action> <action>Continue to Step 2</action>
</step> </step>
<step n="2" goal="Read and parse sprint-status.yaml"> <step n="2" goal="Read and parse sprint-status.yaml">
<check if="{sprint_status_file} is not defined">
<action>HALT - Safety Error: sprint_status_file variable lost or undefined.</action>
</check>
<action>Read the FULL file: {sprint_status_file}</action> <action>Read the FULL file: {sprint_status_file}</action>
<action>Parse fields: generated, project, project_key, tracking_system, story_location</action> <action>Parse fields: generated, project, project_key, tracking_system, story_location</action>
<action>Parse development_status map. Classify keys:</action> <action>Parse development_status map. Classify keys:</action>
@ -164,6 +174,9 @@ If the command targets a story, set `story_key={{next_story_id}}` when prompted.
<!-- ========================= --> <!-- ========================= -->
<step n="20" goal="Data mode output"> <step n="20" goal="Data mode output">
<check if="{sprint_status_file} is not defined">
<action>HALT - Safety Error: sprint_status_file variable lost or undefined.</action>
</check>
<action>Load and parse {sprint_status_file} same as Step 2</action> <action>Load and parse {sprint_status_file} same as Step 2</action>
<action>Compute recommendation same as Step 3</action> <action>Compute recommendation same as Step 3</action>
<template-output>next_workflow_id = {{next_workflow_id}}</template-output> <template-output>next_workflow_id = {{next_workflow_id}}</template-output>
@ -185,6 +198,9 @@ If the command targets a story, set `story_key={{next_story_id}}` when prompted.
<!-- ========================= --> <!-- ========================= -->
<step n="30" goal="Validate sprint-status file"> <step n="30" goal="Validate sprint-status file">
<check if="{sprint_status_file} is not defined">
<action>HALT - Safety Error: sprint_status_file variable lost or undefined.</action>
</check>
<action>Check that {sprint_status_file} exists</action> <action>Check that {sprint_status_file} exists</action>
<check if="missing"> <check if="missing">
<template-output>is_valid = false</template-output> <template-output>is_valid = false</template-output>

View File

@ -23,7 +23,9 @@ This uses **step-file architecture** for focused execution:
## INITIALIZATION ## INITIALIZATION
### Configuration Loading ### 1. Configuration Loading
Load and read full config from {main_config} and resolve variables and artifact paths.
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:

View File

@ -66,8 +66,9 @@ This uses **step-file architecture** for disciplined execution:
### 1. Configuration Loading ### 1. Configuration Loading
Load and read full config from `{main_config}` and resolve: Load and read full config from {main_config} and resolve variables and artifact paths.
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
- `project_name`, `planning_artifacts`, `implementation_artifacts`, `user_name` - `project_name`, `planning_artifacts`, `implementation_artifacts`, `user_name`
- `communication_language`, `document_output_language`, `user_skill_level` - `communication_language`, `document_output_language`, `user_skill_level`
- `date` as system-generated current datetime - `date` as system-generated current datetime

View File

@ -79,6 +79,11 @@
</step> </step>
## 1. Configuration Loading
Load and read full config from {main_config} and resolve variables and artifact paths.
<step n="3" goal="Check for existing documentation and determine workflow mode" if="resume_mode == false"> <step n="3" goal="Check for existing documentation and determine workflow mode" if="resume_mode == false">
<action>Check if {project_knowledge}/index.md exists</action> <action>Check if {project_knowledge}/index.md exists</action>

View File

@ -11,6 +11,36 @@
<action>Load existing project structure from index.md and project-parts.json (if exists)</action> <action>Load existing project structure from index.md and project-parts.json (if exists)</action>
<action>Load source tree analysis to understand available areas</action> <action>Load source tree analysis to understand available areas</action>
<!-- Step 1: Check for inline project override (#project:NAME or #p:NAME) -->
<action>Scan request for pattern #project:NAME or #p:NAME (case-insensitive)</action>
<check if="inline override found">
<action>Set project_suffix = extracted NAME</action>
</check>
<!-- Step 2: Fall back to .current_project file -->
<check if="project_suffix not yet set AND {project-root}/_bmad/.current_project exists">
<action>Read content as project_suffix</action>
</check>
<!-- Step 3: Validate and Canonicalize -->
<check if="project_suffix is set">
<!-- Security: Reject traversal, absolute paths, and invalid patterns -->
<check if="project_suffix is empty OR project_suffix contains '..' or starts with '/' or starts with '\'">
<output>🚫 Security Error: Invalid project context path detected — path traversal or absolute path detected.</output>
<action>HALT</action>
</check>
<!-- Whitelist: Alphanumeric, dots, dashes, underscores, AND slashes (for nested segments) -->
<check if="project_suffix matches regex '[^a-zA-Z0-9._-/]|^\s*$'">
<output>🚫 Error: Project context must only contain alphanumeric characters, dots, dashes, underscores, or slashes.</output>
<action>HALT</action>
</check>
<action>Override output_folder to {project-root}/_bmad-output/{project_suffix}</action>
<action>Override project_knowledge to {project-root}/_bmad-output/{project_suffix}</action>
<action>Output "Monorepo context detected. Writing deep-dive artifacts to: {project_knowledge}"</action>
</check>
<step n="13a" goal="Identify area for deep-dive"> <step n="13a" goal="Identify area for deep-dive">
<action>Analyze existing documentation to suggest deep-dive options</action> <action>Analyze existing documentation to suggest deep-dive options</action>
@ -250,8 +280,11 @@ Detailed exhaustive analysis of specific areas:
- Complete file inventory with all exports - Complete file inventory with all exports
- Dependency graph and data flow - Dependency graph and data flow
- Integration points and API contracts ### 1. Configuration Loading
- Testing analysis and coverage
Load and read full config from {main_config} and resolve variables and artifact paths.
- Related code and reuse opportunities - Related code and reuse opportunities
- Implementation guidance - Implementation guidance

View File

@ -95,6 +95,8 @@ Your choice [1/2/3]:
- Best for: Quick project overview, initial understanding - Best for: Quick project overview, initial understanding
- File reading: Minimal (configs, README, package.json, etc.) - File reading: Minimal (configs, README, package.json, etc.)
**2. Deep Scan** (10-30 minutes) **2. Deep Scan** (10-30 minutes)
- Reads files in critical directories based on project type - Reads files in critical directories based on project type

View File

@ -25,9 +25,10 @@ This uses **micro-file architecture** for disciplined execution:
## INITIALIZATION ## INITIALIZATION
### Configuration Loading ### 1. Configuration Loading
Load and read full config from {main_config} and resolve variables and artifact paths.
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
- `project_name`, `output_folder`, `user_name` - `project_name`, `output_folder`, `user_name`
- `communication_language`, `document_output_language`, `user_skill_level` - `communication_language`, `document_output_language`, `user_skill_level`

View File

@ -18,6 +18,7 @@ Check project for existing test framework:
- Search online for current recommended test framework for that stack - Search online for current recommended test framework for that stack
- Suggest the meta framework and use it (or ask user to confirm) - Suggest the meta framework and use it (or ask user to confirm)
### Step 1: Identify Features ### Step 1: Identify Features
Ask user what to test: Ask user what to test:

View File

@ -18,16 +18,23 @@
<flow> <flow>
<step n="1" title="Load and Initialize Workflow"> <step n="1" title="Load and Initialize Workflow">
<substep n="1a" title="Load Configuration and Resolve Variables"> <substep n="1a" title="Initialize Environment Variables">
<action>Resolve system variables (date:system-generated) and paths ({project-root}, {installed_path})</action>
</substep>
<substep n="1b" title="Load Configuration and Resolve Variables">
<action>Read workflow.yaml from provided path</action> <action>Read workflow.yaml from provided path</action>
<mandate>Load config_source (REQUIRED for all modules)</mandate> <mandate>Load config_source (REQUIRED for all modules)</mandate>
<phase n="1">Load external config from config_source path</phase> <phase n="1">Load external config from config_source path</phase>
<phase n="2">Resolve all {config_source}: references with values from config</phase> <phase n="2">Resolve all {config_source}: references with values from config</phase>
<phase n="3">Resolve system variables (date:system-generated) and paths ({project-root}, {installed_path})</phase> <phase n="3">Ask user for input of any variables that are still unknown</phase>
<phase n="4">Ask user for input of any variables that are still unknown</phase>
</substep> </substep>
<substep n="1b" title="Load Required Components"> <substep n="1c" title="Monorepo Context Enforcement">
{{monorepo_context_logic}}
</substep>
<substep n="1d" title="Load Required Components">
<mandate>Instructions: Read COMPLETE file from path OR embedded list (REQUIRED)</mandate> <mandate>Instructions: Read COMPLETE file from path OR embedded list (REQUIRED)</mandate>
<check>If template path → Read COMPLETE template file</check> <check>If template path → Read COMPLETE template file</check>
<check>If validation path → Note path for later loading when needed</check> <check>If validation path → Note path for later loading when needed</check>
@ -35,7 +42,7 @@
<note>Data files (csv, json) → Store paths only, load on-demand when instructions reference them</note> <note>Data files (csv, json) → Store paths only, load on-demand when instructions reference them</note>
</substep> </substep>
<substep n="1c" title="Initialize Output" if="template-workflow"> <substep n="1e" title="Initialize Output" if="template-workflow">
<action>Resolve default_output_file path with all variables and {{date}}</action> <action>Resolve default_output_file path with all variables and {{date}}</action>
<action>Create output directory if doesn't exist</action> <action>Create output directory if doesn't exist</action>
<action>If template-workflow → Write template to output file with placeholders</action> <action>If template-workflow → Write template to output file with placeholders</action>

View File

@ -20,6 +20,42 @@
<flow> <flow>
<step n="1" title="Method Registry Loading"> <step n="1" title="Method Registry Loading">
<!-- Retained inline check because this workflow may be invoked as a standalone tool mid-conversation, bypassing the OS-level context injection. -->
<!-- Step 1: Check for inline project override (#project:NAME or #p:NAME) -->
<action>Scan request for pattern #project:NAME or #p:NAME (case-insensitive)</action>
<check if="inline override found">
<action>Set project_suffix = extracted NAME</action>
</check>
<!-- Step 2: Fall back to .current_project file -->
<check if="project_suffix not yet set AND {project-root}/_bmad/.current_project exists">
<action>Read content as project_suffix</action>
</check>
<!-- Step 3: Validate and Canonicalize -->
<check if="project_suffix is set">
<!-- Security: Reject traversal, absolute paths, and invalid patterns -->
<check if="project_suffix is empty OR project_suffix contains '..' or starts with '/' or starts with '\'">
<output>🚫 Security Error: Invalid project context path detected — path traversal or absolute path detected.</output>
<action>HALT</action>
</check>
<!-- Whitelist: Alphanumeric, dots, dashes, underscores, AND slashes (for nested segments) -->
<check if="project_suffix matches regex '[^a-zA-Z0-9._-/]|^\s*$'">
<output>🚫 Error: Project context must only contain alphanumeric characters, dots, dashes, underscores, or slashes.</output>
<action>HALT</action>
</check>
<action>Override project_name to {project_suffix}</action>
<action>Override output_folder to {project-root}/_bmad-output/{project_suffix}</action>
<action>Override planning_artifacts to {project-root}/_bmad-output/{project_suffix}</action>
<action>Override implementation_artifacts to {project-root}/_bmad-output/{project_suffix}</action>
<action>Override project_knowledge to {project-root}/_bmad-output/{project_suffix}</action>
<action>Override sprint_status_file to {project-root}/_bmad-output/{project_suffix}/sprint-status.yaml</action>
<action>Output "Monorepo context detected. Paths adjusted to: {project_suffix}"</action>
</check>
<action>Load and read {{methods}} and {{agent-party}}</action> <action>Load and read {{methods}} and {{agent-party}}</action>
<csv-structure> <csv-structure>

View File

@ -32,9 +32,10 @@ This uses **micro-file architecture** for disciplined execution:
## INITIALIZATION ## INITIALIZATION
### Configuration Loading ### 1. Configuration Loading
Load and read full config from {main_config} and resolve variables and artifact paths.
Load config from `{project-root}/_bmad/core/config.yaml` and resolve:
- `project_name`, `output_folder`, `user_name` - `project_name`, `output_folder`, `user_name`
- `communication_language`, `document_output_language`, `user_skill_level` - `communication_language`, `document_output_language`, `user_skill_level`

View File

@ -25,9 +25,9 @@ This uses **micro-file architecture** with **sequential conversation orchestrati
## INITIALIZATION ## INITIALIZATION
### Configuration Loading ### 1. Configuration Loading
Load config from `{project-root}/_bmad/core/config.yaml` and resolve: Load and read full config from {main_config} and resolve variables and artifact paths.
- `project_name`, `output_folder`, `user_name` - `project_name`, `output_folder`, `user_name`
- `communication_language`, `document_output_language`, `user_skill_level` - `communication_language`, `document_output_language`, `user_skill_level`

View File

@ -0,0 +1,214 @@
/**
* Context Logic Integration Tests
*
* Validates the centralized monorepo context logic deduplication:
* 1. context-logic.js exports a valid XML block
* 2. All workflow templates that need it use the {{monorepo_context_logic}} placeholder
* 3. No stale hardcoded <monorepo-context-check> blocks exist in templates
* 4. src/core/tasks/workflow.xml uses the placeholder (not a hardcoded block)
* 5. All JS consumers correctly import context-logic.js
* 6. MONOREPO_CONTEXT_LOGIC string integrity (key fields are present)
*/
const fs = require('fs-extra');
const path = require('node:path');
// ANSI colors
const c = {
reset: '\u001B[0m',
green: '\u001B[32m',
red: '\u001B[31m',
yellow: '\u001B[33m',
cyan: '\u001B[36m',
dim: '\u001B[2m',
};
let passed = 0;
let failed = 0;
function ok(condition, testName, detail = '') {
if (condition) {
console.log(`${c.green}${c.reset} ${testName}`);
passed++;
} else {
console.log(`${c.red}${c.reset} ${testName}`);
if (detail) console.log(` ${c.dim}${detail}${c.reset}`);
failed++;
}
}
async function readFile(p) {
return fs.readFile(p, 'utf8');
}
async function exists(p) {
return fs.pathExists(p);
}
async function runTests() {
console.log(`${c.cyan}============================================================`);
console.log(' Context Logic Integration Tests');
console.log(`============================================================${c.reset}\n`);
const root = path.join(__dirname, '..');
const sharedDir = path.join(root, 'tools/cli/installers/lib/ide/shared');
const templatesDir = path.join(root, 'tools/cli/installers/lib/ide/templates');
const combinedDir = path.join(templatesDir, 'combined');
// ────────────────────────────────────────────────────────────
// Suite 1: context-logic.js module integrity
// ────────────────────────────────────────────────────────────
console.log(`${c.yellow}Suite 1: context-logic.js module integrity${c.reset}\n`);
const contextLogicPath = path.join(sharedDir, 'context-logic.js');
ok(await exists(contextLogicPath), 'context-logic.js file exists');
let MONOREPO_CONTEXT_LOGIC;
try {
const mod = require(contextLogicPath);
ok(typeof mod.MONOREPO_CONTEXT_LOGIC === 'string', 'exports MONOREPO_CONTEXT_LOGIC as a string');
ok(mod.MONOREPO_CONTEXT_LOGIC.length > 0, 'MONOREPO_CONTEXT_LOGIC is non-empty');
MONOREPO_CONTEXT_LOGIC = mod.MONOREPO_CONTEXT_LOGIC;
} catch (error) {
ok(false, 'context-logic.js is require()-able', error.message);
MONOREPO_CONTEXT_LOGIC = '';
}
// Key content checks
ok(MONOREPO_CONTEXT_LOGIC.includes('<monorepo-context-check'), 'has opening <monorepo-context-check> tag');
ok(MONOREPO_CONTEXT_LOGIC.includes('</monorepo-context-check>'), 'has closing </monorepo-context-check> tag');
ok(MONOREPO_CONTEXT_LOGIC.includes('#project:NAME'), 'documents #project:NAME syntax');
ok(MONOREPO_CONTEXT_LOGIC.includes('#p:NAME'), 'documents #p:NAME short alias');
ok(MONOREPO_CONTEXT_LOGIC.includes('.current_project'), 'includes .current_project fallback logic');
ok(MONOREPO_CONTEXT_LOGIC.includes('path traversal'), 'includes path traversal security check');
ok(MONOREPO_CONTEXT_LOGIC.includes('output_folder'), 'overrides output_folder path variable');
ok(MONOREPO_CONTEXT_LOGIC.includes('planning_artifacts'), 'overrides planning_artifacts path variable');
ok(MONOREPO_CONTEXT_LOGIC.includes('HALT'), 'halts on security violation');
console.log('');
// ────────────────────────────────────────────────────────────
// Suite 2: JS consumers import context-logic.js correctly
// ────────────────────────────────────────────────────────────
console.log(`${c.yellow}Suite 2: JS consumers import context-logic.js${c.reset}\n`);
const consumers = [
{
file: 'tools/cli/installers/lib/core/installer.js',
expectedImport: "require('../ide/shared/context-logic')",
},
{
file: 'tools/cli/installers/lib/ide/_config-driven.js',
expectedImport: "require('./shared/context-logic')",
},
{
file: 'tools/cli/installers/lib/ide/shared/workflow-command-generator.js',
expectedImport: "require('./context-logic')",
},
];
for (const { file, expectedImport } of consumers) {
const fullPath = path.join(root, file);
try {
const content = await readFile(fullPath);
ok(content.includes(expectedImport), `${path.basename(file)} imports context-logic correctly`);
ok(content.includes("replaceAll('{{monorepo_context_logic}}'"), `${path.basename(file)} uses replaceAll for placeholder`);
} catch (error) {
ok(false, `File not found or unreadable: ${fullPath} - ${error.message}`);
}
}
console.log('');
// ────────────────────────────────────────────────────────────
// Suite 3: Templates use placeholder, not hardcoded blocks
// ────────────────────────────────────────────────────────────
console.log(`${c.yellow}Suite 3: Templates use {{monorepo_context_logic}} placeholder${c.reset}\n`);
// These templates MUST have the placeholder (they are rendered directly as IDE workflow commands)
const mustHavePlaceholder = [
path.join(templatesDir, 'workflow-command-template.md'),
path.join(templatesDir, 'workflow-commander.md'),
path.join(combinedDir, 'antigravity.md'),
path.join(combinedDir, 'claude-workflow.md'),
path.join(combinedDir, 'claude-workflow-yaml.md'),
path.join(combinedDir, 'default-workflow.md'),
path.join(combinedDir, 'default-workflow-yaml.md'),
path.join(combinedDir, 'kiro-workflow.md'),
path.join(combinedDir, 'opencode-workflow.md'),
path.join(combinedDir, 'windsurf-workflow.md'),
];
for (const filePath of mustHavePlaceholder) {
const rel = path.relative(root, filePath);
try {
const content = await readFile(filePath);
ok(content.includes('{{monorepo_context_logic}}'), `${path.basename(filePath)} has {{monorepo_context_logic}} placeholder`);
// Must NOT have raw hardcoded block (only the shared module should have it)
ok(!content.includes('<monorepo-context-check'), `${path.basename(filePath)} has NO hardcoded <monorepo-context-check> block`);
} catch (error) {
ok(false, `File not found or unreadable: ${filePath} - ${error.message}`);
}
}
console.log('');
// ────────────────────────────────────────────────────────────
// Suite 4: No rogue hardcoded blocks anywhere in templates dir
// ────────────────────────────────────────────────────────────
console.log(`${c.yellow}Suite 4: No hardcoded blocks in templates directory${c.reset}\n`);
const walkDir = async (dir) => {
const entries = await fs.readdir(dir, { withFileTypes: true });
const files = [];
for (const e of entries) {
const full = path.join(dir, e.name);
if (e.isDirectory()) files.push(...(await walkDir(full)));
else if (e.isFile()) files.push(full);
}
return files;
};
const allTemplateFiles = await walkDir(templatesDir);
const rogueFiles = [];
for (const f of allTemplateFiles) {
const content = await readFile(f);
if (content.includes('<monorepo-context-check') && !f.includes('context-logic.js')) {
rogueFiles.push(path.relative(root, f));
}
}
ok(
rogueFiles.length === 0,
`No hardcoded <monorepo-context-check> blocks in templates (found ${rogueFiles.length})`,
rogueFiles.length > 0 ? `Rogue files: ${rogueFiles.join(', ')}` : '',
);
console.log('');
// ────────────────────────────────────────────────────────────
// Suite 5: src/core/tasks/workflow.xml uses placeholder
// ────────────────────────────────────────────────────────────
console.log(`${c.yellow}Suite 5: src/core/tasks/workflow.xml uses placeholder${c.reset}\n`);
const srcWorkflowXml = path.join(root, 'src/core/tasks/workflow.xml');
ok(await exists(srcWorkflowXml), 'src/core/tasks/workflow.xml exists');
const srcXmlContent = await readFile(srcWorkflowXml);
ok(srcXmlContent.includes('{{monorepo_context_logic}}'), 'workflow.xml (src) uses {{monorepo_context_logic}} placeholder');
ok(!srcXmlContent.includes('<monorepo-context-check'), 'workflow.xml (src) has NO hardcoded <monorepo-context-check> block');
// ────────────────────────────────────────────────────────────
// Results
// ────────────────────────────────────────────────────────────
console.log(`\n${c.cyan}============================================================`);
console.log(` Results: ${c.green}${passed} passed${c.reset}${c.cyan}, ${c.red}${failed} failed${c.reset}${c.cyan}`);
console.log(`============================================================${c.reset}\n`);
if (failed === 0) {
console.log(`${c.green}✨ All context-logic integration tests passed!${c.reset}\n`);
process.exit(0);
} else {
console.log(`${c.red}${failed} test(s) failed${c.reset}\n`);
process.exit(1);
}
}
runTests().catch((error) => {
console.error(error);
process.exit(1);
});

View File

@ -0,0 +1,145 @@
/**
* Monorepo Support Validation Tests
*
* Architecture after deduplication:
* - Monorepo context logic lives ONLY in context-logic.js
* - workflow.xml (src) uses {{monorepo_context_logic}} placeholder injected at install time
* - Individual source workflow files do NOT have inline checks (that's the deduplication!)
* - Only code-review/instructions.xml, dev-story/instructions.xml, create-story/instructions.xml
* and advanced-elicitation/workflow.xml are XML workflows checked; XML workflows that go through
* workflow.xml no longer need inline checks.
*
* Verifies:
* 1. The set-project workflow is correctly registered.
* 2. No source workflow file has a stale inline "Monorepo Context Check" block.
* 3. Only the canonical SINGLE source (context-logic.js) defines the check.
* 4. set-project implementation still manages .current_project.
*/
const fs = require('fs-extra');
const path = require('node:path');
const { globSync } = require('glob');
// ANSI colors
const colors = {
reset: '\u001B[0m',
green: '\u001B[32m',
red: '\u001B[31m',
yellow: '\u001B[33m',
cyan: '\u001B[36m',
dim: '\u001B[2m',
};
let passed = 0;
let failed = 0;
function assert(condition, testName, errorMessage = '') {
if (condition) {
console.log(`${colors.green}${colors.reset} ${testName}`);
passed++;
} else {
console.log(`${colors.red}${colors.reset} ${testName}`);
if (errorMessage) {
console.log(` ${colors.dim}${errorMessage}${colors.reset}`);
}
failed++;
}
}
async function runTests() {
console.log(`${colors.cyan}========================================`);
console.log('Monorepo Support Validation Tests');
console.log(`========================================${colors.reset}\n`);
const projectRoot = path.join(__dirname, '..');
// 1. Verify set-project registration
console.log(`${colors.yellow}Test Suite 1: Workflow Registration${colors.reset}\n`);
try {
const csvPath = path.join(projectRoot, 'src/bmm/module-help.csv');
const content = await fs.readFile(csvPath, 'utf8');
assert(content.includes('set-project'), 'set-project workflow is registered in module-help.csv');
} catch (error) {
assert(false, 'Registration check failed', error.message);
}
console.log('');
// 2. Verify NO stale inline "Monorepo Context Check" blocks in source workflow files
// These are redundant since workflow.xml now handles context injection via context-logic.js
console.log(`${colors.yellow}Test Suite 2: No Stale Inline Monorepo Context Checks${colors.reset}\n`);
console.log(` ${colors.dim}(Inline checks were moved to workflow.xml via context-logic.js)${colors.reset}\n`);
const workflowFiles = globSync('src/{core,bmm}/workflows/**/*.{md,xml}', { cwd: projectRoot });
const exceptions = [
'context-logic.js',
'code-review/instructions.xml',
'create-story/instructions.xml',
'dev-story/instructions.xml',
'advanced-elicitation/workflow.xml',
'deep-dive-instructions.md',
];
for (const file of workflowFiles) {
if (exceptions.some((e) => file.endsWith(e))) continue;
const content = await fs.readFile(path.join(projectRoot, file), 'utf8');
const hasMarkdownCheck = content.includes('**Monorepo Context Check:**');
const hasXmlCheck = /<check\s+if=.*_bmad\/\.current_project.*/.test(content);
assert(!hasMarkdownCheck && !hasXmlCheck, `No stale inline check block in: ${file}`);
}
console.log('');
// 3. Verify canonical source is context-logic.js (single source of truth)
console.log(`${colors.yellow}Test Suite 3: Single Source of Truth${colors.reset}\n`);
const contextLogicPath = path.join(projectRoot, 'tools/cli/installers/lib/ide/shared/context-logic.js');
assert(await fs.pathExists(contextLogicPath), 'context-logic.js exists as canonical source');
const srcWorkflowXml = path.join(projectRoot, 'src/core/tasks/workflow.xml');
const xmlContent = await fs.readFile(srcWorkflowXml, 'utf8');
assert(xmlContent.includes('{{monorepo_context_logic}}'), 'workflow.xml uses {{monorepo_context_logic}} placeholder');
assert(!xmlContent.includes('**Monorepo Context Check:**'), 'workflow.xml has no stale inline check');
console.log('');
// 4. Verify set-project implementation
console.log(`${colors.yellow}Test Suite 4: set-project Implementation${colors.reset}\n`);
try {
const setProjectPath = path.join(projectRoot, 'src/bmm/workflows/0-context/set-project/workflow.md');
const exists = await fs.pathExists(setProjectPath);
assert(exists, 'set-project workflow file exists');
if (exists) {
const content = await fs.readFile(setProjectPath, 'utf8');
assert(content.includes('{{bmadFolderName}}/.current_project'), 'set-project implementation manages .current_project');
const examplePattern = /(?:example|my[-_ ]?app|[a-z0-9]+-[a-z0-9]+)/i;
assert(examplePattern.test(content), 'set-project examples use generic public-friendly names');
}
} catch (error) {
assert(false, 'set-project check failed', error.message);
}
console.log('\n');
console.log(`${colors.cyan}========================================`);
console.log('Test Results:');
console.log(` Passed: ${colors.green}${passed}${colors.reset}`);
console.log(` Failed: ${colors.red}${failed}${colors.reset}`);
console.log(`========================================${colors.reset}\n`);
if (failed === 0) {
console.log(`${colors.green}✨ All monorepo validation tests passed!${colors.reset}\n`);
process.exit(0);
} else {
console.log(`${colors.red}❌ Some monorepo validation tests failed${colors.reset}\n`);
process.exit(1);
}
}
runTests().catch((error) => {
console.error(error);
process.exit(1);
});

View File

@ -16,6 +16,7 @@ const { IdeConfigManager } = require('./ide-config-manager');
const { CustomHandler } = require('../custom/handler'); const { CustomHandler } = require('../custom/handler');
const prompts = require('../../../lib/prompts'); const prompts = require('../../../lib/prompts');
const { BMAD_FOLDER_NAME } = require('../ide/shared/path-utils'); const { BMAD_FOLDER_NAME } = require('../ide/shared/path-utils');
const { MONOREPO_CONTEXT_LOGIC } = require('../ide/shared/context-logic');
class Installer { class Installer {
constructor() { constructor() {
@ -89,6 +90,17 @@ class Installer {
// Read the file content // Read the file content
let content = await fs.readFile(sourcePath, 'utf8'); let content = await fs.readFile(sourcePath, 'utf8');
// Apply replacements in an order that protects _bmad-output literals.
// 1. First, inject the monorepo logic (which now uses {{bmadFolderName}} for its config dir references).
content = content.replaceAll('{{monorepo_context_logic}}', MONOREPO_CONTEXT_LOGIC);
// 2. Perform a precise replacement of the generic '_bmad' folder name using a negative lookahead
// to avoid corrupting the fixed '_bmad-output' folder name.
content = content.replaceAll(/_bmad(?!-output)/g, this.bmadFolderName);
// 3. Finally, resolve the explicit placeholder used in centralized context logic.
content = content.replaceAll('{{bmadFolderName}}', this.bmadFolderName);
// Write to target with replaced content // Write to target with replaced content
await fs.ensureDir(path.dirname(targetPath)); await fs.ensureDir(path.dirname(targetPath));
await fs.writeFile(targetPath, content, 'utf8'); await fs.writeFile(targetPath, content, 'utf8');

View File

@ -391,17 +391,21 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}}
// No default // No default
} }
const { MONOREPO_CONTEXT_LOGIC } = require('./shared/context-logic');
let rendered = template let rendered = template
.replaceAll('{{name}}', artifact.name || '') .replaceAll('{{name}}', artifact.name || '')
.replaceAll('{{module}}', artifact.module || 'core') .replaceAll('{{module}}', artifact.module || 'core')
.replaceAll('{{path}}', pathToUse) .replaceAll('{{path}}', pathToUse)
.replaceAll('{{description}}', artifact.description || `${artifact.name} ${artifact.type || ''}`) .replaceAll('{{description}}', artifact.description || `${artifact.name} ${artifact.type || ''}`)
.replaceAll('{{workflow_path}}', pathToUse); .replaceAll('{{workflow_path}}', pathToUse)
.replaceAll('{{monorepo_context_logic}}', MONOREPO_CONTEXT_LOGIC);
// Replace _bmad placeholder with actual folder name // Replace _bmad placeholder with actual folder name using precise regex
rendered = rendered.replaceAll('_bmad', this.bmadFolderName); // This protects literals like '_bmad-output' from corruption.
rendered = rendered.replaceAll(/_bmad(?!-output)/g, this.bmadFolderName);
// Replace {{bmadFolderName}} placeholder if present // Replace {{bmadFolderName}} placeholder (used in centralized context logic)
rendered = rendered.replaceAll('{{bmadFolderName}}', this.bmadFolderName); rendered = rendered.replaceAll('{{bmadFolderName}}', this.bmadFolderName);
return rendered; return rendered;

View File

@ -437,9 +437,9 @@ tools: ${toolsStr}
- **Communication Language**: ${configVars.communication_language || '{{communication_language}}'} - **Communication Language**: ${configVars.communication_language || '{{communication_language}}'}
- **Document Output Language**: ${configVars.document_output_language || '{{document_output_language}}'} - **Document Output Language**: ${configVars.document_output_language || '{{document_output_language}}'}
- **User Skill Level**: ${configVars.user_skill_level || '{{user_skill_level}}'} - **User Skill Level**: ${configVars.user_skill_level || '{{user_skill_level}}'}
- **Output Folder**: ${configVars.output_folder || '{{output_folder}}'} - **Output Folder**: ${configVars.output_folder || '{{output_folder}}'}/{context} (Dynamic)
- **Planning Artifacts**: ${configVars.planning_artifacts || '{{planning_artifacts}}'} - **Planning Artifacts**: ${configVars.planning_artifacts || '{{planning_artifacts}}'}/{context} (Dynamic)
- **Implementation Artifacts**: ${configVars.implementation_artifacts || '{{implementation_artifacts}}'} - **Implementation Artifacts**: ${configVars.implementation_artifacts || '{{implementation_artifacts}}'}/{context} (Dynamic)
- **Project Knowledge**: ${configVars.project_knowledge || '{{project_knowledge}}'} - **Project Knowledge**: ${configVars.project_knowledge || '{{project_knowledge}}'}
## BMAD Runtime Structure ## BMAD Runtime Structure

View File

@ -0,0 +1,51 @@
/**
* Monorepo Context Logic XML Block
*
* robust, secure, and centralized logic for handling:
* 1. Inline project overrides (#p:NAME)
* 2. .current_project file fallback
* 3. Path variable overrides
*/
const MONOREPO_CONTEXT_LOGIC = `
<monorepo-context-check CRITICAL="TRUE" priority="before-config">
<!-- Step 1: Check for inline project override in user invocation -->
<!-- Supported syntax: #project:NAME (full) or #p:NAME (short alias) -->
<action>Scan user's invocation message for pattern #project:NAME or #p:NAME (case-insensitive)</action>
<check if="inline override found">
<action>Set project_suffix = extracted NAME</action>
<output>🎯 Inline project override: {project_suffix}</output>
</check>
<!-- Step 2: Fall back to .current_project file -->
<check if="project_suffix not yet set AND {project-root}/{{bmadFolderName}}/.current_project exists">
<action>Read {project-root}/{{bmadFolderName}}/.current_project as project_suffix</action>
</check>
<!-- Step 3: Validate -->
<check if="project_suffix is set">
<action>Trim whitespace and newlines from project_suffix</action>
<!-- Security: Reject traversal, absolute paths, and invalid patterns -->
<check if="project_suffix is empty OR project_suffix contains '..' OR starts with '/' OR starts with '\\\\'">
<output>🚫 Security Error: Invalid project context path traversal or absolute path detected.</output>
<action>HALT</action>
</check>
<!-- Whitelist: Alphanumeric, dots, dashes, underscores, AND slashes (for nested segments) -->
<check if="project_suffix matches regex '[^a-zA-Z0-9._-/]|^\\\\s*$'">
<output>🚫 Error: project_suffix must only contain alphanumeric characters, dots, dashes, underscores, or slashes.</output>
<action>HALT</action>
</check>
<!-- Step 4: Override path and identification variables -->
<action>Override project_name = {project_suffix}</action>
<action>Override output_folder = {project-root}/_bmad-output/{project_suffix}</action>
<action>Override planning_artifacts = {output_folder}/planning-artifacts</action>
<action>Override implementation_artifacts = {output_folder}/implementation-artifacts</action>
<action>Override project_knowledge = {output_folder}/knowledge</action>
<action>Override sprint_status_file = {output_folder}/sprint-status.yaml</action>
<output>🗂 Monorepo context: {project_suffix} outputs to {output_folder}</output>
</check>
</monorepo-context-check>
`;
module.exports = { MONOREPO_CONTEXT_LOGIC };

View File

@ -151,13 +151,22 @@ class WorkflowCommandGenerator {
} }
} }
const { MONOREPO_CONTEXT_LOGIC } = require('./context-logic');
// Replace template variables // Replace template variables
return template return (
.replaceAll('{{name}}', workflow.name) template
.replaceAll('{{module}}', workflow.module) .replaceAll('{{name}}', workflow.name)
.replaceAll('{{description}}', workflow.description) .replaceAll('{{module}}', workflow.module)
.replaceAll('{{workflow_path}}', workflowPath) .replaceAll('{{description}}', workflow.description)
.replaceAll('_bmad', this.bmadFolderName); .replaceAll('{{workflow_path}}', workflowPath)
.replaceAll('{{monorepo_context_logic}}', MONOREPO_CONTEXT_LOGIC)
// Replace _bmad placeholder with actual folder name using precise regex
// This protects literals like '_bmad-output' from corruption.
.replaceAll(/_bmad(?!-output)/g, this.bmadFolderName)
// Replace {{bmadFolderName}} placeholder (used in centralized context logic)
.replaceAll('{{bmadFolderName}}', this.bmadFolderName)
);
} }
/** /**

View File

@ -3,6 +3,8 @@ name: '{{name}}'
description: '{{description}}' description: '{{description}}'
--- ---
{{monorepo_context_logic}}
Read the entire workflow file at: {project-root}/_bmad/{{workflow_path}} Read the entire workflow file at: {project-root}/_bmad/{{workflow_path}}
Follow all instructions in the workflow file exactly as written. Follow all instructions in the workflow file exactly as written.

View File

@ -6,6 +6,8 @@ disable-model-invocation: true
IT IS CRITICAL THAT YOU FOLLOW THESE STEPS - while staying in character as the current agent persona you may have loaded: IT IS CRITICAL THAT YOU FOLLOW THESE STEPS - while staying in character as the current agent persona you may have loaded:
{{monorepo_context_logic}}
<steps CRITICAL="TRUE"> <steps CRITICAL="TRUE">
1. Always LOAD the FULL @{project-root}/{{bmadFolderName}}/core/tasks/workflow.xml 1. Always LOAD the FULL @{project-root}/{{bmadFolderName}}/core/tasks/workflow.xml
2. READ its entire contents - this is the CORE OS for EXECUTING the specific workflow-config @{project-root}/{{bmadFolderName}}/{{path}} 2. READ its entire contents - this is the CORE OS for EXECUTING the specific workflow-config @{project-root}/{{bmadFolderName}}/{{path}}

View File

@ -4,4 +4,6 @@ description: '{{description}}'
disable-model-invocation: true disable-model-invocation: true
--- ---
{{monorepo_context_logic}}
IT IS CRITICAL THAT YOU FOLLOW THIS COMMAND: LOAD the FULL @{project-root}/{{bmadFolderName}}/{{path}}, READ its entire contents and follow its directions exactly! IT IS CRITICAL THAT YOU FOLLOW THIS COMMAND: LOAD the FULL @{project-root}/{{bmadFolderName}}/{{path}}, READ its entire contents and follow its directions exactly!

View File

@ -4,4 +4,6 @@ inclusion: manual
# {{name}} # {{name}}
{{monorepo_context_logic}}
IT IS CRITICAL THAT YOU FOLLOW THIS COMMAND: LOAD the FULL #[[file:{{bmadFolderName}}/{{path}}]], READ its entire contents and follow its directions exactly! IT IS CRITICAL THAT YOU FOLLOW THIS COMMAND: LOAD the FULL #[[file:{{bmadFolderName}}/{{path}}]], READ its entire contents and follow its directions exactly!

View File

@ -3,6 +3,8 @@ name: '{{name}}'
description: '{{description}}' description: '{{description}}'
--- ---
{{monorepo_context_logic}}
Execute the BMAD '{{name}}' workflow. Execute the BMAD '{{name}}' workflow.
CRITICAL: You must load and follow the workflow definition exactly. CRITICAL: You must load and follow the workflow definition exactly.

View File

@ -5,6 +5,8 @@ auto_execution_mode: "iterate"
# {{name}} # {{name}}
{{monorepo_context_logic}}
Read the entire workflow file at {project-root}/_bmad/{{workflow_path}} Read the entire workflow file at {project-root}/_bmad/{{workflow_path}}
Follow all instructions in the workflow file exactly as written. Follow all instructions in the workflow file exactly as written.

View File

@ -3,6 +3,8 @@ description: '{{description}}'
disable-model-invocation: true disable-model-invocation: true
--- ---
{{monorepo_context_logic}}
IT IS CRITICAL THAT YOU FOLLOW THESE STEPS - while staying in character as the current agent persona you may have loaded: IT IS CRITICAL THAT YOU FOLLOW THESE STEPS - while staying in character as the current agent persona you may have loaded:
<steps CRITICAL="TRUE"> <steps CRITICAL="TRUE">

View File

@ -3,4 +3,6 @@ description: '{{description}}'
disable-model-invocation: true disable-model-invocation: true
--- ---
{{monorepo_context_logic}}
IT IS CRITICAL THAT YOU FOLLOW THIS COMMAND: LOAD the FULL @{{workflow_path}}, READ its entire contents and follow its directions exactly! IT IS CRITICAL THAT YOU FOLLOW THIS COMMAND: LOAD the FULL @{{workflow_path}}, READ its entire contents and follow its directions exactly!