From 3e35057b892869a8e7b29e6b432fbccdb779e87c Mon Sep 17 00:00:00 2001 From: Alex Verkhovsky Date: Tue, 10 Feb 2026 17:02:23 -0700 Subject: [PATCH 01/17] fix: auto-discover PRD in validate-prd instead of always asking (#1619) When only one PRD exists in planning_artifacts, use it automatically instead of prompting the user for its path. Still asks when multiple PRDs are found or falls back to manual input when none are discovered. Co-authored-by: Claude Opus 4.6 --- .../create-prd/steps-v/step-v-01-discovery.md | 18 +++++++++++++----- .../create-prd/workflow-validate-prd.md | 2 -- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md b/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md index b79e12fe0..6c591c2dd 100644 --- a/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md +++ b/src/bmm/workflows/2-plan-workflows/create-prd/steps-v/step-v-01-discovery.md @@ -70,14 +70,22 @@ This file contains the BMAD PRD philosophy, standards, and validation criteria t **If PRD path provided as invocation parameter:** - Use provided path -**If no PRD path provided:** -"**PRD Validation Workflow** +**If no PRD path provided, auto-discover:** +- Search `{planning_artifacts}` for files matching `*prd*.md` +- Also check for sharded PRDs: `{planning_artifacts}/*prd*/*.md` -Which PRD would you like to validate? +**If exactly ONE PRD found:** +- Use it automatically +- Inform user: "Found PRD: {discovered_path} — using it for validation." -Please provide the path to the PRD file you want to validate." +**If MULTIPLE PRDs found:** +- List all discovered PRDs with numbered options +- "I found multiple PRDs. Which one would you like to validate?" +- Wait for user selection -**Wait for user to provide PRD path.** +**If NO PRDs found:** +- "I couldn't find any PRD files in {planning_artifacts}. Please provide the path to the PRD file you want to validate." +- Wait for user to provide PRD path. ### 3. Validate PRD Exists and Load diff --git a/src/bmm/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md b/src/bmm/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md index 67a1aafc8..e21745139 100644 --- a/src/bmm/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md +++ b/src/bmm/workflows/2-plan-workflows/create-prd/workflow-validate-prd.md @@ -60,6 +60,4 @@ Load and read full config from {main_config} and resolve: "**Validate Mode: Validating an existing PRD against BMAD standards.**" -Prompt for PRD path: "Which PRD would you like to validate? Please provide the path to the PRD.md file." - Then read fully and follow: `{validateWorkflow}` (steps-v/step-v-01-discovery.md) From b4d118c897690029dc24062094d63964e3e2bfc8 Mon Sep 17 00:00:00 2001 From: Alex Verkhovsky Date: Wed, 11 Feb 2026 09:59:18 -0700 Subject: [PATCH 02/17] fix: remove output_folder/story_dir aliases, flatten variables sections (#1608) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: remove output_folder/story_dir aliases, flatten variables sections (#1602) Drop pointless alias variables (output_folder, story_dir, story_directory) from Phase 4, Quick Flow, and QA workflows. Replace all references with the canonical {implementation_artifacts} or {planning_artifacts} variables. Also flatten unnecessary `variables:` YAML nesting in all affected workflow.yaml files — the workflow engine treats all keys as top-level, so the nesting added complexity with no semantic value. Co-Authored-By: Claude Opus 4.6 * fix: add missing config declarations, remove remaining aliases and dead variables - Add missing document_output_language and user_skill_level to create-story (referenced in instructions.xml but never declared) - Remove retrospectives_folder alias, replace with canonical implementation_artifacts - Remove unused sprint_status and duplicate validation alias from correct-course - Remove unused date, planning_artifacts, tracking_system from sprint-status Co-Authored-By: Claude Opus 4.6 * fix: address PR review findings and rename shadowed output_folder variable - Fix single/double brace mismatch for {implementation_artifacts} in create-story instructions.xml (F1) - Remove escaped asterisks in glob patterns in retrospective instructions.md (F2) - Eliminate redundant {config_source} re-resolution for story_location in sprint-planning workflow.yaml (F5) - Add explicit instruction to discover previous_story_num by scanning artifacts instead of leaving it undefined (#7) - Rename output_folder to project_knowledge in document-project workflows to stop shadowing the canonical core config variable (#13) Co-Authored-By: Claude Opus 4.6 * fix: use plural retrospectives in previous retro search instructions The glob pattern can match multiple retrospective files for the same epic (e.g., partial mid-sprint retro and full completion retro). Use plural "retrospectives" to make clear the LLM should load all matches. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- .../code-review/workflow.yaml | 6 +--- .../correct-course/workflow.yaml | 3 -- .../create-story/checklist.md | 4 +-- .../create-story/instructions.xml | 3 +- .../create-story/workflow.yaml | 22 ++++++------- .../dev-story/instructions.xml | 4 +-- .../4-implementation/dev-story/workflow.yaml | 2 -- .../retrospective/instructions.md | 26 +++++++-------- .../retrospective/workflow.yaml | 3 -- .../sprint-planning/workflow.yaml | 32 ++++++++----------- .../sprint-status/workflow.yaml | 8 +---- .../bmad-quick-flow/quick-dev/workflow.md | 2 +- .../quick-spec/steps/step-01-understand.md | 2 +- .../bmad-quick-flow/quick-spec/workflow.md | 2 +- .../document-project/instructions.md | 12 +++---- .../templates/project-scan-report-schema.json | 4 +-- .../workflows/document-project/workflow.yaml | 2 +- .../workflows/deep-dive-instructions.md | 8 ++--- .../document-project/workflows/deep-dive.yaml | 2 +- .../workflows/full-scan-instructions.md | 26 +++++++-------- .../document-project/workflows/full-scan.yaml | 2 +- src/bmm/workflows/qa/automate/workflow.yaml | 7 ++-- 22 files changed, 77 insertions(+), 105 deletions(-) diff --git a/src/bmm/workflows/4-implementation/code-review/workflow.yaml b/src/bmm/workflows/4-implementation/code-review/workflow.yaml index 5b5f6b2fc..c6edf8464 100644 --- a/src/bmm/workflows/4-implementation/code-review/workflow.yaml +++ b/src/bmm/workflows/4-implementation/code-review/workflow.yaml @@ -12,7 +12,6 @@ document_output_language: "{config_source}:document_output_language" date: system-generated planning_artifacts: "{config_source}:planning_artifacts" implementation_artifacts: "{config_source}:implementation_artifacts" -output_folder: "{implementation_artifacts}" sprint_status: "{implementation_artifacts}/sprint-status.yaml" # Workflow components @@ -21,10 +20,7 @@ instructions: "{installed_path}/instructions.xml" validation: "{installed_path}/checklist.md" template: false -variables: - # Project context - project_context: "**/project-context.md" - story_dir: "{implementation_artifacts}" +project_context: "**/project-context.md" # Smart input file references - handles both whole docs and sharded docs # Priority: Whole document first, then sharded version diff --git a/src/bmm/workflows/4-implementation/correct-course/workflow.yaml b/src/bmm/workflows/4-implementation/correct-course/workflow.yaml index ea213e6db..6eb4b7f03 100644 --- a/src/bmm/workflows/4-implementation/correct-course/workflow.yaml +++ b/src/bmm/workflows/4-implementation/correct-course/workflow.yaml @@ -12,8 +12,6 @@ date: system-generated implementation_artifacts: "{config_source}:implementation_artifacts" planning_artifacts: "{config_source}:planning_artifacts" project_knowledge: "{config_source}:project_knowledge" -output_folder: "{implementation_artifacts}" -sprint_status: "{implementation_artifacts}/sprint-status.yaml" project_context: "**/project-context.md" # Smart input file references - handles both whole docs and sharded docs @@ -52,6 +50,5 @@ input_file_patterns: installed_path: "{project-root}/_bmad/bmm/workflows/4-implementation/correct-course" template: false instructions: "{installed_path}/instructions.md" -validation: "{installed_path}/checklist.md" checklist: "{installed_path}/checklist.md" default_output_file: "{planning_artifacts}/sprint-change-proposal-{date}.md" diff --git a/src/bmm/workflows/4-implementation/create-story/checklist.md b/src/bmm/workflows/4-implementation/create-story/checklist.md index 55e6c397e..6fc678994 100644 --- a/src/bmm/workflows/4-implementation/create-story/checklist.md +++ b/src/bmm/workflows/4-implementation/create-story/checklist.md @@ -49,7 +49,7 @@ This is a COMPETITION to create the **ULTIMATE story context** that makes LLM de ### **Required Inputs:** - **Story file**: The story file to review and improve -- **Workflow variables**: From workflow.yaml (story_dir, output_folder, epics_file, etc.) +- **Workflow variables**: From workflow.yaml (implementation_artifacts, epics_file, etc.) - **Source documents**: Epics, architecture, etc. (discovered or provided) - **Validation framework**: `validate-workflow.xml` (handles checklist execution) @@ -65,7 +65,7 @@ You will systematically re-do the entire story creation process, but with a crit 2. **Load the story file**: `{story_file_path}` (provided by user or discovered) 3. **Load validation framework**: `{project-root}/_bmad/core/tasks/validate-workflow.xml` 4. **Extract metadata**: epic_num, story_num, story_key, story_title from story file -5. **Resolve all workflow variables**: story_dir, output_folder, epics_file, architecture_file, etc. +5. **Resolve all workflow variables**: implementation_artifacts, epics_file, architecture_file, etc. 6. **Understand current status**: What story implementation guidance is currently provided? **Note:** If running in fresh context, user should provide the story file path being reviewed. If running from create-story workflow, the validation framework will automatically discover the checklist and story file. diff --git a/src/bmm/workflows/4-implementation/create-story/instructions.xml b/src/bmm/workflows/4-implementation/create-story/instructions.xml index 81eb82269..f9433371f 100644 --- a/src/bmm/workflows/4-implementation/create-story/instructions.xml +++ b/src/bmm/workflows/4-implementation/create-story/instructions.xml @@ -192,7 +192,8 @@ (As a, I want, so that) - Detailed acceptance criteria (already BDD formatted) - Technical requirements specific to this story - Business context and value - Success criteria - Load previous story file: {{story_dir}}/{{epic_num}}-{{previous_story_num}}-*.md **PREVIOUS STORY INTELLIGENCE:** - + Find {{previous_story_num}}: scan {implementation_artifacts} for the story file in epic {{epic_num}} with the highest story number less than {{story_num}} + Load previous story file: {implementation_artifacts}/{{epic_num}}-{{previous_story_num}}-*.md **PREVIOUS STORY INTELLIGENCE:** - Dev notes and learnings from previous story - Review feedback and corrections needed - Files that were created/modified and their patterns - Testing approaches that worked/didn't work - Problems encountered and solutions found - Code patterns established Extract all learnings that could impact current story implementation diff --git a/src/bmm/workflows/4-implementation/create-story/workflow.yaml b/src/bmm/workflows/4-implementation/create-story/workflow.yaml index 1f3ac9784..991f78c2e 100644 --- a/src/bmm/workflows/4-implementation/create-story/workflow.yaml +++ b/src/bmm/workflows/4-implementation/create-story/workflow.yaml @@ -6,11 +6,11 @@ author: "BMad" config_source: "{project-root}/_bmad/bmm/config.yaml" user_name: "{config_source}:user_name" communication_language: "{config_source}:communication_language" +document_output_language: "{config_source}:document_output_language" +user_skill_level: "{config_source}:user_skill_level" date: system-generated planning_artifacts: "{config_source}:planning_artifacts" implementation_artifacts: "{config_source}:implementation_artifacts" -output_folder: "{implementation_artifacts}" -story_dir: "{implementation_artifacts}" # Workflow components installed_path: "{project-root}/_bmad/bmm/workflows/4-implementation/create-story" @@ -19,18 +19,14 @@ instructions: "{installed_path}/instructions.xml" validation: "{installed_path}/checklist.md" # Variables and inputs -variables: - sprint_status: "{implementation_artifacts}/sprint-status.yaml" # Primary source for story tracking - epics_file: "{planning_artifacts}/epics.md" # Enhanced epics+stories with BDD and source hints - prd_file: "{planning_artifacts}/prd.md" # Fallback for requirements (if not in epics file) - architecture_file: "{planning_artifacts}/architecture.md" # Fallback for constraints (if not in epics file) - ux_file: "{planning_artifacts}/*ux*.md" # Fallback for UX requirements (if not in epics file) - story_title: "" # Will be elicited if not derivable - -# Project context +sprint_status: "{implementation_artifacts}/sprint-status.yaml" # Primary source for story tracking +epics_file: "{planning_artifacts}/epics.md" # Enhanced epics+stories with BDD and source hints +prd_file: "{planning_artifacts}/prd.md" # Fallback for requirements (if not in epics file) +architecture_file: "{planning_artifacts}/architecture.md" # Fallback for constraints (if not in epics file) +ux_file: "{planning_artifacts}/*ux*.md" # Fallback for UX requirements (if not in epics file) +story_title: "" # Will be elicited if not derivable project_context: "**/project-context.md" - -default_output_file: "{story_dir}/{{story_key}}.md" +default_output_file: "{implementation_artifacts}/{{story_key}}.md" # Smart input file references - Simplified for enhanced approach # The epics+stories file should contain everything needed with source hints diff --git a/src/bmm/workflows/4-implementation/dev-story/instructions.xml b/src/bmm/workflows/4-implementation/dev-story/instructions.xml index 6150944f1..3c4989f39 100644 --- a/src/bmm/workflows/4-implementation/dev-story/instructions.xml +++ b/src/bmm/workflows/4-implementation/dev-story/instructions.xml @@ -78,7 +78,7 @@ - Search {story_dir} for stories directly + Search {implementation_artifacts} for stories directly Find stories with "ready-for-dev" status in files Look for story files matching pattern: *-*-*.md Read each candidate story file to check Status section @@ -114,7 +114,7 @@ Store the found story_key (e.g., "1-2-user-authentication") for later status updates - Find matching story file in {story_dir} using story_key pattern: {{story_key}}.md + Find matching story file in {implementation_artifacts} using story_key pattern: {{story_key}}.md Read COMPLETE story file from discovered path diff --git a/src/bmm/workflows/4-implementation/dev-story/workflow.yaml b/src/bmm/workflows/4-implementation/dev-story/workflow.yaml index daf152b71..c8a85a079 100644 --- a/src/bmm/workflows/4-implementation/dev-story/workflow.yaml +++ b/src/bmm/workflows/4-implementation/dev-story/workflow.yaml @@ -4,12 +4,10 @@ author: "BMad" # Critical variables from config config_source: "{project-root}/_bmad/bmm/config.yaml" -output_folder: "{config_source}:output_folder" user_name: "{config_source}:user_name" communication_language: "{config_source}:communication_language" user_skill_level: "{config_source}:user_skill_level" document_output_language: "{config_source}:document_output_language" -story_dir: "{config_source}:implementation_artifacts" date: system-generated # Workflow components diff --git a/src/bmm/workflows/4-implementation/retrospective/instructions.md b/src/bmm/workflows/4-implementation/retrospective/instructions.md index d76383852..018ef6ee3 100644 --- a/src/bmm/workflows/4-implementation/retrospective/instructions.md +++ b/src/bmm/workflows/4-implementation/retrospective/instructions.md @@ -81,7 +81,7 @@ Bob (Scrum Master): "I'm having trouble detecting the completed epic from {sprin PRIORITY 3: Fallback to stories folder -Scan {story_directory} for highest numbered story files +Scan {implementation_artifacts} for highest numbered story files Extract epic numbers from story filenames (pattern: epic-X-Y-story-name.md) Set {{detected_epic}} = highest epic number found @@ -171,7 +171,7 @@ Bob (Scrum Master): "Before we start the team discussion, let me review all the Charlie (Senior Dev): "Good idea - those dev notes always have gold in them." -For each story in epic {{epic_number}}, read the complete story file from {story_directory}/{{epic_number}}-{{story_num}}-\*.md +For each story in epic {{epic_number}}, read the complete story file from {implementation_artifacts}/{{epic_number}}-{{story_num}}-*.md Extract and analyze from each story: @@ -262,14 +262,14 @@ Bob (Scrum Master): "We'll get to all of it. But first, let me load the previous Calculate previous epic number: {{prev_epic_num}} = {{epic_number}} - 1 - Search for previous retrospective using pattern: {retrospectives_folder}/epic-{{prev_epic_num}}-retro-*.md + Search for previous retrospectives using pattern: {implementation_artifacts}/epic-{{prev_epic_num}}-retro-*.md - + -Bob (Scrum Master): "I found our retrospective from Epic {{prev_epic_num}}. Let me see what we committed to back then..." +Bob (Scrum Master): "I found our retrospectives from Epic {{prev_epic_num}}. Let me see what we committed to back then..." - Read the complete previous retrospective file + Read the previous retrospectives Extract key elements: - **Action items committed**: What did the team agree to improve? @@ -366,7 +366,7 @@ Alice (Product Owner): "Good thinking - helps us connect what we learned to what Attempt to load next epic using selective loading strategy: **Try sharded first (more specific):** -Check if file exists: {planning_artifacts}/epic\*/epic-{{next_epic_num}}.md +Check if file exists: {planning_artifacts}/epic*/epic-{{next_epic_num}}.md Load {planning_artifacts}/*epic*/epic-{{next_epic_num}}.md @@ -375,7 +375,7 @@ Alice (Product Owner): "Good thinking - helps us connect what we learned to what **Fallback to whole document:** -Check if file exists: {planning_artifacts}/epic\*.md +Check if file exists: {planning_artifacts}/epic*.md Load entire epics document @@ -1303,7 +1303,7 @@ Bob (Scrum Master): "See you all when prep work is done. Meeting adjourned!" -Ensure retrospectives folder exists: {retrospectives_folder} +Ensure retrospectives folder exists: {implementation_artifacts} Create folder if it doesn't exist Generate comprehensive retrospective summary document including: @@ -1323,11 +1323,11 @@ Bob (Scrum Master): "See you all when prep work is done. Meeting adjourned!" - Commitments and next steps Format retrospective document as readable markdown with clear sections -Set filename: {retrospectives_folder}/epic-{{epic_number}}-retro-{date}.md +Set filename: {implementation_artifacts}/epic-{{epic_number}}-retro-{date}.md Save retrospective document -✅ Retrospective document saved: {retrospectives_folder}/epic-{{epic_number}}-retro-{date}.md +✅ Retrospective document saved: {implementation_artifacts}/epic-{{epic_number}}-retro-{date}.md Update {sprint_status_file} to mark retrospective as completed @@ -1366,7 +1366,7 @@ Retrospective document was saved successfully, but {sprint_status_file} may need - Epic {{epic_number}}: {{epic_title}} reviewed - Retrospective Status: completed -- Retrospective saved: {retrospectives_folder}/epic-{{epic_number}}-retro-{date}.md +- Retrospective saved: {implementation_artifacts}/epic-{{epic_number}}-retro-{date}.md **Commitments Made:** @@ -1376,7 +1376,7 @@ Retrospective document was saved successfully, but {sprint_status_file} may need **Next Steps:** -1. **Review retrospective summary**: {retrospectives_folder}/epic-{{epic_number}}-retro-{date}.md +1. **Review retrospective summary**: {implementation_artifacts}/epic-{{epic_number}}-retro-{date}.md 2. **Execute preparation sprint** (Est: {{prep_days}} days) - Complete {{critical_count}} critical path items diff --git a/src/bmm/workflows/4-implementation/retrospective/workflow.yaml b/src/bmm/workflows/4-implementation/retrospective/workflow.yaml index d2be349f1..773c7f2d6 100644 --- a/src/bmm/workflows/4-implementation/retrospective/workflow.yaml +++ b/src/bmm/workflows/4-implementation/retrospective/workflow.yaml @@ -4,7 +4,6 @@ description: "Run after epic completion to review overall success, extract lesso author: "BMad" config_source: "{project-root}/_bmad/bmm/config.yaml" -output_folder: "{config_source}:implementation_artifacts}" user_name: "{config_source}:user_name" communication_language: "{config_source}:communication_language" user_skill_level: "{config_source}:user_skill_level" @@ -52,5 +51,3 @@ input_file_patterns: # Required files sprint_status_file: "{implementation_artifacts}/sprint-status.yaml" -story_directory: "{implementation_artifacts}" -retrospectives_folder: "{implementation_artifacts}" diff --git a/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml b/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml index 7b157633c..6c5d22d64 100644 --- a/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml +++ b/src/bmm/workflows/4-implementation/sprint-planning/workflow.yaml @@ -9,7 +9,6 @@ communication_language: "{config_source}:communication_language" date: system-generated implementation_artifacts: "{config_source}:implementation_artifacts" planning_artifacts: "{config_source}:planning_artifacts" -output_folder: "{implementation_artifacts}" # Workflow components installed_path: "{project-root}/_bmad/bmm/workflows/4-implementation/sprint-planning" @@ -18,24 +17,21 @@ template: "{installed_path}/sprint-status-template.yaml" validation: "{installed_path}/checklist.md" # Variables and inputs -variables: - # Project context - project_context: "**/project-context.md" - # Project identification - project_name: "{config_source}:project_name" +project_context: "**/project-context.md" +project_name: "{config_source}:project_name" - # Tracking system configuration - tracking_system: "file-system" # Options: file-system, Future will support other options from config of mcp such as jira, linear, trello - project_key: "NOKEY" # Placeholder for tracker integrations; file-system uses a no-op key - story_location: "{config_source}:implementation_artifacts" # Relative path for file-system, Future will support URL for Jira/Linear/Trello - story_location_absolute: "{config_source}:implementation_artifacts" # Absolute path for file operations +# Tracking system configuration +tracking_system: "file-system" # Options: file-system, Future will support other options from config of mcp such as jira, linear, trello +project_key: "NOKEY" # Placeholder for tracker integrations; file-system uses a no-op key +story_location: "{implementation_artifacts}" # Relative path for file-system, Future will support URL for Jira/Linear/Trello +story_location_absolute: "{implementation_artifacts}" # Absolute path for file operations - # Source files (file-system only) - epics_location: "{planning_artifacts}" # Directory containing epic*.md files - epics_pattern: "epic*.md" # Pattern to find epic files +# Source files (file-system only) +epics_location: "{planning_artifacts}" # Directory containing epic*.md files +epics_pattern: "epic*.md" # Pattern to find epic files - # Output configuration - status_file: "{implementation_artifacts}/sprint-status.yaml" +# Output configuration +status_file: "{implementation_artifacts}/sprint-status.yaml" # Smart input file references - handles both whole docs and sharded docs # Priority: Whole document first, then sharded version @@ -43,8 +39,8 @@ variables: input_file_patterns: epics: description: "All epics with user stories" - whole: "{output_folder}/*epic*.md" - sharded: "{output_folder}/*epic*/*.md" + whole: "{planning_artifacts}/*epic*.md" + sharded: "{planning_artifacts}/*epic*/*.md" load_strategy: "FULL_LOAD" # Output configuration diff --git a/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml b/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml index ef98f48da..f27d57024 100644 --- a/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml +++ b/src/bmm/workflows/4-implementation/sprint-status/workflow.yaml @@ -5,23 +5,17 @@ author: "BMad" # Critical variables from config config_source: "{project-root}/_bmad/bmm/config.yaml" -output_folder: "{config_source}:output_folder" user_name: "{config_source}:user_name" communication_language: "{config_source}:communication_language" document_output_language: "{config_source}:document_output_language" -date: system-generated implementation_artifacts: "{config_source}:implementation_artifacts" -planning_artifacts: "{config_source}:planning_artifacts" -project_context: "**/project-context.md" # Workflow components installed_path: "{project-root}/_bmad/bmm/workflows/4-implementation/sprint-status" instructions: "{installed_path}/instructions.md" # Inputs -variables: - sprint_status_file: "{implementation_artifacts}/sprint-status.yaml" - tracking_system: "file-system" +sprint_status_file: "{implementation_artifacts}/sprint-status.yaml" # Smart input file references input_file_patterns: diff --git a/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md b/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md index 3fbeb13b1..8c6a1902b 100644 --- a/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md +++ b/src/bmm/workflows/bmad-quick-flow/quick-dev/workflow.md @@ -28,7 +28,7 @@ This uses **step-file architecture** for focused execution: Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve: - `user_name`, `communication_language`, `user_skill_level` -- `output_folder`, `planning_artifacts`, `implementation_artifacts` +- `planning_artifacts`, `implementation_artifacts` - `date` as system-generated current datetime - ✅ YOU MUST ALWAYS SPEAK OUTPUT In your Agent communication style with the config `{communication_language}` diff --git a/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-01-understand.md b/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-01-understand.md index d338f24b7..f0622f207 100644 --- a/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-01-understand.md +++ b/src/bmm/workflows/bmad-quick-flow/quick-spec/steps/step-01-understand.md @@ -76,7 +76,7 @@ a) **Before asking detailed questions, do a rapid scan to understand the landsca b) **Check for existing context docs:** -- Check `{output_folder}` and `{planning_artifacts}`for planning documents (PRD, architecture, epics, research) +- Check `{implementation_artifacts}` and `{planning_artifacts}`for planning documents (PRD, architecture, epics, research) - Check for `**/project-context.md` - if it exists, skim for patterns and conventions - Check for any existing stories or specs related to user's request diff --git a/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md b/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md index 5591df898..cc4fdf221 100644 --- a/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md +++ b/src/bmm/workflows/bmad-quick-flow/quick-spec/workflow.md @@ -68,7 +68,7 @@ This uses **step-file architecture** for disciplined execution: Load and read full config from `{main_config}` and resolve: -- `project_name`, `output_folder`, `planning_artifacts`, `implementation_artifacts`, `user_name` +- `project_name`, `planning_artifacts`, `implementation_artifacts`, `user_name` - `communication_language`, `document_output_language`, `user_skill_level` - `date` as system-generated current datetime - `project_context` = `**/project-context.md` (load if exists) diff --git a/src/bmm/workflows/document-project/instructions.md b/src/bmm/workflows/document-project/instructions.md index 2f567fa38..059134259 100644 --- a/src/bmm/workflows/document-project/instructions.md +++ b/src/bmm/workflows/document-project/instructions.md @@ -57,7 +57,7 @@ SMART LOADING STRATEGY: Check state file FIRST before loading any CSV files -Check for existing state file at: {output_folder}/project-scan-report.json +Check for existing state file at: {project_knowledge}/project-scan-report.json Read state file and extract: timestamps, mode, scan_level, current_step, completed_steps, project_classification @@ -107,8 +107,8 @@ Your choice [1/2/3]: - Create archive directory: {output_folder}/.archive/ - Move old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json + Create archive directory: {project_knowledge}/.archive/ + Move old state file to: {project_knowledge}/.archive/project-scan-report-{{timestamp}}.json Set resume_mode = false Continue to Step 0.5 @@ -120,7 +120,7 @@ Your choice [1/2/3]: Display: "Found old state file (>24 hours). Starting fresh scan." - Archive old state file to: {output_folder}/.archive/project-scan-report-{{timestamp}}.json + Archive old state file to: {project_knowledge}/.archive/project-scan-report-{{timestamp}}.json Set resume_mode = false Continue to Step 0.5 @@ -128,7 +128,7 @@ Your choice [1/2/3]: -Check if {output_folder}/index.md exists +Check if {project_knowledge}/index.md exists Read existing index.md to extract metadata (date, project structure, parts count) @@ -195,7 +195,7 @@ Your choice [1/2/3]: - Mode: {{workflow_mode}} - Scan Level: {{scan_level}} -- Output: {output_folder}/index.md and related files +- Output: {project_knowledge}/index.md and related files {{#if status_file_found}} **Status Updated:** diff --git a/src/bmm/workflows/document-project/templates/project-scan-report-schema.json b/src/bmm/workflows/document-project/templates/project-scan-report-schema.json index 8133e15fd..69e059833 100644 --- a/src/bmm/workflows/document-project/templates/project-scan-report-schema.json +++ b/src/bmm/workflows/document-project/templates/project-scan-report-schema.json @@ -45,9 +45,9 @@ "type": "string", "description": "Absolute path to project root directory" }, - "output_folder": { + "project_knowledge": { "type": "string", - "description": "Absolute path to output folder" + "description": "Absolute path to project knowledge folder" }, "completed_steps": { "type": "array", diff --git a/src/bmm/workflows/document-project/workflow.yaml b/src/bmm/workflows/document-project/workflow.yaml index 4667d7c0b..be9600c24 100644 --- a/src/bmm/workflows/document-project/workflow.yaml +++ b/src/bmm/workflows/document-project/workflow.yaml @@ -6,7 +6,7 @@ author: "BMad" # Critical variables config_source: "{project-root}/_bmad/bmm/config.yaml" -output_folder: "{config_source}:project_knowledge" +project_knowledge: "{config_source}:project_knowledge" user_name: "{config_source}:user_name" communication_language: "{config_source}:communication_language" document_output_language: "{config_source}:document_output_language" diff --git a/src/bmm/workflows/document-project/workflows/deep-dive-instructions.md b/src/bmm/workflows/document-project/workflows/deep-dive-instructions.md index c88dfb08b..637621c4c 100644 --- a/src/bmm/workflows/document-project/workflows/deep-dive-instructions.md +++ b/src/bmm/workflows/document-project/workflows/deep-dive-instructions.md @@ -194,7 +194,7 @@ This will read EVERY file in this area. Proceed? [y/n] Load complete deep-dive template from: {installed_path}/templates/deep-dive-template.md Fill template with all collected data from steps 13b-13d -Write filled template to: {output_folder}/deep-dive-{{sanitized_target_name}}.md +Write filled template to: {project_knowledge}/deep-dive-{{sanitized_target_name}}.md Validate deep-dive document completeness deep_dive_documentation @@ -241,7 +241,7 @@ Detailed exhaustive analysis of specific areas: ## Deep-Dive Documentation Complete! ✓ -**Generated:** {output_folder}/deep-dive-{{target_name}}.md +**Generated:** {project_knowledge}/deep-dive-{{target_name}}.md **Files Analyzed:** {{file_count}} **Lines of Code Scanned:** {{total_loc}} **Time Taken:** ~{{duration}} @@ -255,7 +255,7 @@ Detailed exhaustive analysis of specific areas: - Related code and reuse opportunities - Implementation guidance -**Index Updated:** {output_folder}/index.md now includes link to this deep-dive +**Index Updated:** {project_knowledge}/index.md now includes link to this deep-dive ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ @@ -278,7 +278,7 @@ Your choice [1/2]: All deep-dive documentation complete! -**Master Index:** {output_folder}/index.md +**Master Index:** {project_knowledge}/index.md **Deep-Dives Generated:** {{deep_dive_count}} These comprehensive docs are now ready for: diff --git a/src/bmm/workflows/document-project/workflows/deep-dive.yaml b/src/bmm/workflows/document-project/workflows/deep-dive.yaml index a333cc4bf..c7b85c031 100644 --- a/src/bmm/workflows/document-project/workflows/deep-dive.yaml +++ b/src/bmm/workflows/document-project/workflows/deep-dive.yaml @@ -8,7 +8,7 @@ parent_workflow: "{project-root}/_bmad/bmm/workflows/document-project/workflow.y # Critical variables inherited from parent config_source: "{project-root}/_bmad/bmb/config.yaml" -output_folder: "{config_source}:output_folder" +project_knowledge: "{config_source}:project_knowledge" user_name: "{config_source}:user_name" date: system-generated diff --git a/src/bmm/workflows/document-project/workflows/full-scan-instructions.md b/src/bmm/workflows/document-project/workflows/full-scan-instructions.md index 1340f75ec..8a3621d21 100644 --- a/src/bmm/workflows/document-project/workflows/full-scan-instructions.md +++ b/src/bmm/workflows/document-project/workflows/full-scan-instructions.md @@ -43,7 +43,7 @@ This workflow uses a single comprehensive CSV file to intelligently document you -Check if {output_folder}/index.md exists +Check if {project_knowledge}/index.md exists Read existing index.md to extract metadata (date, project structure, parts count) @@ -127,7 +127,7 @@ Your choice [1/2/3] (default: 1): Display: "Using Exhaustive Scan (reading all source files)" -Initialize state file: {output_folder}/project-scan-report.json +Initialize state file: {project_knowledge}/project-scan-report.json Every time you touch the state file, record: step id, human-readable summary (what you actually did), precise timestamp, and any outputs written. Vague phrases are unacceptable. Write initial state: { @@ -136,7 +136,7 @@ Your choice [1/2/3] (default: 1): "mode": "{{workflow_mode}}", "scan_level": "{{scan_level}}", "project_root": "{{project_root_path}}", -"output_folder": "{{output_folder}}", +"project_knowledge": "{{project_knowledge}}", "completed_steps": [], "current_step": "step_1", "findings": {}, @@ -325,7 +325,7 @@ findings.batches_completed: [ Build API contracts catalog -IMMEDIATELY write to: {output_folder}/api-contracts-{part_id}.md +IMMEDIATELY write to: {project_knowledge}/api-contracts-{part_id}.md Validate document has all required sections Update state file with output generated PURGE detailed API data, keep only: "{{api_count}} endpoints documented" @@ -346,7 +346,7 @@ findings.batches_completed: [ Build database schema documentation -IMMEDIATELY write to: {output_folder}/data-models-{part_id}.md +IMMEDIATELY write to: {project_knowledge}/data-models-{part_id}.md Validate document completeness Update state file with output generated PURGE detailed schema data, keep only: "{{table_count}} tables documented" @@ -805,7 +805,7 @@ When a document SHOULD be generated but wasn't (due to quick scan, missing data, Show summary of all generated files: -Generated in {{output_folder}}/: +Generated in {{project_knowledge}}/: {{file_list_with_sizes}} @@ -823,7 +823,7 @@ Generated in {{output_folder}}/: 3. Extract document metadata from each match for user selection -Read {output_folder}/index.md +Read {project_knowledge}/index.md Scan for incomplete documentation markers: Step 1: Search for exact pattern "_(To be generated)_" (case-sensitive) @@ -1065,9 +1065,9 @@ Enter number(s) separated by commas (e.g., "1,3,5"), or type 'all': ## Project Documentation Complete! ✓ -**Location:** {{output_folder}}/ +**Location:** {{project_knowledge}}/ -**Master Index:** {{output_folder}}/index.md +**Master Index:** {{project_knowledge}}/index.md 👆 This is your primary entry point for AI-assisted development **Generated Documentation:** @@ -1076,9 +1076,9 @@ Enter number(s) separated by commas (e.g., "1,3,5"), or type 'all': **Next Steps:** 1. Review the index.md to familiarize yourself with the documentation structure -2. When creating a brownfield PRD, point the PRD workflow to: {{output_folder}}/index.md -3. For UI-only features: Reference {{output_folder}}/architecture-{{ui_part_id}}.md -4. For API-only features: Reference {{output_folder}}/architecture-{{api_part_id}}.md +2. When creating a brownfield PRD, point the PRD workflow to: {{project_knowledge}}/index.md +3. For UI-only features: Reference {{project_knowledge}}/architecture-{{ui_part_id}}.md +4. For API-only features: Reference {{project_knowledge}}/architecture-{{api_part_id}}.md 5. For full-stack features: Reference both part architectures + integration-architecture.md **Verification Recap:** @@ -1101,6 +1101,6 @@ When ready to plan new features, run the PRD workflow and provide this index as - Write final state file -Display: "State file saved: {{output_folder}}/project-scan-report.json" +Display: "State file saved: {{project_knowledge}}/project-scan-report.json" diff --git a/src/bmm/workflows/document-project/workflows/full-scan.yaml b/src/bmm/workflows/document-project/workflows/full-scan.yaml index f62aba9b2..272baedda 100644 --- a/src/bmm/workflows/document-project/workflows/full-scan.yaml +++ b/src/bmm/workflows/document-project/workflows/full-scan.yaml @@ -8,7 +8,7 @@ parent_workflow: "{project-root}/_bmad/bmm/workflows/document-project/workflow.y # Critical variables inherited from parent config_source: "{project-root}/_bmad/bmb/config.yaml" -output_folder: "{config_source}:output_folder" +project_knowledge: "{config_source}:project_knowledge" user_name: "{config_source}:user_name" date: system-generated diff --git a/src/bmm/workflows/qa/automate/workflow.yaml b/src/bmm/workflows/qa/automate/workflow.yaml index 847365d7b..f1119e980 100644 --- a/src/bmm/workflows/qa/automate/workflow.yaml +++ b/src/bmm/workflows/qa/automate/workflow.yaml @@ -5,7 +5,6 @@ author: "BMad" # Critical variables from config config_source: "{project-root}/_bmad/bmm/config.yaml" -output_folder: "{config_source}:output_folder" implementation_artifacts: "{config_source}:implementation_artifacts" user_name: "{config_source}:user_name" communication_language: "{config_source}:communication_language" @@ -19,10 +18,8 @@ validation: "{installed_path}/checklist.md" template: false # Variables and inputs -variables: - # Directory paths - test_dir: "{project-root}/tests" # Root test directory - source_dir: "{project-root}" # Source code directory +test_dir: "{project-root}/tests" # Root test directory +source_dir: "{project-root}" # Source code directory # Output configuration default_output_file: "{implementation_artifacts}/tests/test-summary.md" From 5b79330f727a7c5dee78f2f5cd80dafd8cc36abe Mon Sep 17 00:00:00 2001 From: Pablo LION Date: Thu, 12 Feb 2026 19:09:12 +0100 Subject: [PATCH 03/17] fix: fix typos in tech-writer and ux-designer agent definitions (#1599) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - tech-writer: "1000s works" → "1000s of words" (idiom typo) - ux-designer: "PRovides" → "Provides", "that" → "than" (typos in description) Co-authored-by: Claude Opus 4.6 --- src/bmm/agents/tech-writer/tech-writer.agent.yaml | 2 +- src/bmm/agents/ux-designer.agent.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bmm/agents/tech-writer/tech-writer.agent.yaml b/src/bmm/agents/tech-writer/tech-writer.agent.yaml index a129aca34..555bd7981 100644 --- a/src/bmm/agents/tech-writer/tech-writer.agent.yaml +++ b/src/bmm/agents/tech-writer/tech-writer.agent.yaml @@ -16,7 +16,7 @@ agent: communication_style: "Patient educator who explains like teaching a friend. Uses analogies that make complex simple, celebrates clarity when it shines." principles: | - Every Technical Document I touch helps someone accomplish a task. Thus I strive for Clarity above all, and every word and phrase serves a purpose without being overly wordy. - - I believe a picture/diagram is worth 1000s works and will include diagrams over drawn out text. + - I believe a picture/diagram is worth 1000s of words and will include diagrams over drawn out text. - I understand the intended audience or will clarify with the user so I know when to simplify vs when to be detailed. - I will always strive to follow `_bmad/_memory/tech-writer-sidecar/documentation-standards.md` best practices. diff --git a/src/bmm/agents/ux-designer.agent.yaml b/src/bmm/agents/ux-designer.agent.yaml index cbff28576..301a07fc6 100644 --- a/src/bmm/agents/ux-designer.agent.yaml +++ b/src/bmm/agents/ux-designer.agent.yaml @@ -24,4 +24,4 @@ agent: menu: - trigger: CU or fuzzy match on ux-design exec: "{project-root}/_bmad/bmm/workflows/2-plan-workflows/create-ux-design/workflow.md" - description: "[CU] Create UX: Guidance through realizing the plan for your UX to inform architecture and implementation. PRovides more details that what was discovered in the PRD" + description: "[CU] Create UX: Guidance through realizing the plan for your UX to inform architecture and implementation. Provides more details than what was discovered in the PRD" From c8ca08331604a7a47b4c7090d30e58099421f28f Mon Sep 17 00:00:00 2001 From: Pablo LION Date: Thu, 12 Feb 2026 19:10:33 +0100 Subject: [PATCH 04/17] fix: remove unnecessary quotes and fix grammar in bmad-master principles (#1600) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove YAML quotes from principles list item (consistency with other agents) - Add missing comma: "at runtime never" → "at runtime, never" (run-on fix) Co-authored-by: Claude Opus 4.6 --- src/core/agents/bmad-master.agent.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/agents/bmad-master.agent.yaml b/src/core/agents/bmad-master.agent.yaml index a7dbc7105..1304c1cc9 100644 --- a/src/core/agents/bmad-master.agent.yaml +++ b/src/core/agents/bmad-master.agent.yaml @@ -15,7 +15,7 @@ agent: identity: "Master-level expert in the BMAD Core Platform and all loaded modules with comprehensive knowledge of all resources, tasks, and workflows. Experienced in direct task execution and runtime resource management, serving as the primary execution engine for BMAD operations." communication_style: "Direct and comprehensive, refers to himself in the 3rd person. Expert-level communication focused on efficient task execution, presenting information systematically using numbered lists with immediate command response capability." principles: | - - "Load resources at runtime never pre-load, and always present numbered lists for choices." + - Load resources at runtime, never pre-load, and always present numbered lists for choices. critical_actions: - "Always greet the user and let them know they can use `/bmad-help` at any time to get advice on what to do next, and they can combine that with what they need help with `/bmad-help where should I start with an idea I have that does XYZ`" From b81541090411f5c37187778ce62fa68485cbcc02 Mon Sep 17 00:00:00 2001 From: Adam Biggs Date: Thu, 12 Feb 2026 16:58:13 -0800 Subject: [PATCH 05/17] fix(opencode): remove incorrect mode: primary and restore name field in templates (#1644) Remove hallucinated mode: primary from opencode-agent template - OpenCode defaults to mode: all and mode: primary does not enable Tab-switching as the original PR #1556 claimed. Restore the name frontmatter field across all OpenCode templates to match the standard pattern used by other IDEs. --- .../cli/installers/lib/ide/templates/combined/opencode-agent.md | 2 +- .../cli/installers/lib/ide/templates/combined/opencode-task.md | 2 ++ .../cli/installers/lib/ide/templates/combined/opencode-tool.md | 2 ++ .../lib/ide/templates/combined/opencode-workflow-yaml.md | 2 ++ .../installers/lib/ide/templates/combined/opencode-workflow.md | 2 ++ 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/cli/installers/lib/ide/templates/combined/opencode-agent.md b/tools/cli/installers/lib/ide/templates/combined/opencode-agent.md index 1102aa8a1..65f0a771d 100644 --- a/tools/cli/installers/lib/ide/templates/combined/opencode-agent.md +++ b/tools/cli/installers/lib/ide/templates/combined/opencode-agent.md @@ -1,5 +1,5 @@ --- -mode: primary +name: '{{name}}' description: '{{description}}' --- diff --git a/tools/cli/installers/lib/ide/templates/combined/opencode-task.md b/tools/cli/installers/lib/ide/templates/combined/opencode-task.md index 155c135c4..98b3a5d77 100644 --- a/tools/cli/installers/lib/ide/templates/combined/opencode-task.md +++ b/tools/cli/installers/lib/ide/templates/combined/opencode-task.md @@ -1,10 +1,12 @@ --- +name: '{{name}}' description: '{{description}}' --- Execute the BMAD '{{name}}' task. TASK INSTRUCTIONS: + 1. LOAD the task file from {project-root}/{{bmadFolderName}}/{{path}} 2. READ its entire contents 3. FOLLOW every instruction precisely as specified diff --git a/tools/cli/installers/lib/ide/templates/combined/opencode-tool.md b/tools/cli/installers/lib/ide/templates/combined/opencode-tool.md index 505445253..1ae9c9ac8 100644 --- a/tools/cli/installers/lib/ide/templates/combined/opencode-tool.md +++ b/tools/cli/installers/lib/ide/templates/combined/opencode-tool.md @@ -1,10 +1,12 @@ --- +name: '{{name}}' description: '{{description}}' --- Execute the BMAD '{{name}}' tool. TOOL INSTRUCTIONS: + 1. LOAD the tool file from {project-root}/{{bmadFolderName}}/{{path}} 2. READ its entire contents 3. FOLLOW every instruction precisely as specified diff --git a/tools/cli/installers/lib/ide/templates/combined/opencode-workflow-yaml.md b/tools/cli/installers/lib/ide/templates/combined/opencode-workflow-yaml.md index d1e2b0af2..a6f5cb96f 100644 --- a/tools/cli/installers/lib/ide/templates/combined/opencode-workflow-yaml.md +++ b/tools/cli/installers/lib/ide/templates/combined/opencode-workflow-yaml.md @@ -1,4 +1,5 @@ --- +name: '{{name}}' description: '{{description}}' --- @@ -7,6 +8,7 @@ Execute the BMAD '{{name}}' workflow. CRITICAL: You must load and follow the workflow definition exactly. WORKFLOW INSTRUCTIONS: + 1. LOAD the workflow file from {project-root}/{{bmadFolderName}}/{{path}} 2. READ its entire contents 3. FOLLOW every step precisely as specified diff --git a/tools/cli/installers/lib/ide/templates/combined/opencode-workflow.md b/tools/cli/installers/lib/ide/templates/combined/opencode-workflow.md index d1e2b0af2..a6f5cb96f 100644 --- a/tools/cli/installers/lib/ide/templates/combined/opencode-workflow.md +++ b/tools/cli/installers/lib/ide/templates/combined/opencode-workflow.md @@ -1,4 +1,5 @@ --- +name: '{{name}}' description: '{{description}}' --- @@ -7,6 +8,7 @@ Execute the BMAD '{{name}}' workflow. CRITICAL: You must load and follow the workflow definition exactly. WORKFLOW INSTRUCTIONS: + 1. LOAD the workflow file from {project-root}/{{bmadFolderName}}/{{path}} 2. READ its entire contents 3. FOLLOW every step precisely as specified From e66bbd02f23f2ded52429247f6f782379be29a79 Mon Sep 17 00:00:00 2001 From: Alex Verkhovsky Date: Fri, 13 Feb 2026 21:54:35 -0700 Subject: [PATCH 06/17] docs: replace branching strategy doc with trunk-based development reference (#1598) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 06ab6d174..d9c12655f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -73,7 +73,7 @@ After searching, use the [feature request template](https://github.com/bmad-code ### Target Branch -Submit PRs to the `main` branch. +Submit PRs to the `main` branch. We use [trunk-based development](https://trunkbaseddevelopment.com/branch-for-release/): `main` is the trunk where all work lands, and stable release branches receive only cherry-picked fixes. ### PR Size From 3103c3d4ce4d8fd5575ac2bc73ae5204ec2b630d Mon Sep 17 00:00:00 2001 From: Murat K Ozcan <34237651+muratkeremozcan@users.noreply.github.com> Date: Sat, 14 Feb 2026 10:44:39 -0600 Subject: [PATCH 07/17] feat: tea automation prereq prompts (#1649) * feat: tea automation prereq prompts * fix: addressed PR comments * docs: added docs on how to set the post install output in the module * addressed PR request from Brian --- .../installers/lib/core/config-collector.js | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tools/cli/installers/lib/core/config-collector.js b/tools/cli/installers/lib/core/config-collector.js index 44d3805d7..b01098318 100644 --- a/tools/cli/installers/lib/core/config-collector.js +++ b/tools/cli/installers/lib/core/config-collector.js @@ -550,6 +550,8 @@ class ConfigCollector { } } + await this.displayModulePostConfigNotes(moduleName, moduleConfig); + return newKeys.length > 0 || newStaticKeys.length > 0; // Return true if we had any new fields (interactive or static) } @@ -923,6 +925,8 @@ class ConfigCollector { } } } + + await this.displayModulePostConfigNotes(moduleName, moduleConfig); } /** @@ -1195,6 +1199,59 @@ class ConfigCollector { return question; } + /** + * Display post-configuration notes for a module + * Shows prerequisite guidance based on collected config values + * Reads notes from the module's `post-install-notes` section in module.yaml + * Supports two formats: + * - Simple string: always displayed + * - Object keyed by config field name, with value-specific messages + * @param {string} moduleName - Module name + * @param {Object} moduleConfig - Parsed module.yaml content + */ + async displayModulePostConfigNotes(moduleName, moduleConfig) { + if (this._silentConfig) return; + if (!moduleConfig || !moduleConfig['post-install-notes']) return; + + const notes = moduleConfig['post-install-notes']; + const color = await prompts.getColor(); + + // Format 1: Simple string - always display + if (typeof notes === 'string') { + await prompts.log.message(''); + for (const line of notes.trim().split('\n')) { + await prompts.log.message(color.dim(line)); + } + return; + } + + // Format 2: Conditional on config values + if (typeof notes === 'object') { + const config = this.collectedConfig[moduleName]; + if (!config) return; + + let hasOutput = false; + for (const [configKey, valueMessages] of Object.entries(notes)) { + const selectedValue = config[configKey]; + if (!selectedValue || !valueMessages[selectedValue]) continue; + + if (hasOutput) await prompts.log.message(''); + hasOutput = true; + + const message = valueMessages[selectedValue]; + await prompts.log.message(''); + for (const line of message.trim().split('\n')) { + const trimmedLine = line.trim(); + if (trimmedLine.endsWith(':') && !trimmedLine.startsWith(' ')) { + await prompts.log.info(color.bold(trimmedLine)); + } else { + await prompts.log.message(color.dim(' ' + trimmedLine)); + } + } + } + } + } + /** * Deep merge two objects * @param {Object} target - Target object From ae7b3a7930865d2bc622a6ccec5c553b9b690e38 Mon Sep 17 00:00:00 2001 From: Murat K Ozcan <34237651+muratkeremozcan@users.noreply.github.com> Date: Sat, 14 Feb 2026 10:59:07 -0600 Subject: [PATCH 08/17] docs: post install notes (#1653) --- tools/cli/README.md | 53 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tools/cli/README.md b/tools/cli/README.md index 6d698580f..8ba164d36 100644 --- a/tools/cli/README.md +++ b/tools/cli/README.md @@ -5,3 +5,56 @@ For external official modules to be discoverable during install, ensure an entry for the external repo is added to external-official-modules.yaml. For community modules - this will be handled in a different way. This file is only for registration of modules under the bmad-code-org. + +## Post-Install Notes + +Modules can display setup guidance to users after configuration is collected during `npx bmad-method install`. Notes are defined in the module's own `module.yaml` — no changes to the installer are needed. + +### Simple Format + +Always displayed after the module is configured: + +```yaml +post-install-notes: | + Remember to set the API_KEY environment variable. + See: https://example.com/setup +``` + +### Conditional Format + +Display different messages based on a config question's answer: + +```yaml +post-install-notes: + config_key_name: + value1: | + Instructions for value1... + value2: | + Instructions for value2... +``` + +Values without an entry (e.g., `none`) display nothing. Multiple config keys can each have their own conditional notes. + +### Example: TEA Module + +The TEA module uses the conditional format keyed on `tea_browser_automation`: + +```yaml +post-install-notes: + tea_browser_automation: + cli: | + Playwright CLI Setup: + npm install -g @playwright/cli@latest + playwright-cli install --skills + mcp: | + Playwright MCP Setup (two servers): + 1. playwright — npx @playwright/mcp@latest + 2. playwright-test — npx playwright run-test-mcp-server + auto: | + Playwright CLI Setup: + ... + Playwright MCP Setup (two servers): + ... +``` + +When a user selects `auto`, they see both CLI and MCP instructions. When they select `none`, nothing is shown. From 98c1fa8282df16879cf06dfe6e5839f17e49693c Mon Sep 17 00:00:00 2001 From: Brian Madison Date: Thu, 12 Feb 2026 12:52:13 -0600 Subject: [PATCH 09/17] document project remove legacy workflow init and workflow- status function calls --- docs/_STYLE_GUIDE.md | 13 +- .../document-project/instructions.md | 115 ++---------------- 2 files changed, 18 insertions(+), 110 deletions(-) diff --git a/docs/_STYLE_GUIDE.md b/docs/_STYLE_GUIDE.md index 801314cd0..f9b38ed86 100644 --- a/docs/_STYLE_GUIDE.md +++ b/docs/_STYLE_GUIDE.md @@ -78,7 +78,6 @@ your-project/ ├── _bmad/ # BMad configuration ├── _bmad-output/ │ ├── PRD.md # Your requirements document -│ └── bmm-workflow-status.yaml # Progress tracking └── ... ``` ```` @@ -142,12 +141,12 @@ your-project/ ### Types -| Type | Example | -| ----------------- | ---------------------------- | -| **Index/Landing** | `core-concepts/index.md` | -| **Concept** | `what-are-agents.md` | -| **Feature** | `quick-flow.md` | -| **Philosophy** | `why-solutioning-matters.md` | +| Type | Example | +| ----------------- | ----------------------------- | +| **Index/Landing** | `core-concepts/index.md` | +| **Concept** | `what-are-agents.md` | +| **Feature** | `quick-flow.md` | +| **Philosophy** | `why-solutioning-matters.md` | | **FAQ** | `established-projects-faq.md` | ### General Template diff --git a/src/bmm/workflows/document-project/instructions.md b/src/bmm/workflows/document-project/instructions.md index 059134259..0354be610 100644 --- a/src/bmm/workflows/document-project/instructions.md +++ b/src/bmm/workflows/document-project/instructions.md @@ -8,55 +8,7 @@ This router determines workflow mode and delegates to specialized sub-workflows - - - - mode: data - data_request: project_config - - - - {{suggestion}} - Note: Documentation workflow can run standalone. Continuing without progress tracking. - Set standalone_mode = true - Set status_file_found = false - - - - Store {{status_file_path}} for later updates - Set status_file_found = true - - - - Note: This is a greenfield project. Documentation workflow is typically for brownfield projects. - Continue anyway to document planning artifacts? (y/n) - - Exit workflow - - - - - - mode: validate - calling_workflow: document-project - - - - {{warning}} - Note: This may be auto-invoked by prd for brownfield documentation. - Continue with documentation? (y/n) - - {{suggestion}} - Exit workflow - - - - - - - -SMART LOADING STRATEGY: Check state file FIRST before loading any CSV files - + Check for existing state file at: {project_knowledge}/project-scan-report.json @@ -66,21 +18,21 @@ I found an in-progress workflow state from {{last_updated}}. -**Current Progress:** + **Current Progress:** -- Mode: {{mode}} -- Scan Level: {{scan_level}} -- Completed Steps: {{completed_steps_count}}/{{total_steps}} -- Last Step: {{current_step}} -- Project Type(s): {{cached_project_types}} + - Mode: {{mode}} + - Scan Level: {{scan_level}} + - Completed Steps: {{completed_steps_count}}/{{total_steps}} + - Last Step: {{current_step}} + - Project Type(s): {{cached_project_types}} -Would you like to: + Would you like to: -1. **Resume from where we left off** - Continue from step {{current_step}} -2. **Start fresh** - Archive old state and begin new scan -3. **Cancel** - Exit without changes + 1. **Resume from where we left off** - Continue from step {{current_step}} + 2. **Start fresh** - Archive old state and begin new scan + 3. **Cancel** - Exit without changes -Your choice [1/2/3]: + Your choice [1/2/3]: @@ -175,47 +127,4 @@ Your choice [1/2/3]: - - - - - mode: update - action: complete_workflow - workflow_name: document-project - - - - Status updated! - - - -**✅ Document Project Workflow Complete, {user_name}!** - -**Documentation Generated:** - -- Mode: {{workflow_mode}} -- Scan Level: {{scan_level}} -- Output: {project_knowledge}/index.md and related files - -{{#if status_file_found}} -**Status Updated:** - -- Progress tracking updated - -**Next Steps:** - -- **Next required:** {{next_workflow}} ({{next_agent}} agent) - -Check status anytime with: `workflow-status` -{{else}} -**Next Steps:** -Since no workflow is in progress: - -- Refer to the BMM workflow guide if unsure what to do next -- Or run `workflow-init` to create a workflow path and get guided next steps - {{/if}} - - - - From 5b5cb1a3964ba5caab03d3c420d8a5c47fbe4d8d Mon Sep 17 00:00:00 2001 From: Brian Madison Date: Sat, 14 Feb 2026 21:25:58 -0600 Subject: [PATCH 10/17] modify post install notes example --- tools/cli/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/cli/README.md b/tools/cli/README.md index 8ba164d36..9e943d689 100644 --- a/tools/cli/README.md +++ b/tools/cli/README.md @@ -16,8 +16,8 @@ Always displayed after the module is configured: ```yaml post-install-notes: | - Remember to set the API_KEY environment variable. - See: https://example.com/setup + Thank you for choosing the XYZ Cool Module + For Support about this Module call 555-1212 ``` ### Conditional Format From a5e2b1c63a25b0070eb5aa5dd40132a96cec8d42 Mon Sep 17 00:00:00 2001 From: Ankit Gupta Date: Sun, 15 Feb 2026 13:59:11 +0000 Subject: [PATCH 11/17] docs: fix changelog URL in installer start message (#1660) Co-authored-by: Ankit Gupta --- tools/cli/installers/install-messages.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cli/installers/install-messages.yaml b/tools/cli/installers/install-messages.yaml index 66e683a27..6138c7c2c 100644 --- a/tools/cli/installers/install-messages.yaml +++ b/tools/cli/installers/install-messages.yaml @@ -34,7 +34,7 @@ startMessage: | - Subscribe on YouTube: https://www.youtube.com/@BMadCode - Every star & sub helps us reach more developers! - Latest updates: https://github.com/bmad-code-org/BMAD-METHOD/CHANGELOG.md + Latest updates: https://github.com/bmad-code-org/BMAD-METHOD/blob/main/CHANGELOG.md ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ From 2d134314c9daa251faf3554daba3a64f6b783463 Mon Sep 17 00:00:00 2001 From: Davor Racic Date: Sun, 15 Feb 2026 15:13:03 +0100 Subject: [PATCH 12/17] feat(cli): add uninstall command with selective component removal (#1650) * feat(cli): add uninstall command with selective component removal Add `bmad uninstall` CLI command for clean removal of BMAD installations. Interactive mode with directory router and component multiselect; non-interactive `--yes` flag preserves user artifacts by default. Three-phase spinner UX, manifest-scoped IDE cleanup, GitHub Copilot marker stripping, recursive empty directory cleanup, and chalk-to-clack migration in copilot handler. Co-Authored-By: Claude Opus 4.6 * fix(cli): address code review findings for uninstall command - Add path traversal guard in uninstallOutputFolder (resolve + startsWith) - Thread silent flag through to cleanupCopilotInstructions - Trim text input before path.resolve in directory prompt - DRY uninstall() by delegating to extracted helper methods - Validate projectDir existence before probing for BMAD - Use fs.rmdir instead of fs.remove in removeEmptyParents (race safety) Co-Authored-By: Claude Opus 4.6 * feat(cli): add destructive action warning and confirm before uninstall Move warning box after component selection and add a confirmation prompt defaulting to No, so users see the irreversibility warning right before the point of no return. Non-interactive --yes mode skips both. Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 Co-authored-by: Brian --- package.json | 1 + tools/cli/commands/uninstall.js | 167 ++++++++++++++++++ tools/cli/installers/lib/core/installer.js | 151 +++++++++++++++- .../cli/installers/lib/ide/_config-driven.js | 45 +++++ .../cli/installers/lib/ide/github-copilot.js | 95 +++++++--- tools/cli/installers/lib/ide/manager.js | 39 +++- 6 files changed, 464 insertions(+), 34 deletions(-) create mode 100644 tools/cli/commands/uninstall.js diff --git a/package.json b/package.json index 9cd7e90ad..6fc2e1024 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ }, "scripts": { "bmad:install": "node tools/cli/bmad-cli.js install", + "bmad:uninstall": "node tools/cli/bmad-cli.js uninstall", "docs:build": "node tools/build-docs.mjs", "docs:dev": "astro dev --root website", "docs:fix-links": "node tools/fix-doc-links.js", diff --git a/tools/cli/commands/uninstall.js b/tools/cli/commands/uninstall.js new file mode 100644 index 000000000..99734791e --- /dev/null +++ b/tools/cli/commands/uninstall.js @@ -0,0 +1,167 @@ +const path = require('node:path'); +const fs = require('fs-extra'); +const prompts = require('../lib/prompts'); +const { Installer } = require('../installers/lib/core/installer'); + +const installer = new Installer(); + +module.exports = { + command: 'uninstall', + description: 'Remove BMAD installation from the current project', + options: [ + ['-y, --yes', 'Remove all BMAD components without prompting (preserves user artifacts)'], + ['--directory ', 'Project directory (default: current directory)'], + ], + action: async (options) => { + try { + let projectDir; + + if (options.directory) { + // Explicit --directory flag takes precedence + projectDir = path.resolve(options.directory); + } else if (options.yes) { + // Non-interactive mode: use current directory + projectDir = process.cwd(); + } else { + // Interactive: ask user which directory to uninstall from + // select() handles cancellation internally (exits process) + const dirChoice = await prompts.select({ + message: 'Where do you want to uninstall BMAD from?', + choices: [ + { value: 'cwd', name: `Current directory (${process.cwd()})` }, + { value: 'other', name: 'Another directory...' }, + ], + }); + + if (dirChoice === 'other') { + // text() handles cancellation internally (exits process) + const customDir = await prompts.text({ + message: 'Enter the project directory path:', + placeholder: process.cwd(), + validate: (value) => { + if (!value || value.trim().length === 0) return 'Directory path is required'; + }, + }); + + projectDir = path.resolve(customDir.trim()); + } else { + projectDir = process.cwd(); + } + } + + if (!(await fs.pathExists(projectDir))) { + await prompts.log.error(`Directory does not exist: ${projectDir}`); + process.exit(1); + } + + const { bmadDir } = await installer.findBmadDir(projectDir); + + if (!(await fs.pathExists(bmadDir))) { + await prompts.log.warn('No BMAD installation found.'); + process.exit(0); + } + + const existingInstall = await installer.getStatus(projectDir); + const version = existingInstall.version || 'unknown'; + const modules = (existingInstall.modules || []).map((m) => m.id || m.name).join(', '); + const ides = (existingInstall.ides || []).join(', '); + + const outputFolder = await installer.getOutputFolder(projectDir); + + await prompts.intro('BMAD Uninstall'); + await prompts.note(`Version: ${version}\nModules: ${modules}\nIDE integrations: ${ides}`, 'Current Installation'); + + let removeModules = true; + let removeIdeConfigs = true; + let removeOutputFolder = false; + + if (!options.yes) { + // multiselect() handles cancellation internally (exits process) + const selected = await prompts.multiselect({ + message: 'Select components to remove:', + options: [ + { + value: 'modules', + label: `BMAD Modules & data (${installer.bmadFolderName}/)`, + hint: 'Core installation, agents, workflows, config', + }, + { value: 'ide', label: 'IDE integrations', hint: ides || 'No IDEs configured' }, + { value: 'output', label: `User artifacts (${outputFolder}/)`, hint: 'WARNING: Contains your work products' }, + ], + initialValues: ['modules', 'ide'], + required: true, + }); + + removeModules = selected.includes('modules'); + removeIdeConfigs = selected.includes('ide'); + removeOutputFolder = selected.includes('output'); + + const red = (s) => `\u001B[31m${s}\u001B[0m`; + await prompts.note( + red('💀 This action is IRREVERSIBLE! Removed files cannot be recovered!') + + '\n' + + red('💀 IDE configurations and modules will need to be reinstalled.') + + '\n' + + red('💀 User artifacts are preserved unless explicitly selected.'), + '!! DESTRUCTIVE ACTION !!', + ); + + const confirmed = await prompts.confirm({ + message: 'Proceed with uninstall?', + default: false, + }); + + if (!confirmed) { + await prompts.outro('Uninstall cancelled.'); + process.exit(0); + } + } + + // Phase 1: IDE integrations + if (removeIdeConfigs) { + const s = await prompts.spinner(); + s.start('Removing IDE integrations...'); + await installer.uninstallIdeConfigs(projectDir, existingInstall, { silent: true }); + s.stop(`Removed IDE integrations (${ides || 'none'})`); + } + + // Phase 2: User artifacts + if (removeOutputFolder) { + const s = await prompts.spinner(); + s.start(`Removing user artifacts (${outputFolder}/)...`); + await installer.uninstallOutputFolder(projectDir, outputFolder); + s.stop('User artifacts removed'); + } + + // Phase 3: BMAD modules & data (last — other phases may need _bmad/) + if (removeModules) { + const s = await prompts.spinner(); + s.start(`Removing BMAD modules & data (${installer.bmadFolderName}/)...`); + await installer.uninstallModules(projectDir); + s.stop('Modules & data removed'); + } + + const summary = []; + if (removeIdeConfigs) summary.push('IDE integrations cleaned'); + if (removeModules) summary.push('Modules & data removed'); + if (removeOutputFolder) summary.push('User artifacts removed'); + if (!removeOutputFolder) summary.push(`User artifacts preserved in ${outputFolder}/`); + + await prompts.note(summary.join('\n'), 'Summary'); + await prompts.outro('To reinstall, run: npx bmad-method install'); + + process.exit(0); + } catch (error) { + try { + const errorMessage = error instanceof Error ? error.message : String(error); + await prompts.log.error(`Uninstall failed: ${errorMessage}`); + if (error instanceof Error && error.stack) { + await prompts.log.message(error.stack); + } + } catch { + console.error(error instanceof Error ? error.message : error); + } + process.exit(1); + } + }, +}; diff --git a/tools/cli/installers/lib/core/installer.js b/tools/cli/installers/lib/core/installer.js index 3acb36465..b7197d44d 100644 --- a/tools/cli/installers/lib/core/installer.js +++ b/tools/cli/installers/lib/core/installer.js @@ -1528,20 +1528,157 @@ class Installer { } /** - * Uninstall BMAD + * Uninstall BMAD with selective removal options + * @param {string} directory - Project directory + * @param {Object} options - Uninstall options + * @param {boolean} [options.removeModules=true] - Remove _bmad/ directory + * @param {boolean} [options.removeIdeConfigs=true] - Remove IDE configurations + * @param {boolean} [options.removeOutputFolder=false] - Remove user artifacts output folder + * @returns {Object} Result with success status and removed components */ - async uninstall(directory) { + async uninstall(directory, options = {}) { const projectDir = path.resolve(directory); const { bmadDir } = await this.findBmadDir(projectDir); - if (await fs.pathExists(bmadDir)) { - await fs.remove(bmadDir); + if (!(await fs.pathExists(bmadDir))) { + return { success: false, reason: 'not-installed' }; } - // Clean up IDE configurations - await this.ideManager.cleanup(projectDir); + // 1. DETECT: Read state BEFORE deleting anything + const existingInstall = await this.detector.detect(bmadDir); + const outputFolder = await this._readOutputFolder(bmadDir); - return { success: true }; + const removed = { modules: false, ideConfigs: false, outputFolder: false }; + + // 2. IDE CLEANUP (before _bmad/ deletion so configs are accessible) + if (options.removeIdeConfigs !== false) { + await this.uninstallIdeConfigs(projectDir, existingInstall, { silent: options.silent }); + removed.ideConfigs = true; + } + + // 3. OUTPUT FOLDER (only if explicitly requested) + if (options.removeOutputFolder === true && outputFolder) { + removed.outputFolder = await this.uninstallOutputFolder(projectDir, outputFolder); + } + + // 4. BMAD DIRECTORY (last, after everything that needs it) + if (options.removeModules !== false) { + removed.modules = await this.uninstallModules(projectDir); + } + + return { success: true, removed, version: existingInstall.version }; + } + + /** + * Uninstall IDE configurations only + * @param {string} projectDir - Project directory + * @param {Object} existingInstall - Detection result from detector.detect() + * @param {Object} [options] - Options (e.g. { silent: true }) + * @returns {Promise} Results from IDE cleanup + */ + async uninstallIdeConfigs(projectDir, existingInstall, options = {}) { + await this.ideManager.ensureInitialized(); + const cleanupOptions = { isUninstall: true, silent: options.silent }; + const ideList = existingInstall.ides || []; + if (ideList.length > 0) { + return this.ideManager.cleanupByList(projectDir, ideList, cleanupOptions); + } + return this.ideManager.cleanup(projectDir, cleanupOptions); + } + + /** + * Remove user artifacts output folder + * @param {string} projectDir - Project directory + * @param {string} outputFolder - Output folder name (relative) + * @returns {Promise} Whether the folder was removed + */ + async uninstallOutputFolder(projectDir, outputFolder) { + if (!outputFolder) return false; + const resolvedProject = path.resolve(projectDir); + const outputPath = path.resolve(resolvedProject, outputFolder); + if (!outputPath.startsWith(resolvedProject + path.sep)) { + return false; + } + if (await fs.pathExists(outputPath)) { + await fs.remove(outputPath); + return true; + } + return false; + } + + /** + * Remove the _bmad/ directory + * @param {string} projectDir - Project directory + * @returns {Promise} Whether the directory was removed + */ + async uninstallModules(projectDir) { + const { bmadDir } = await this.findBmadDir(projectDir); + if (await fs.pathExists(bmadDir)) { + await fs.remove(bmadDir); + return true; + } + return false; + } + + /** + * Get the configured output folder name for a project + * Resolves bmadDir internally from projectDir + * @param {string} projectDir - Project directory + * @returns {string} Output folder name (relative, default: '_bmad-output') + */ + async getOutputFolder(projectDir) { + const { bmadDir } = await this.findBmadDir(projectDir); + return this._readOutputFolder(bmadDir); + } + + /** + * Read the output_folder setting from module config files + * Checks bmm/config.yaml first, then other module configs + * @param {string} bmadDir - BMAD installation directory + * @returns {string} Output folder path or default + */ + async _readOutputFolder(bmadDir) { + const yaml = require('yaml'); + + // Check bmm/config.yaml first (most common) + const bmmConfigPath = path.join(bmadDir, 'bmm', 'config.yaml'); + if (await fs.pathExists(bmmConfigPath)) { + try { + const content = await fs.readFile(bmmConfigPath, 'utf8'); + const config = yaml.parse(content); + if (config && config.output_folder) { + // Strip {project-root}/ prefix if present + return config.output_folder.replace(/^\{project-root\}[/\\]/, ''); + } + } catch { + // Fall through to other modules + } + } + + // Scan other module config.yaml files + try { + const entries = await fs.readdir(bmadDir, { withFileTypes: true }); + for (const entry of entries) { + if (!entry.isDirectory() || entry.name === 'bmm' || entry.name.startsWith('_')) continue; + const configPath = path.join(bmadDir, entry.name, 'config.yaml'); + if (await fs.pathExists(configPath)) { + try { + const content = await fs.readFile(configPath, 'utf8'); + const config = yaml.parse(content); + if (config && config.output_folder) { + return config.output_folder.replace(/^\{project-root\}[/\\]/, ''); + } + } catch { + // Continue scanning + } + } + } + } catch { + // Directory scan failed + } + + // Default fallback + return '_bmad-output'; } /** diff --git a/tools/cli/installers/lib/ide/_config-driven.js b/tools/cli/installers/lib/ide/_config-driven.js index 7eb2533ed..9541c75ed 100644 --- a/tools/cli/installers/lib/ide/_config-driven.js +++ b/tools/cli/installers/lib/ide/_config-driven.js @@ -456,8 +456,18 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}} async cleanup(projectDir, options = {}) { // Clean all target directories if (this.installerConfig?.targets) { + const parentDirs = new Set(); for (const target of this.installerConfig.targets) { await this.cleanupTarget(projectDir, target.target_dir, options); + // Track parent directories for empty-dir cleanup + const parentDir = path.dirname(target.target_dir); + if (parentDir && parentDir !== '.') { + parentDirs.add(parentDir); + } + } + // After all targets cleaned, remove empty parent directories (recursive up to projectDir) + for (const parentDir of parentDirs) { + await this.removeEmptyParents(projectDir, parentDir); } } else if (this.installerConfig?.target_dir) { await this.cleanupTarget(projectDir, this.installerConfig.target_dir, options); @@ -509,6 +519,41 @@ LOAD and execute from: {project-root}/{{bmadFolderName}}/{{path}} if (removedCount > 0 && !options.silent) { await prompts.log.message(` Cleaned ${removedCount} BMAD files from ${targetDir}`); } + + // Remove empty directory after cleanup + if (removedCount > 0) { + try { + const remaining = await fs.readdir(targetPath); + if (remaining.length === 0) { + await fs.remove(targetPath); + } + } catch { + // Directory may already be gone or in use — skip + } + } + } + /** + * Recursively remove empty directories walking up from dir toward projectDir + * Stops at projectDir boundary — never removes projectDir itself + * @param {string} projectDir - Project root (boundary) + * @param {string} relativeDir - Relative directory to start from + */ + async removeEmptyParents(projectDir, relativeDir) { + let current = relativeDir; + let last = null; + while (current && current !== '.' && current !== last) { + last = current; + const fullPath = path.join(projectDir, current); + try { + if (!(await fs.pathExists(fullPath))) break; + const remaining = await fs.readdir(fullPath); + if (remaining.length > 0) break; + await fs.rmdir(fullPath); + } catch { + break; + } + current = path.dirname(current); + } } } diff --git a/tools/cli/installers/lib/ide/github-copilot.js b/tools/cli/installers/lib/ide/github-copilot.js index 4d852fcb0..033e8d627 100644 --- a/tools/cli/installers/lib/ide/github-copilot.js +++ b/tools/cli/installers/lib/ide/github-copilot.js @@ -1,6 +1,6 @@ const path = require('node:path'); const { BaseIdeSetup } = require('./_base-ide'); -const chalk = require('chalk'); +const prompts = require('../../../lib/prompts'); const { AgentCommandGenerator } = require('./shared/agent-command-generator'); const { BMAD_FOLDER_NAME, toDashPath } = require('./shared/path-utils'); const fs = require('fs-extra'); @@ -31,7 +31,7 @@ class GitHubCopilotSetup extends BaseIdeSetup { * @param {Object} options - Setup options */ async setup(projectDir, bmadDir, options = {}) { - console.log(chalk.cyan(`Setting up ${this.name}...`)); + if (!options.silent) await prompts.log.info(`Setting up ${this.name}...`); // Create .github/agents and .github/prompts directories const githubDir = path.join(projectDir, this.githubDir); @@ -66,21 +66,15 @@ class GitHubCopilotSetup extends BaseIdeSetup { const targetPath = path.join(agentsDir, fileName); await this.writeFile(targetPath, agentContent); agentCount++; - - console.log(chalk.green(` ✓ Created agent: ${fileName}`)); } // Generate prompt files from bmad-help.csv const promptCount = await this.generatePromptFiles(projectDir, bmadDir, agentArtifacts, agentManifest); // Generate copilot-instructions.md - await this.generateCopilotInstructions(projectDir, bmadDir, agentManifest); + await this.generateCopilotInstructions(projectDir, bmadDir, agentManifest, options); - console.log(chalk.green(`\n✓ ${this.name} configured:`)); - console.log(chalk.dim(` - ${agentCount} agents created in .github/agents/`)); - console.log(chalk.dim(` - ${promptCount} prompts created in .github/prompts/`)); - console.log(chalk.dim(` - copilot-instructions.md generated`)); - console.log(chalk.dim(` - Destination: .github/`)); + if (!options.silent) await prompts.log.success(`${this.name} configured: ${agentCount} agents, ${promptCount} prompts → .github/`); return { success: true, @@ -406,7 +400,7 @@ tools: ${toolsStr} * @param {string} bmadDir - BMAD installation directory * @param {Map} agentManifest - Agent manifest data */ - async generateCopilotInstructions(projectDir, bmadDir, agentManifest) { + async generateCopilotInstructions(projectDir, bmadDir, agentManifest, options = {}) { const configVars = await this.loadModuleConfig(bmadDir); // Build the agents table from the manifest @@ -495,19 +489,16 @@ Type \`/bmad-\` in Copilot Chat to see all available BMAD workflows and agent ac const after = existing.slice(endIdx + markerEnd.length); const merged = `${before}${markedContent}${after}`; await this.writeFile(instructionsPath, merged); - console.log(chalk.green(' ✓ Updated BMAD section in copilot-instructions.md')); } else { // Existing file without markers — back it up before overwriting const backupPath = `${instructionsPath}.bak`; await fs.copy(instructionsPath, backupPath); - console.log(chalk.yellow(` ⚠ Backed up existing copilot-instructions.md → copilot-instructions.md.bak`)); + if (!options.silent) await prompts.log.warn(` Backed up copilot-instructions.md → .bak`); await this.writeFile(instructionsPath, `${markedContent}\n`); - console.log(chalk.green(' ✓ Generated copilot-instructions.md (with BMAD markers)')); } } else { // No existing file — create fresh with markers await this.writeFile(instructionsPath, `${markedContent}\n`); - console.log(chalk.green(' ✓ Generated copilot-instructions.md')); } } @@ -607,7 +598,7 @@ Type \`/bmad-\` in Copilot Chat to see all available BMAD workflows and agent ac /** * Cleanup GitHub Copilot configuration - surgically remove only BMAD files */ - async cleanup(projectDir) { + async cleanup(projectDir, options = {}) { // Clean up agents directory const agentsDir = path.join(projectDir, this.githubDir, this.agentsDir); if (await fs.pathExists(agentsDir)) { @@ -621,8 +612,8 @@ Type \`/bmad-\` in Copilot Chat to see all available BMAD workflows and agent ac } } - if (removed > 0) { - console.log(chalk.dim(` Cleaned up ${removed} existing BMAD agents`)); + if (removed > 0 && !options.silent) { + await prompts.log.message(` Cleaned up ${removed} existing BMAD agents`); } } @@ -639,16 +630,70 @@ Type \`/bmad-\` in Copilot Chat to see all available BMAD workflows and agent ac } } - if (removed > 0) { - console.log(chalk.dim(` Cleaned up ${removed} existing BMAD prompts`)); + if (removed > 0 && !options.silent) { + await prompts.log.message(` Cleaned up ${removed} existing BMAD prompts`); } } - // Note: copilot-instructions.md is NOT cleaned up here. - // generateCopilotInstructions() handles marker-based replacement in a single - // read-modify-write pass, which correctly preserves user content outside the markers. - // Stripping markers here would cause generation to treat the file as legacy (no markers) - // and overwrite user content. + // During uninstall, also strip BMAD markers from copilot-instructions.md. + // During reinstall (default), this is skipped because generateCopilotInstructions() + // handles marker-based replacement in a single read-modify-write pass, + // which correctly preserves user content outside the markers. + if (options.isUninstall) { + await this.cleanupCopilotInstructions(projectDir, options); + } + } + + /** + * Strip BMAD marker section from copilot-instructions.md + * If file becomes empty after stripping, delete it. + * If a .bak backup exists and the main file was deleted, restore the backup. + * @param {string} projectDir - Project directory + * @param {Object} [options] - Options (e.g. { silent: true }) + */ + async cleanupCopilotInstructions(projectDir, options = {}) { + const instructionsPath = path.join(projectDir, this.githubDir, 'copilot-instructions.md'); + const backupPath = `${instructionsPath}.bak`; + + if (!(await fs.pathExists(instructionsPath))) { + return; + } + + const content = await fs.readFile(instructionsPath, 'utf8'); + const markerStart = ''; + const markerEnd = ''; + const startIdx = content.indexOf(markerStart); + const endIdx = content.indexOf(markerEnd); + + if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx) { + return; // No valid markers found + } + + // Strip the marker section (including markers) + const before = content.slice(0, startIdx); + const after = content.slice(endIdx + markerEnd.length); + const cleaned = before + after; + + if (cleaned.trim().length === 0) { + // File is empty after stripping — delete it + await fs.remove(instructionsPath); + + // If backup exists, restore it + if (await fs.pathExists(backupPath)) { + await fs.rename(backupPath, instructionsPath); + if (!options.silent) { + await prompts.log.message(' Restored copilot-instructions.md from backup'); + } + } + } else { + // Write cleaned content back (preserve original whitespace) + await fs.writeFile(instructionsPath, cleaned, 'utf8'); + + // If backup exists, it's stale now — remove it + if (await fs.pathExists(backupPath)) { + await fs.remove(backupPath); + } + } } } diff --git a/tools/cli/installers/lib/ide/manager.js b/tools/cli/installers/lib/ide/manager.js index cb9774307..f83db4592 100644 --- a/tools/cli/installers/lib/ide/manager.js +++ b/tools/cli/installers/lib/ide/manager.js @@ -216,13 +216,14 @@ class IdeManager { /** * Cleanup IDE configurations * @param {string} projectDir - Project directory + * @param {Object} [options] - Cleanup options passed through to handlers */ - async cleanup(projectDir) { + async cleanup(projectDir, options = {}) { const results = []; for (const [name, handler] of this.handlers) { try { - await handler.cleanup(projectDir); + await handler.cleanup(projectDir, options); results.push({ ide: name, success: true }); } catch (error) { results.push({ ide: name, success: false, error: error.message }); @@ -232,6 +233,40 @@ class IdeManager { return results; } + /** + * Cleanup only the IDEs in the provided list + * Falls back to cleanup() (all handlers) if ideList is empty or undefined + * @param {string} projectDir - Project directory + * @param {Array} ideList - List of IDE names to clean up + * @param {Object} [options] - Cleanup options passed through to handlers + * @returns {Array} Results array + */ + async cleanupByList(projectDir, ideList, options = {}) { + if (!ideList || ideList.length === 0) { + return this.cleanup(projectDir, options); + } + + await this.ensureInitialized(); + const results = []; + + // Build lowercase lookup for case-insensitive matching + const lowercaseHandlers = new Map([...this.handlers.entries()].map(([k, v]) => [k.toLowerCase(), v])); + + for (const ideName of ideList) { + const handler = lowercaseHandlers.get(ideName.toLowerCase()); + if (!handler) continue; + + try { + await handler.cleanup(projectDir, options); + results.push({ ide: ideName, success: true }); + } catch (error) { + results.push({ ide: ideName, success: false, error: error.message }); + } + } + + return results; + } + /** * Get list of supported IDEs * @returns {Array} List of supported IDE names From 1937552da364e57bc94f373632a637848fb9e700 Mon Sep 17 00:00:00 2001 From: Davor Racic Date: Sun, 15 Feb 2026 22:39:53 +0100 Subject: [PATCH 13/17] fix: improve module config UX messaging and spacing (#1656) - Move "Module configuration complete" to appear after all customization prompts finish, not just after defaults are applied - Change spinner stop message to "Module defaults applied" for clarity when customization follows; keep "Module configuration complete" for express mode where no customization prompts follow - Remove extra blank line before post-install notes - Wrap spinner loop in try/finally for error safety Co-authored-by: Claude Opus 4.6 --- .../installers/lib/core/config-collector.js | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/tools/cli/installers/lib/core/config-collector.js b/tools/cli/installers/lib/core/config-collector.js index b01098318..e8569cd0f 100644 --- a/tools/cli/installers/lib/core/config-collector.js +++ b/tools/cli/installers/lib/core/config-collector.js @@ -302,23 +302,30 @@ class ConfigCollector { const configSpinner = await prompts.spinner(); configSpinner.start('Configuring modules...'); - for (const moduleName of defaultModules) { - const displayName = displayNameMap.get(moduleName) || moduleName.toUpperCase(); - configSpinner.message(`Configuring ${displayName}...`); - try { - this._silentConfig = true; - await this.collectModuleConfig(moduleName, projectDir); - } finally { - this._silentConfig = false; + try { + for (const moduleName of defaultModules) { + const displayName = displayNameMap.get(moduleName) || moduleName.toUpperCase(); + configSpinner.message(`Configuring ${displayName}...`); + try { + this._silentConfig = true; + await this.collectModuleConfig(moduleName, projectDir); + } finally { + this._silentConfig = false; + } } + } finally { + configSpinner.stop(customizeModules.length > 0 ? 'Module defaults applied' : 'Module configuration complete'); } - configSpinner.stop('Module configuration complete'); } // Run customized modules individually (may show interactive prompts) for (const moduleName of customizeModules) { await this.collectModuleConfig(moduleName, projectDir); } + + if (customizeModules.length > 0) { + await prompts.log.step('Module configuration complete'); + } } // Add metadata @@ -1239,7 +1246,6 @@ class ConfigCollector { hasOutput = true; const message = valueMessages[selectedValue]; - await prompts.log.message(''); for (const line of message.trim().split('\n')) { const trimmedLine = line.trim(); if (trimmedLine.endsWith(':') && !trimmedLine.startsWith(' ')) { From 382ab8ed45551029e67ee2142af4742dbee91709 Mon Sep 17 00:00:00 2001 From: Curtis Ide <60450113+cidemaxio@users.noreply.github.com> Date: Sun, 15 Feb 2026 14:44:28 -0700 Subject: [PATCH 14/17] Fix: --custom-content flag and workflow config.yaml copying (#1651) * fix custom install bug * fix manager.js * From PR #1624: added empty module.yaml handling (skip + warn) and removed paths from the config to match promptCustomContentSource() * fix: custom-content quick-update ENOENT, pass --custom-content through, add PR#1624 improvements to allow update installs to work using non-interactive mode --- tools/cli/installers/lib/core/installer.js | 155 +++++++++++--------- tools/cli/installers/lib/modules/manager.js | 6 +- tools/cli/lib/ui.js | 71 ++++++++- 3 files changed, 159 insertions(+), 73 deletions(-) diff --git a/tools/cli/installers/lib/core/installer.js b/tools/cli/installers/lib/core/installer.js index b7197d44d..8ee4960d8 100644 --- a/tools/cli/installers/lib/core/installer.js +++ b/tools/cli/installers/lib/core/installer.js @@ -527,28 +527,30 @@ class Installer { const cachedModules = await fs.readdir(cacheDir, { withFileTypes: true }); for (const cachedModule of cachedModules) { - if (cachedModule.isDirectory()) { - const moduleId = cachedModule.name; + const moduleId = cachedModule.name; + const cachedPath = path.join(cacheDir, moduleId); - // Skip if we already have this module from manifest - if (customModulePaths.has(moduleId)) { - continue; - } + // Skip if path doesn't exist (broken symlink, deleted dir) - avoids lstat ENOENT + if (!(await fs.pathExists(cachedPath)) || !cachedModule.isDirectory()) { + continue; + } - // Check if this is an external official module - skip cache for those - const isExternal = await this.moduleManager.isExternalModule(moduleId); - if (isExternal) { - // External modules are handled via cloneExternalModule, not from cache - continue; - } + // Skip if we already have this module from manifest + if (customModulePaths.has(moduleId)) { + continue; + } - const cachedPath = path.join(cacheDir, moduleId); + // Check if this is an external official module - skip cache for those + const isExternal = await this.moduleManager.isExternalModule(moduleId); + if (isExternal) { + // External modules are handled via cloneExternalModule, not from cache + continue; + } - // Check if this is actually a custom module (has module.yaml) - const moduleYamlPath = path.join(cachedPath, 'module.yaml'); - if (await fs.pathExists(moduleYamlPath)) { - customModulePaths.set(moduleId, cachedPath); - } + // Check if this is actually a custom module (has module.yaml) + const moduleYamlPath = path.join(cachedPath, 'module.yaml'); + if (await fs.pathExists(moduleYamlPath)) { + customModulePaths.set(moduleId, cachedPath); } } @@ -609,28 +611,30 @@ class Installer { const cachedModules = await fs.readdir(cacheDir, { withFileTypes: true }); for (const cachedModule of cachedModules) { - if (cachedModule.isDirectory()) { - const moduleId = cachedModule.name; + const moduleId = cachedModule.name; + const cachedPath = path.join(cacheDir, moduleId); - // Skip if we already have this module from manifest - if (customModulePaths.has(moduleId)) { - continue; - } + // Skip if path doesn't exist (broken symlink, deleted dir) - avoids lstat ENOENT + if (!(await fs.pathExists(cachedPath)) || !cachedModule.isDirectory()) { + continue; + } - // Check if this is an external official module - skip cache for those - const isExternal = await this.moduleManager.isExternalModule(moduleId); - if (isExternal) { - // External modules are handled via cloneExternalModule, not from cache - continue; - } + // Skip if we already have this module from manifest + if (customModulePaths.has(moduleId)) { + continue; + } - const cachedPath = path.join(cacheDir, moduleId); + // Check if this is an external official module - skip cache for those + const isExternal = await this.moduleManager.isExternalModule(moduleId); + if (isExternal) { + // External modules are handled via cloneExternalModule, not from cache + continue; + } - // Check if this is actually a custom module (has module.yaml) - const moduleYamlPath = path.join(cachedPath, 'module.yaml'); - if (await fs.pathExists(moduleYamlPath)) { - customModulePaths.set(moduleId, cachedPath); - } + // Check if this is actually a custom module (has module.yaml) + const moduleYamlPath = path.join(cachedPath, 'module.yaml'); + if (await fs.pathExists(moduleYamlPath)) { + customModulePaths.set(moduleId, cachedPath); } } @@ -949,12 +953,11 @@ class Installer { if (!isCustomModule && config._customModuleSources && config._customModuleSources.has(moduleName)) { customInfo = config._customModuleSources.get(moduleName); isCustomModule = true; - if ( - customInfo.sourcePath && - (customInfo.sourcePath.startsWith('_config') || customInfo.sourcePath.includes('_config/custom')) && - !customInfo.path - ) - customInfo.path = customInfo.sourcePath; + if (customInfo.sourcePath && !customInfo.path) { + customInfo.path = path.isAbsolute(customInfo.sourcePath) + ? customInfo.sourcePath + : path.join(bmadDir, customInfo.sourcePath); + } } // Finally check regular custom content @@ -2373,41 +2376,58 @@ class Installer { const configuredIdes = existingInstall.ides || []; const projectRoot = path.dirname(bmadDir); - // Get custom module sources from cache + // Get custom module sources: first from --custom-content (re-cache from source), then from cache const customModuleSources = new Map(); + if (config.customContent?.sources?.length > 0) { + for (const source of config.customContent.sources) { + if (source.id && source.path && (await fs.pathExists(source.path))) { + customModuleSources.set(source.id, { + id: source.id, + name: source.name || source.id, + sourcePath: source.path, + cached: false, // From CLI, will be re-cached + }); + } + } + } const cacheDir = path.join(bmadDir, '_config', 'custom'); if (await fs.pathExists(cacheDir)) { const cachedModules = await fs.readdir(cacheDir, { withFileTypes: true }); for (const cachedModule of cachedModules) { - if (cachedModule.isDirectory()) { - const moduleId = cachedModule.name; + const moduleId = cachedModule.name; + const cachedPath = path.join(cacheDir, moduleId); - // Skip if we already have this module from manifest - if (customModuleSources.has(moduleId)) { - continue; - } + // Skip if path doesn't exist (broken symlink, deleted dir) - avoids lstat ENOENT + if (!(await fs.pathExists(cachedPath))) { + continue; + } + if (!cachedModule.isDirectory()) { + continue; + } - // Check if this is an external official module - skip cache for those - const isExternal = await this.moduleManager.isExternalModule(moduleId); - if (isExternal) { - // External modules are handled via cloneExternalModule, not from cache - continue; - } + // Skip if we already have this module from manifest + if (customModuleSources.has(moduleId)) { + continue; + } - const cachedPath = path.join(cacheDir, moduleId); + // Check if this is an external official module - skip cache for those + const isExternal = await this.moduleManager.isExternalModule(moduleId); + if (isExternal) { + // External modules are handled via cloneExternalModule, not from cache + continue; + } - // Check if this is actually a custom module (has module.yaml) - const moduleYamlPath = path.join(cachedPath, 'module.yaml'); - if (await fs.pathExists(moduleYamlPath)) { - // For quick update, we always rebuild from cache - customModuleSources.set(moduleId, { - id: moduleId, - name: moduleId, // We'll read the actual name if needed - sourcePath: cachedPath, - cached: true, // Flag to indicate this is from cache - }); - } + // Check if this is actually a custom module (has module.yaml) + const moduleYamlPath = path.join(cachedPath, 'module.yaml'); + if (await fs.pathExists(moduleYamlPath)) { + // For quick update, we always rebuild from cache + customModuleSources.set(moduleId, { + id: moduleId, + name: moduleId, // We'll read the actual name if needed + sourcePath: cachedPath, + cached: true, // Flag to indicate this is from cache + }); } } } @@ -2544,6 +2564,7 @@ class Installer { _savedIdeConfigs: savedIdeConfigs, // Pass saved IDE configs to installer _customModuleSources: customModuleSources, // Pass custom module sources for updates _existingModules: installedModules, // Pass all installed modules for manifest generation + customContent: config.customContent, // Pass through for re-caching from source }; // Call the standard install method diff --git a/tools/cli/installers/lib/modules/manager.js b/tools/cli/installers/lib/modules/manager.js index b4acc3aef..f162593b7 100644 --- a/tools/cli/installers/lib/modules/manager.js +++ b/tools/cli/installers/lib/modules/manager.js @@ -734,8 +734,10 @@ class ModuleManager { continue; } - // Skip config.yaml templates - we'll generate clean ones with actual values - if (file === 'config.yaml' || file.endsWith('/config.yaml')) { + // Skip module root config.yaml only - generated by config collector with actual values + // Workflow-level config.yaml (e.g. workflows/orchestrate-story/config.yaml) must be copied + // for custom modules that use workflow-specific configuration + if (file === 'config.yaml') { continue; } diff --git a/tools/cli/lib/ui.js b/tools/cli/lib/ui.js index 224d147e3..ae99e300f 100644 --- a/tools/cli/lib/ui.js +++ b/tools/cli/lib/ui.js @@ -245,11 +245,48 @@ class UI { // Handle quick update separately if (actionType === 'quick-update') { - // Quick update doesn't install custom content - just updates existing modules + // Pass --custom-content through so installer can re-cache if cache is missing + let customContentForQuickUpdate = { hasCustomContent: false }; + if (options.customContent) { + const paths = options.customContent + .split(',') + .map((p) => p.trim()) + .filter(Boolean); + if (paths.length > 0) { + const customPaths = []; + const selectedModuleIds = []; + const sources = []; + for (const customPath of paths) { + const expandedPath = this.expandUserPath(customPath); + const validation = this.validateCustomContentPathSync(expandedPath); + if (validation) continue; + let moduleMeta; + try { + const moduleYamlPath = path.join(expandedPath, 'module.yaml'); + moduleMeta = require('yaml').parse(await fs.readFile(moduleYamlPath, 'utf-8')); + } catch { + continue; + } + if (!moduleMeta?.code) continue; + customPaths.push(expandedPath); + selectedModuleIds.push(moduleMeta.code); + sources.push({ path: expandedPath, id: moduleMeta.code, name: moduleMeta.name || moduleMeta.code }); + } + if (customPaths.length > 0) { + customContentForQuickUpdate = { + hasCustomContent: true, + selected: true, + sources, + selectedFiles: customPaths.map((p) => path.join(p, 'module.yaml')), + selectedModuleIds, + }; + } + } + } return { actionType: 'quick-update', directory: confirmedDirectory, - customContent: { hasCustomContent: false }, + customContent: customContentForQuickUpdate, skipPrompts: options.yes || false, }; } @@ -305,6 +342,7 @@ class UI { // Build custom content config similar to promptCustomContentSource const customPaths = []; const selectedModuleIds = []; + const sources = []; for (const customPath of paths) { const expandedPath = this.expandUserPath(customPath); @@ -326,6 +364,11 @@ class UI { continue; } + if (!moduleMeta) { + await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml is empty`); + continue; + } + if (!moduleMeta.code) { await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml missing 'code' field`); continue; @@ -333,6 +376,11 @@ class UI { customPaths.push(expandedPath); selectedModuleIds.push(moduleMeta.code); + sources.push({ + path: expandedPath, + id: moduleMeta.code, + name: moduleMeta.name || moduleMeta.code, + }); } if (customPaths.length > 0) { @@ -340,7 +388,9 @@ class UI { selectedCustomModules: selectedModuleIds, customContentConfig: { hasCustomContent: true, - paths: customPaths, + selected: true, + sources, + selectedFiles: customPaths.map((p) => path.join(p, 'module.yaml')), selectedModuleIds: selectedModuleIds, }, }; @@ -446,6 +496,7 @@ class UI { // Build custom content config similar to promptCustomContentSource const customPaths = []; const selectedModuleIds = []; + const sources = []; for (const customPath of paths) { const expandedPath = this.expandUserPath(customPath); @@ -467,6 +518,11 @@ class UI { continue; } + if (!moduleMeta) { + await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml is empty`); + continue; + } + if (!moduleMeta.code) { await prompts.log.warn(`Skipping custom content path: ${customPath} - module.yaml missing 'code' field`); continue; @@ -474,12 +530,19 @@ class UI { customPaths.push(expandedPath); selectedModuleIds.push(moduleMeta.code); + sources.push({ + path: expandedPath, + id: moduleMeta.code, + name: moduleMeta.name || moduleMeta.code, + }); } if (customPaths.length > 0) { customContentConfig = { hasCustomContent: true, - paths: customPaths, + selected: true, + sources, + selectedFiles: customPaths.map((p) => path.join(p, 'module.yaml')), selectedModuleIds: selectedModuleIds, }; } From ccaa88bb2d0406ffeda2c0cac96964bbf9402bae Mon Sep 17 00:00:00 2001 From: Brian Madison Date: Sun, 15 Feb 2026 17:29:12 -0600 Subject: [PATCH 15/17] feat: add Diataxis style fixer skill Adds bmad-os-diataxis-style-fix skill that automatically fixes documentation to comply with the Diataxis framework and BMad Method style guide rules. - Includes Diataxis framework primer (4 document types) - References main docs/_STYLE_GUIDE.md as single source of truth - Detects doc type by folder location - Applies fixes without committing (user reviews first) --- .../bmad-os-diataxis-style-fix/SKILL.md | 7 + .../prompts/instructions.md | 229 ++++++++++++++++++ 2 files changed, 236 insertions(+) create mode 100644 .claude/skills/bmad-os-diataxis-style-fix/SKILL.md create mode 100644 .claude/skills/bmad-os-diataxis-style-fix/prompts/instructions.md diff --git a/.claude/skills/bmad-os-diataxis-style-fix/SKILL.md b/.claude/skills/bmad-os-diataxis-style-fix/SKILL.md new file mode 100644 index 000000000..a874dc8ce --- /dev/null +++ b/.claude/skills/bmad-os-diataxis-style-fix/SKILL.md @@ -0,0 +1,7 @@ +--- +name: bmad-os-diataxis-style-fix +description: Fixes documentation to comply with Diataxis framework and BMad Method style guide rules +disable-model-invocation: true +--- + +Read `prompts/instructions.md` and execute. diff --git a/.claude/skills/bmad-os-diataxis-style-fix/prompts/instructions.md b/.claude/skills/bmad-os-diataxis-style-fix/prompts/instructions.md new file mode 100644 index 000000000..827e39115 --- /dev/null +++ b/.claude/skills/bmad-os-diataxis-style-fix/prompts/instructions.md @@ -0,0 +1,229 @@ +# Diataxis Style Fixer + +Automatically fixes documentation to comply with the Diataxis framework and BMad Method style guide. + +## CRITICAL RULES + +- **NEVER commit or push changes** — let the user review first +- **NEVER make destructive edits** — preserve all content, only fix formatting +- **Use Edit tool** — make targeted fixes, not full file rewrites +- **Show summary** — after fixing, list all changes made + +## Input + +Documentation file path or directory to fix. Defaults to `docs/` if not specified. + +## Step 1: Understand Diataxis Framework + +**Diataxis** is a documentation framework that categorizes content into four types based on two axes: + +| | **Learning** (oriented toward future) | **Doing** (oriented toward present) | +| -------------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | +| **Practical** | **Tutorials** — lessons that guide learners through achieving a specific goal | **How-to guides** — step-by-step instructions for solving a specific problem | +| **Conceptual** | **Explanation** — content that clarifies and describes underlying concepts | **Reference** — technical descriptions, organized for lookup | + +**Key principles:** +- Each document type serves a distinct user need +- Don't mix types — a tutorial shouldn't explain concepts deeply +- Focus on the user's goal, not exhaustive coverage +- Structure follows purpose (tutorials are linear, reference is scannable) + +## Step 2: Read the Style Guide + +Read the project's style guide at `docs/_STYLE_GUIDE.md` to understand all project-specific conventions. + +## Step 3: Detect Document Type + +Based on file location, determine the document type: + +| Location | Diataxis Type | +| -------------------- | -------------------- | +| `/docs/tutorials/` | Tutorial | +| `/docs/how-to/` | How-to guide | +| `/docs/explanation/` | Explanation | +| `/docs/reference/` | Reference | +| `/docs/glossary/` | Reference (glossary) | + +## Step 4: Find and Fix Issues + +For each markdown file, scan for issues and fix them: + +### Universal Fixes (All Doc Types) + +**Horizontal Rules (`---`)** +- Remove any `---` outside of YAML frontmatter +- Replace with `##` section headers or admonitions as appropriate + +**`####` Headers** +- Replace with bold text: `#### Header` → `**Header**` +- Or convert to admonition if it's a warning/notice + +**"Related" or "Next:" Sections** +- Remove entire section including links +- The sidebar handles navigation + +**Deeply Nested Lists** +- Break into sections with `##` headers +- Flatten to max 3 levels + +**Code Blocks for Dialogue/Examples** +- Convert to admonitions: + ``` + :::note[Example] + [content] + ::: + ``` + +**Bold Paragraph Callouts** +- Convert to admonitions with appropriate type + +**Too Many Admonitions** +- Limit to 1-2 per section (tutorials allow 3-4 per major section) +- Consolidate related admonitions +- Remove less critical ones if over limit + +**Table Cells / List Items > 2 Sentences** +- Break into multiple rows/cells +- Or shorten to 1-2 sentences + +**Header Budget Exceeded** +- Merge related sections +- Convert some `##` to `###` subsections +- Goal: 8-12 `##` per doc; 2-3 `###` per section + +### Type-Specific Fixes + +**Tutorials** (`/docs/tutorials/`) +- Ensure hook describes outcome in 1-2 sentences +- Add "What You'll Learn" bullet section if missing +- Add `:::note[Prerequisites]` if missing +- Add `:::tip[Quick Path]` TL;DR at top if missing +- Use tables for phases, commands, agents +- Add "What You've Accomplished" section if missing +- Add Quick Reference table if missing +- Add Common Questions section if missing +- Add Getting Help section if missing +- Add `:::tip[Key Takeaways]` at end if missing + +**How-To** (`/docs/how-to/`) +- Ensure hook starts with "Use the `X` workflow to..." +- Add "When to Use This" with 3-5 bullets if missing +- Add `:::note[Prerequisites]` if missing +- Ensure steps are numbered `###` with action verbs +- Add "What You Get" describing outputs if missing + +**Explanation** (`/docs/explanation/`) +- Ensure hook states what document explains +- Organize content into scannable `##` sections +- Add comparison tables for 3+ options +- Link to how-to guides for procedural questions +- Limit to 2-3 admonitions per document + +**Reference** (`/docs/reference/`) +- Ensure hook states what document references +- Ensure structure matches reference type +- Use consistent item structure throughout +- Use tables for structured/comparative data +- Link to explanation docs for conceptual depth +- Limit to 1-2 admonitions per document + +**Glossary** (`/docs/glossary/` or glossary files) +- Ensure categories as `##` headers +- Ensure terms in tables (not individual headers) +- Definitions 1-2 sentences max +- Bold term names in cells + +## Step 5: Apply Fixes + +For each file with issues: +1. Read the file +2. Use Edit tool for each fix +3. Track what was changed + +## Step 6: Summary + +After processing all files, output a summary: + +```markdown +# Style Fixes Applied + +**Files processed:** N +**Files modified:** N + +## Changes Made + +### `path/to/file.md` +- Removed horizontal rule at line 45 +- Converted `####` headers to bold text +- Added `:::tip[Quick Path]` admonition +- Consolidated 3 admonitions into 2 + +### `path/to/other.md` +- Removed "Related:" section +- Fixed table cell length (broke into 2 rows) + +## Review Required + +Please review the changes. When satisfied, commit and push as needed. +``` + +## Common Patterns + +**Converting `####` to bold:** +```markdown +#### Important Note +Some text here. +``` +→ +```markdown +**Important Note** + +Some text here. +``` + +**Removing horizontal rule:** +```markdown +Some content above. + +--- + +Some content below. +``` +→ +```markdown +Some content above. + +## [Descriptive Section Header] + +Some content below. +``` + +**Converting code block to admonition:** +```markdown +``` +User: What should I do? + +Agent: Run the workflow. +``` +``` +→ +```markdown +:::note[Example] + +**User:** What should I do? + +**Agent:** Run the workflow. + +::: +``` + +**Converting bold paragraph to admonition:** +```markdown +**IMPORTANT:** This is critical that you read this before proceeding. +``` +→ +```markdown +:::caution[Important] +This is critical that you read this before proceeding. +::: +``` From d6cc8b060a8c2335f0f283493c8846cf30cc6d64 Mon Sep 17 00:00:00 2001 From: Brian Madison Date: Sun, 15 Feb 2026 17:31:10 -0600 Subject: [PATCH 16/17] refactor: rename skill folders to bmad-os- prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Standardizes all skill folder names with bmad-os- prefix: - changelog-social → bmad-os-changelog-social - draft-changelog → bmad-os-draft-changelog - gh-triage → bmad-os-gh-triage - release-module → bmad-os-release-module --- .../{changelog-social => bmad-os-changelog-social}/SKILL.md | 0 .../examples/discord-example.md | 0 .../examples/linkedin-example.md | 0 .../examples/twitter-example.md | 0 .../skills/{draft-changelog => bmad-os-draft-changelog}/SKILL.md | 0 .../prompts/instructions.md | 0 .claude/skills/{gh-triage => bmad-os-gh-triage}/README.md | 0 .claude/skills/{gh-triage => bmad-os-gh-triage}/SKILL.md | 0 .../{gh-triage => bmad-os-gh-triage}/prompts/agent-prompt.md | 0 .../{gh-triage => bmad-os-gh-triage}/prompts/instructions.md | 0 .../skills/{release-module => bmad-os-release-module}/README.md | 0 .../skills/{release-module => bmad-os-release-module}/SKILL.md | 0 .../prompts/instructions.md | 0 13 files changed, 0 insertions(+), 0 deletions(-) rename .claude/skills/{changelog-social => bmad-os-changelog-social}/SKILL.md (100%) rename .claude/skills/{changelog-social => bmad-os-changelog-social}/examples/discord-example.md (100%) rename .claude/skills/{changelog-social => bmad-os-changelog-social}/examples/linkedin-example.md (100%) rename .claude/skills/{changelog-social => bmad-os-changelog-social}/examples/twitter-example.md (100%) rename .claude/skills/{draft-changelog => bmad-os-draft-changelog}/SKILL.md (100%) rename .claude/skills/{draft-changelog => bmad-os-draft-changelog}/prompts/instructions.md (100%) rename .claude/skills/{gh-triage => bmad-os-gh-triage}/README.md (100%) rename .claude/skills/{gh-triage => bmad-os-gh-triage}/SKILL.md (100%) rename .claude/skills/{gh-triage => bmad-os-gh-triage}/prompts/agent-prompt.md (100%) rename .claude/skills/{gh-triage => bmad-os-gh-triage}/prompts/instructions.md (100%) rename .claude/skills/{release-module => bmad-os-release-module}/README.md (100%) rename .claude/skills/{release-module => bmad-os-release-module}/SKILL.md (100%) rename .claude/skills/{release-module => bmad-os-release-module}/prompts/instructions.md (100%) diff --git a/.claude/skills/changelog-social/SKILL.md b/.claude/skills/bmad-os-changelog-social/SKILL.md similarity index 100% rename from .claude/skills/changelog-social/SKILL.md rename to .claude/skills/bmad-os-changelog-social/SKILL.md diff --git a/.claude/skills/changelog-social/examples/discord-example.md b/.claude/skills/bmad-os-changelog-social/examples/discord-example.md similarity index 100% rename from .claude/skills/changelog-social/examples/discord-example.md rename to .claude/skills/bmad-os-changelog-social/examples/discord-example.md diff --git a/.claude/skills/changelog-social/examples/linkedin-example.md b/.claude/skills/bmad-os-changelog-social/examples/linkedin-example.md similarity index 100% rename from .claude/skills/changelog-social/examples/linkedin-example.md rename to .claude/skills/bmad-os-changelog-social/examples/linkedin-example.md diff --git a/.claude/skills/changelog-social/examples/twitter-example.md b/.claude/skills/bmad-os-changelog-social/examples/twitter-example.md similarity index 100% rename from .claude/skills/changelog-social/examples/twitter-example.md rename to .claude/skills/bmad-os-changelog-social/examples/twitter-example.md diff --git a/.claude/skills/draft-changelog/SKILL.md b/.claude/skills/bmad-os-draft-changelog/SKILL.md similarity index 100% rename from .claude/skills/draft-changelog/SKILL.md rename to .claude/skills/bmad-os-draft-changelog/SKILL.md diff --git a/.claude/skills/draft-changelog/prompts/instructions.md b/.claude/skills/bmad-os-draft-changelog/prompts/instructions.md similarity index 100% rename from .claude/skills/draft-changelog/prompts/instructions.md rename to .claude/skills/bmad-os-draft-changelog/prompts/instructions.md diff --git a/.claude/skills/gh-triage/README.md b/.claude/skills/bmad-os-gh-triage/README.md similarity index 100% rename from .claude/skills/gh-triage/README.md rename to .claude/skills/bmad-os-gh-triage/README.md diff --git a/.claude/skills/gh-triage/SKILL.md b/.claude/skills/bmad-os-gh-triage/SKILL.md similarity index 100% rename from .claude/skills/gh-triage/SKILL.md rename to .claude/skills/bmad-os-gh-triage/SKILL.md diff --git a/.claude/skills/gh-triage/prompts/agent-prompt.md b/.claude/skills/bmad-os-gh-triage/prompts/agent-prompt.md similarity index 100% rename from .claude/skills/gh-triage/prompts/agent-prompt.md rename to .claude/skills/bmad-os-gh-triage/prompts/agent-prompt.md diff --git a/.claude/skills/gh-triage/prompts/instructions.md b/.claude/skills/bmad-os-gh-triage/prompts/instructions.md similarity index 100% rename from .claude/skills/gh-triage/prompts/instructions.md rename to .claude/skills/bmad-os-gh-triage/prompts/instructions.md diff --git a/.claude/skills/release-module/README.md b/.claude/skills/bmad-os-release-module/README.md similarity index 100% rename from .claude/skills/release-module/README.md rename to .claude/skills/bmad-os-release-module/README.md diff --git a/.claude/skills/release-module/SKILL.md b/.claude/skills/bmad-os-release-module/SKILL.md similarity index 100% rename from .claude/skills/release-module/SKILL.md rename to .claude/skills/bmad-os-release-module/SKILL.md diff --git a/.claude/skills/release-module/prompts/instructions.md b/.claude/skills/bmad-os-release-module/prompts/instructions.md similarity index 100% rename from .claude/skills/release-module/prompts/instructions.md rename to .claude/skills/bmad-os-release-module/prompts/instructions.md From d4b4bdfa12615ce9292d6ea5bea7b4f251feed2d Mon Sep 17 00:00:00 2001 From: Brian Madison Date: Sun, 15 Feb 2026 17:32:05 -0600 Subject: [PATCH 17/17] docs: improve project-context documentation and fix folder structure - Add explanation/how-to docs for project-context.md feature - Update workflow-map Context Management section with comprehensive guidance - Fix folder structure examples to show proper nested subdirectories (planning-artifacts/ and implementation-artifacts/ under _bmad-output/) - Update established-projects.md with project-context creation step - Standardize terminology: use "existing projects" instead of "brownfield" --- docs/_STYLE_GUIDE.md | 7 +- docs/explanation/project-context.md | 157 +++++++++++++++++++++++++++ docs/how-to/established-projects.md | 27 ++++- docs/how-to/project-context.md | 136 +++++++++++++++++++++++ docs/how-to/shard-large-documents.md | 4 +- docs/reference/workflow-map.md | 48 ++++++-- docs/tutorials/getting-started.md | 20 +++- 7 files changed, 380 insertions(+), 19 deletions(-) create mode 100644 docs/explanation/project-context.md create mode 100644 docs/how-to/project-context.md diff --git a/docs/_STYLE_GUIDE.md b/docs/_STYLE_GUIDE.md index f9b38ed86..c6e9eff58 100644 --- a/docs/_STYLE_GUIDE.md +++ b/docs/_STYLE_GUIDE.md @@ -75,9 +75,12 @@ Show in "What You've Accomplished" sections: ````md ``` your-project/ -├── _bmad/ # BMad configuration +├── _bmad/ # BMad configuration ├── _bmad-output/ -│ ├── PRD.md # Your requirements document +│ ├── planning-artifacts/ +│ │ └── PRD.md # Your requirements document +│ ├── implementation-artifacts/ +│ └── project-context.md # Implementation rules (optional) └── ... ``` ```` diff --git a/docs/explanation/project-context.md b/docs/explanation/project-context.md new file mode 100644 index 000000000..6522b92a5 --- /dev/null +++ b/docs/explanation/project-context.md @@ -0,0 +1,157 @@ +--- +title: "Project Context" +description: How project-context.md guides AI agents with your project's rules and preferences +sidebar: + order: 7 +--- + +The `project-context.md` file is your project's implementation guide for AI agents. Similar to a "constitution" in other development systems, it captures the rules, patterns, and preferences that ensure consistent code generation across all workflows. + +## What It Does + +AI agents make implementation decisions constantly — which patterns to follow, how to structure code, what conventions to use. Without clear guidance, they may: +- Follow generic best practices that don't match your codebase +- Make inconsistent decisions across different stories +- Miss project-specific requirements or constraints + +The `project-context.md` file solves this by documenting what agents need to know in a concise, LLM-optimized format. + +## How It Works + +Every implementation workflow automatically loads `project-context.md` if it exists. The architect workflow also loads it to respect your technical preferences when designing the architecture. + +**Loaded by these workflows:** +- `create-architecture` — respects technical preferences during solutioning +- `create-story` — informs story creation with project patterns +- `dev-story` — guides implementation decisions +- `code-review` — validates against project standards +- `quick-dev` — applies patterns when implementing tech-specs +- `sprint-planning`, `retrospective`, `correct-course` — provides project-wide context + +## When to Create It + +The `project-context.md` file is useful at any stage of a project: + +| Scenario | When to Create | Purpose | +|----------|----------------|---------| +| **New project, before architecture** | Manually, before `create-architecture` | Document your technical preferences so the architect respects them | +| **New project, after architecture** | Via `generate-project-context` or manually | Capture architecture decisions for implementation agents | +| **Existing project** | Via `generate-project-context` | Discover existing patterns so agents follow established conventions | +| **Quick Flow project** | Before or during `quick-dev` | Ensure quick implementation respects your patterns | + +:::tip[Recommended] +For new projects, create it manually before architecture if you have strong technical preferences. Otherwise, generate it after architecture to capture those decisions. +::: + +## What Goes In It + +The file has two main sections: + +### Technology Stack & Versions + +Documents the frameworks, languages, and tools your project uses with specific versions: + +```markdown +## Technology Stack & Versions + +- Node.js 20.x, TypeScript 5.3, React 18.2 +- State: Zustand (not Redux) +- Testing: Vitest, Playwright, MSW +- Styling: Tailwind CSS with custom design tokens +``` + +### Critical Implementation Rules + +Documents patterns and conventions that agents might otherwise miss: + +```markdown +## Critical Implementation Rules + +**TypeScript Configuration:** +- Strict mode enabled — no `any` types without explicit approval +- Use `interface` for public APIs, `type` for unions/intersections + +**Code Organization:** +- Components in `/src/components/` with co-located `.test.tsx` +- Utilities in `/src/lib/` for reusable pure functions +- API calls use the `apiClient` singleton — never fetch directly + +**Testing Patterns:** +- Unit tests focus on business logic, not implementation details +- Integration tests use MSW to mock API responses +- E2E tests cover critical user journeys only + +**Framework-Specific:** +- All async operations use the `handleError` wrapper for consistent error handling +- Feature flags accessed via `featureFlag()` from `@/lib/flags` +- New routes follow the file-based routing pattern in `/src/app/` +``` + +Focus on what's **unobvious** — things agents might not infer from reading code snippets. Don't document standard practices that apply universally. + +## Creating the File + +You have three options: + +### Manual Creation + +Create the file at `_bmad-output/project-context.md` and add your rules: + +```bash +# In your project root +mkdir -p _bmad-output +touch _bmad-output/project-context.md +``` + +Edit it with your technology stack and implementation rules. The architect and implementation workflows will automatically find and load it. + +### Generate After Architecture + +Run the `generate-project-context` workflow after completing your architecture: + +```bash +/bmad-bmm-generate-project-context +``` + +This scans your architecture document and project files to generate a context file capturing the decisions made. + +### Generate for Existing Projects + +For existing projects, run `generate-project-context` to discover existing patterns: + +```bash +/bmad-bmm-generate-project-context +``` + +The workflow analyzes your codebase to identify conventions, then generates a context file you can review and refine. + +## Why It Matters + +Without `project-context.md`, agents make assumptions that may not match your project: + +| Without Context | With Context | +|----------------|--------------| +| Uses generic patterns | Follows your established conventions | +| Inconsistent style across stories | Consistent implementation | +| May miss project-specific constraints | Respects all technical requirements | +| Each agent decides independently | All agents align with same rules | + +This is especially important for: +- **Quick Flow** — skips PRD and architecture, so context file fills the gap +- **Team projects** — ensures all agents follow the same standards +- **Existing projects** — prevents breaking established patterns + +## Editing and Updating + +The `project-context.md` file is a living document. Update it when: + +- Architecture decisions change +- New conventions are established +- Patterns evolve during implementation +- You identify gaps from agent behavior + +You can edit it manually at any time, or re-run `generate-project-context` to update it after significant changes. + +:::note[File Location] +The default location is `_bmad-output/project-context.md`. Workflows search for it there, and also check `**/project-context.md` anywhere in your project. +::: diff --git a/docs/how-to/established-projects.md b/docs/how-to/established-projects.md index 5f1066a51..91b709b9d 100644 --- a/docs/how-to/established-projects.md +++ b/docs/how-to/established-projects.md @@ -5,7 +5,7 @@ sidebar: order: 6 --- -Use BMad Method effectively when working on existing projects and legacy codebases, sometimes also referred to as brownfield projects. +Use BMad Method effectively when working on existing projects and legacy codebases. This guide covers the essential workflow for onboarding to existing projects with BMad Method. @@ -23,7 +23,30 @@ If you have completed all PRD epics and stories through the BMad process, clean - `_bmad-output/planning-artifacts/` - `_bmad-output/implementation-artifacts/` -## Step 2: Maintain Quality Project Documentation +## Step 2: Create Project Context + +:::tip[Recommended for Existing Projects] +Generate `project-context.md` to capture your existing codebase patterns and conventions. This ensures AI agents follow your established practices when implementing changes. +::: + +Run the generate project context workflow: + +```bash +/bmad-bmm-generate-project-context +``` + +This scans your codebase to identify: +- Technology stack and versions +- Code organization patterns +- Naming conventions +- Testing approaches +- Framework-specific patterns + +You can review and refine the generated file, or create it manually at `_bmad-output/project-context.md` if you prefer. + +[Learn more about project context](../explanation/project-context.md) + +## Step 3: Maintain Quality Project Documentation Your `docs/` folder should contain succinct, well-organized documentation that accurately represents your project: diff --git a/docs/how-to/project-context.md b/docs/how-to/project-context.md new file mode 100644 index 000000000..105906098 --- /dev/null +++ b/docs/how-to/project-context.md @@ -0,0 +1,136 @@ +--- +title: "Manage Project Context" +description: Create and maintain project-context.md to guide AI agents +sidebar: + order: 7 +--- + +Use the `project-context.md` file to ensure AI agents follow your project's technical preferences and implementation rules throughout all workflows. + +:::note[Prerequisites] +- BMad Method installed +- Understanding of your project's technology stack and conventions +::: + +## When to Use This + +- You have strong technical preferences before starting architecture +- You've completed architecture and want to capture decisions for implementation +- You're working on an existing codebase with established patterns +- You notice agents making inconsistent decisions across stories + +## Step 1: Choose Your Approach + +**Manual creation** — Best when you know exactly what rules you want to document + +**Generate after architecture** — Best for capturing decisions made during solutioning + +**Generate for existing projects** — Best for discovering patterns in existing codebases + +## Step 2: Create the File + +### Option A: Manual Creation + +Create the file at `_bmad-output/project-context.md`: + +```bash +mkdir -p _bmad-output +touch _bmad-output/project-context.md +``` + +Add your technology stack and implementation rules: + +```markdown +--- +project_name: 'MyProject' +user_name: 'YourName' +date: '2026-02-15' +sections_completed: ['technology_stack', 'critical_rules'] +--- + +# Project Context for AI Agents + +## Technology Stack & Versions + +- Node.js 20.x, TypeScript 5.3, React 18.2 +- State: Zustand +- Testing: Vitest, Playwright +- Styling: Tailwind CSS + +## Critical Implementation Rules + +**TypeScript:** +- Strict mode enabled, no `any` types +- Use `interface` for public APIs, `type` for unions + +**Code Organization:** +- Components in `/src/components/` with co-located tests +- API calls use `apiClient` singleton — never fetch directly + +**Testing:** +- Unit tests focus on business logic +- Integration tests use MSW for API mocking +``` + +### Option B: Generate After Architecture + +Run the workflow in a fresh chat: + +```bash +/bmad-bmm-generate-project-context +``` + +The workflow scans your architecture document and project files to generate a context file capturing the decisions made. + +### Option C: Generate for Existing Projects + +For existing projects, run: + +```bash +/bmad-bmm-generate-project-context +``` + +The workflow analyzes your codebase to identify conventions, then generates a context file you can review and refine. + +## Step 3: Verify Content + +Review the generated file and ensure it captures: + +- Correct technology versions +- Your actual conventions (not generic best practices) +- Rules that prevent common mistakes +- Framework-specific patterns + +Edit manually to add anything missing or remove inaccuracies. + +## What You Get + +A `project-context.md` file that: + +- Ensures all agents follow the same conventions +- Prevents inconsistent decisions across stories +- Captures architecture decisions for implementation +- Serves as a reference for your project's patterns and rules + +## Tips + +:::tip[Focus on the Unobvious] +Document patterns agents might miss such as "Use JSDoc style comments on every public class, function and variable", not universal practices like "use meaningful variable names" which LLMs know at this point. +::: + +:::tip[Keep It Lean] +This file is loaded by every implementation workflow. Long files waste context. Do not include content that only applies to narrow scope or specific stories or features. +::: + +:::tip[Update as Needed] +Edit manually when patterns change, or re-generate after significant architecture changes. +::: + +:::tip[Works for All Project Types] +Just as useful for Quick Flow as for full BMad Method projects. +::: + +## Next Steps + +- [**Project Context Explanation**](../explanation/project-context.md) — Learn more about how it works +- [**Workflow Map**](../reference/workflow-map.md) — See which workflows load project context diff --git a/docs/how-to/shard-large-documents.md b/docs/how-to/shard-large-documents.md index e58e37946..b10c64fb8 100644 --- a/docs/how-to/shard-large-documents.md +++ b/docs/how-to/shard-large-documents.md @@ -23,11 +23,11 @@ Document sharding splits large markdown files into smaller, organized files base ```text Before Sharding: -docs/ +_bmad-output/planning-artifacts/ └── PRD.md (large 50k token file) After Sharding: -docs/ +_bmad-output/planning-artifacts/ └── prd/ ├── index.md # Table of contents with descriptions ├── overview.md # Section 1 diff --git a/docs/reference/workflow-map.md b/docs/reference/workflow-map.md index fc38b69ee..5f89b6dba 100644 --- a/docs/reference/workflow-map.md +++ b/docs/reference/workflow-map.md @@ -77,14 +77,46 @@ Skip phases 1-3 for small, well-understood work. Each document becomes context for the next phase. The PRD tells the architect what constraints matter. The architecture tells the dev agent which patterns to follow. Story files give focused, complete context for implementation. Without this structure, agents make inconsistent decisions. -For established projects, `document-project` creates or updates `project-context.md` - what exists in the codebase and the rules all implementation workflows must observe. Run it just before Phase 4, and again when something significant changes - structure, architecture, or those rules. You can also edit `project-context.md` by hand. +### Project Context -All implementation workflows load `project-context.md` if it exists. Additional context per workflow: +:::tip[Recommended] +Create `project-context.md` to ensure AI agents follow your project's rules and preferences. This file works like a constitution for your project — it guides implementation decisions across all workflows. +::: -| Workflow | Also Loads | -| -------------- | ---------------------------- | +**When to create it:** + +| Scenario | Approach | +|----------|----------| +| Before architecture (manual) | Document technical preferences you want the architect to respect | +| After architecture | Generate it to capture decisions made during solutioning | +| Existing projects | Run `generate-project-context` to discover established patterns | +| Quick Flow | Create before `quick-dev` to ensure consistent implementation | + +**How to create it:** + +- **Manually** — Create `_bmad-output/project-context.md` with your technology stack and implementation rules +- **Generate it** — Run `/bmad-bmm-generate-project-context` to auto-generate from your architecture or codebase + +**What workflows load it:** + +| Workflow | Purpose | +|----------|---------| +| `create-architecture` | Respects technical preferences when designing | +| `create-story` | Informs story creation with project patterns | +| `dev-story` | Guides implementation decisions | +| `code-review` | Validates against project standards | +| `quick-dev` | Applies patterns when implementing | + +[**Learn more about project-context.md**](../explanation/project-context.md) + +### Additional Context by Workflow + +Beyond `project-context.md`, each workflow loads specific documents: + +| Workflow | Also Loads | +|----------|------------| | `create-story` | epics, PRD, architecture, UX | -| `dev-story` | story file | -| `code-review` | architecture, story file | -| `quick-spec` | planning docs (if exist) | -| `quick-dev` | tech-spec | +| `dev-story` | story file | +| `code-review` | architecture, story file | +| `quick-spec` | planning docs (if exist) | +| `quick-dev` | tech-spec | diff --git a/docs/tutorials/getting-started.md b/docs/tutorials/getting-started.md index f8dbdad2f..279d37d4d 100644 --- a/docs/tutorials/getting-started.md +++ b/docs/tutorials/getting-started.md @@ -79,6 +79,12 @@ Always start a fresh chat for each workflow. This prevents context limitations f Work through phases 1-3. **Use fresh chats for each workflow.** +:::tip[Project Context (Optional)] +Before starting, consider creating `project-context.md` to document your technical preferences and implementation rules. This ensures all AI agents follow your conventions throughout the project. + +Create it manually at `_bmad-output/project-context.md` or generate it after architecture using `/bmad-bmm-generate-project-context`. [Learn more](../explanation/project-context.md). +::: + ### Phase 1: Analysis (Optional) All workflows in this phase are optional: @@ -155,12 +161,15 @@ Your project now has: ```text your-project/ -├── _bmad/ # BMad configuration +├── _bmad/ # BMad configuration ├── _bmad-output/ -│ ├── PRD.md # Your requirements document -│ ├── architecture.md # Technical decisions -│ ├── epics/ # Epic and story files -│ └── sprint-status.yaml # Sprint tracking +│ ├── planning-artifacts/ +│ │ ├── PRD.md # Your requirements document +│ │ ├── architecture.md # Technical decisions +│ │ └── epics/ # Epic and story files +│ ├── implementation-artifacts/ +│ │ └── sprint-status.yaml # Sprint tracking +│ └── project-context.md # Implementation rules (optional) └── ... ``` @@ -171,6 +180,7 @@ your-project/ | `help` | `/bmad-help` | Any | Get guidance on what to do next | | `prd` | `/bmad-bmm-create-prd` | PM | Create Product Requirements Document | | `create-architecture` | `/bmad-bmm-create-architecture` | Architect | Create architecture document | +| `generate-project-context` | `/bmad-bmm-generate-project-context` | Analyst | Create project context file | | `create-epics-and-stories` | `/bmad-bmm-create-epics-and-stories` | PM | Break down PRD into epics | | `check-implementation-readiness` | `/bmad-bmm-check-implementation-readiness` | Architect | Validate planning cohesion | | `sprint-planning` | `/bmad-bmm-sprint-planning` | SM | Initialize sprint tracking |