_cfg -> _config

This commit is contained in:
Brian Madison 2025-12-13 19:41:09 +08:00
parent ac5fa5c23f
commit ae9851acab
37 changed files with 192 additions and 130 deletions

View File

@ -9,7 +9,7 @@ Customize BMad agents without modifying core files. All customizations persist t
After installation, find agent customization files in: After installation, find agent customization files in:
``` ```
_bmad/_cfg/agents/ _bmad/_config/agents/
├── core-bmad-master.customize.yaml ├── core-bmad-master.customize.yaml
├── bmm-dev.customize.yaml ├── bmm-dev.customize.yaml
├── bmm-pm.customize.yaml ├── bmm-pm.customize.yaml
@ -119,7 +119,7 @@ prompts:
**Example 1: Customize Developer Agent for TDD** **Example 1: Customize Developer Agent for TDD**
```yaml ```yaml
# _bmad/_cfg/agents/bmm-dev.customize.yaml # _bmad/_config/agents/bmm-dev.customize.yaml
agent: agent:
metadata: metadata:
name: 'TDD Developer' name: 'TDD Developer'
@ -135,7 +135,7 @@ critical_actions:
**Example 2: Add Custom Deployment Workflow** **Example 2: Add Custom Deployment Workflow**
```yaml ```yaml
# _bmad/_cfg/agents/bmm-dev.customize.yaml # _bmad/_config/agents/bmm-dev.customize.yaml
menu: menu:
- trigger: deploy-staging - trigger: deploy-staging
workflow: '{project-root}/_bmad/deploy-staging.yaml' workflow: '{project-root}/_bmad/deploy-staging.yaml'
@ -148,7 +148,7 @@ menu:
**Example 3: Multilingual Product Manager** **Example 3: Multilingual Product Manager**
```yaml ```yaml
# _bmad/_cfg/agents/bmm-pm.customize.yaml # _bmad/_config/agents/bmm-pm.customize.yaml
persona: persona:
role: 'Bilingual Product Manager' role: 'Bilingual Product Manager'
identity: 'Expert in US and LATAM markets' identity: 'Expert in US and LATAM markets'
@ -166,15 +166,15 @@ memories:
- **Start Small:** Customize one section at a time and rebuild to test - **Start Small:** Customize one section at a time and rebuild to test
- **Backup:** Copy customization files before major changes - **Backup:** Copy customization files before major changes
- **Update-Safe:** Your customizations in `_cfg/` survive all BMad updates - **Update-Safe:** Your customizations in `_config/` survive all BMad updates
- **Per-Project:** Customization files are per-project, not global - **Per-Project:** Customization files are per-project, not global
- **Version Control:** Consider committing `_cfg/` to share customizations with your team - **Version Control:** Consider committing `_config/` to share customizations with your team
## Module vs. Global Config ## Module vs. Global Config
**Module-Level (Recommended):** **Module-Level (Recommended):**
- Customize agents per-project in `_bmad/_cfg/agents/` - Customize agents per-project in `_bmad/_config/agents/`
- Different projects can have different agent behaviors - Different projects can have different agent behaviors
**Global Config (Coming Soon):** **Global Config (Coming Soon):**

View File

@ -28,7 +28,7 @@ BMad Core is a modular AI agent framework with intelligent installation, platfor
``` ```
project-root/ project-root/
├── _bmad/ # Centralized installation ├── _bmad/ # Centralized installation
│ ├── _cfg/ # Configuration │ ├── _config/ # Configuration
│ │ ├── agents/ # Agent configs │ │ ├── agents/ # Agent configs
│ │ └── agent-manifest.csv # Agent manifest │ │ └── agent-manifest.csv # Agent manifest
│ ├── core/ # Core module │ ├── core/ # Core module
@ -265,7 +265,7 @@ Extractable config nodes:
</agent> </agent>
``` ```
Generated in: `bmad/_cfg/agents/{module}-{agent}.md` Generated in: `bmad/_config/agents/{module}-{agent}.md`
## Troubleshooting ## Troubleshooting
@ -290,7 +290,7 @@ bmad status -v # Detailed status
### Best Practices ### Best Practices
1. Run from project root 1. Run from project root
2. Backup `_bmad/_cfg/` before updates 2. Backup `_bmad/_config/` before updates
3. Use interactive mode for guidance 3. Use interactive mode for guidance
4. Review generated configs post-install 4. Review generated configs post-install

View File

@ -68,7 +68,7 @@ your-project/
├── bmm/ # BMad Method (software/game dev) ├── bmm/ # BMad Method (software/game dev)
├── bmb/ # BMad Builder (create agents/workflows) ├── bmb/ # BMad Builder (create agents/workflows)
├── cis/ # Creative Intelligence Suite ├── cis/ # Creative Intelligence Suite
└── _cfg/ # Your customizations └── _config/ # Your customizations
└── agents/ # Agent customization files └── agents/ # Agent customization files
``` ```
@ -114,11 +114,11 @@ In v4, you may have modified agent files directly in `_bmad-*` folders.
### v6 Agent Customization ### v6 Agent Customization
**All customizations** now go in `_bmad/_cfg/agents/` using customize files: **All customizations** now go in `_bmad/_config/agents/` using customize files:
**Example: Renaming an agent and changing communication style** **Example: Renaming an agent and changing communication style**
File: `_bmad/_cfg/agents/bmm-pm.customize.yaml` File: `_bmad/_config/agents/bmm-pm.customize.yaml`
```yaml ```yaml
# Customize the PM agent # Customize the PM agent
@ -134,7 +134,7 @@ persona:
**How it works:** **How it works:**
- Base agent: `_bmad/bmm/agents/pm.md` - Base agent: `_bmad/bmm/agents/pm.md`
- Customization: `_bmad/_cfg/agents/bmm-pm.customize.yaml` - Customization: `_bmad/_config/agents/bmm-pm.customize.yaml`
- Result: Agent uses your custom name and style, but updates don't overwrite your changes - Result: Agent uses your custom name and style, but updates don't overwrite your changes
--- ---
@ -214,7 +214,7 @@ Since you are migrating an existing project from v4, it's most likely **Level 3
- [ ] v4 folders backed up to `v4-backup/` - [ ] v4 folders backed up to `v4-backup/`
- [ ] v6 installed to `_bmad/` folder - [ ] v6 installed to `_bmad/` folder
- [ ] `workflow-init` run with correct project level selected - [ ] `workflow-init` run with correct project level selected
- [ ] Agent customizations migrated to `_bmad/_cfg/agents/` if needed - [ ] Agent customizations migrated to `_bmad/_config/agents/` if needed
- [ ] IDE integration working (test by listing agents) - [ ] IDE integration working (test by listing agents)
- [ ] For active development: `sprint-planning` workflow executed - [ ] For active development: `sprint-planning` workflow executed

View File

@ -336,7 +336,7 @@ Agents adapt their menus based on project phase and available workflows.
Customize agents using the [Agent Customization Guide](./agent-customization-guide.md): Customize agents using the [Agent Customization Guide](./agent-customization-guide.md):
1. Edit `_bmad/_cfg/agents/<agent>.customize.yaml` 1. Edit `_bmad/_config/agents/<agent>.customize.yaml`
2. Rebuild: `npx bmad-method build <agent-name>` 2. Rebuild: `npx bmad-method build <agent-name>`
3. Generate bundles: `npm run bundle` 3. Generate bundles: `npm run bundle`

View File

@ -24,11 +24,11 @@ agent:
# Agent menu items # Agent menu items
menu: menu:
- trigger: "list-tasks" - trigger: "list-tasks"
action: "list all tasks from {project-root}/_bmad/_cfg/task-manifest.csv" action: "list all tasks from {project-root}/_bmad/_config/task-manifest.csv"
description: "List Available Tasks" description: "List Available Tasks"
- trigger: "list-workflows" - trigger: "list-workflows"
action: "list all workflows from {project-root}/_bmad/_cfg/workflow-manifest.csv" action: "list all workflows from {project-root}/_bmad/_config/workflow-manifest.csv"
description: "List Workflows" description: "List Workflows"
- trigger: "party-mode" - trigger: "party-mode"

View File

@ -1,6 +1,6 @@
<task id="_bmad/core/tasks/advanced-elicitation.xml" name="Advanced Elicitation" standalone="true" <task id="_bmad/core/tasks/advanced-elicitation.xml" name="Advanced Elicitation" standalone="true"
methods="{project-root}/_bmad/core/tasks/advanced-elicitation-methods.csv" methods="{project-root}/_bmad/core/tasks/advanced-elicitation-methods.csv"
agent-party="{project-root}/_bmad/_cfg/agent-manifest.csv"> agent-party="{project-root}/_bmad/_config/agent-manifest.csv">
<llm critical="true"> <llm critical="true">
<i>MANDATORY: Execute ALL steps in the flow section IN EXACT ORDER</i> <i>MANDATORY: Execute ALL steps in the flow section IN EXACT ORDER</i>
<i>DO NOT skip steps or change the sequence</i> <i>DO NOT skip steps or change the sequence</i>

View File

@ -18,7 +18,7 @@
## CONTEXT BOUNDARIES: ## CONTEXT BOUNDARIES:
- Agent manifest CSV is available at `{project-root}/_bmad/_cfg/agent-manifest.csv` - Agent manifest CSV is available at `{project-root}/_bmad/_config/agent-manifest.csv`
- User configuration from config.yaml is loaded and resolved - User configuration from config.yaml is loaded and resolved
- Party mode is standalone interactive workflow - Party mode is standalone interactive workflow
- All agent data is available for conversation orchestration - All agent data is available for conversation orchestration
@ -37,7 +37,7 @@ Begin agent loading process:
**Agent Manifest Loading:**" **Agent Manifest Loading:**"
Load and parse the agent manifest CSV from `{project-root}/_bmad/_cfg/agent-manifest.csv` Load and parse the agent manifest CSV from `{project-root}/_bmad/_config/agent-manifest.csv`
### 2. Extract Agent Data ### 2. Extract Agent Data

View File

@ -32,12 +32,12 @@ Load config from `{project-root}/_bmad/core/config.yaml` and resolve:
- `project_name`, `output_folder`, `user_name` - `project_name`, `output_folder`, `user_name`
- `communication_language`, `document_output_language`, `user_skill_level` - `communication_language`, `document_output_language`, `user_skill_level`
- `date` as a system-generated value - `date` as a system-generated value
- Agent manifest path: `{project-root}/_bmad/_cfg/agent-manifest.csv` - Agent manifest path: `{project-root}/_bmad/_config/agent-manifest.csv`
### Paths ### Paths
- `installed_path` = `{project-root}/_bmad/core/workflows/party-mode` - `installed_path` = `{project-root}/_bmad/core/workflows/party-mode`
- `agent_manifest_path` = `{project-root}/_bmad/_cfg/agent-manifest.csv` - `agent_manifest_path` = `{project-root}/_bmad/_config/agent-manifest.csv`
- `standalone_mode` = `true` (party mode is an interactive workflow) - `standalone_mode` = `true` (party mode is an interactive workflow)
--- ---

View File

@ -132,7 +132,7 @@ Universal attribute for supplementary information.
menu: menu:
- trigger: team-standup - trigger: team-standup
exec: '{project-root}/_bmad/bmm/tasks/standup.xml' exec: '{project-root}/_bmad/bmm/tasks/standup.xml'
data: '{project-root}/_bmad/_cfg/agent-manifest.csv' data: '{project-root}/_bmad/_config/agent-manifest.csv'
description: 'Run team standup' description: 'Run team standup'
- trigger: analyze-metrics - trigger: analyze-metrics

View File

@ -63,7 +63,7 @@ agent:
- trigger: with-data - trigger: with-data
exec: '{project-root}/_bmad/{module-code}/tasks/{task-name}.xml' exec: '{project-root}/_bmad/{module-code}/tasks/{task-name}.xml'
data: '{project-root}/_bmad/_cfg/agent-manifest.csv' data: '{project-root}/_bmad/_config/agent-manifest.csv'
description: 'Execute task with data file' description: 'Execute task with data file'
``` ```
@ -136,7 +136,7 @@ Combines task execution with template file.
menu: menu:
- trigger: team-standup - trigger: team-standup
exec: '{project-root}/_bmad/bmm/tasks/standup.xml' exec: '{project-root}/_bmad/bmm/tasks/standup.xml'
data: '{project-root}/_bmad/_cfg/agent-manifest.csv' data: '{project-root}/_bmad/_config/agent-manifest.csv'
description: 'Run team standup with agent roster' description: 'Run team standup with agent roster'
``` ```

View File

@ -10,7 +10,7 @@ thisStepFile: '{workflow_path}/steps/step-09-customize.md'
nextStepFile: '{workflow_path}/steps/step-10-build-tools.md' nextStepFile: '{workflow_path}/steps/step-10-build-tools.md'
workflowFile: '{workflow_path}/workflow.md' workflowFile: '{workflow_path}/workflow.md'
outputFile: '{output_folder}/agent-customization-{project_name}.md' outputFile: '{output_folder}/agent-customization-{project_name}.md'
configOutputFile: '{project-root}/_bmad/_cfg/agents/{target_module}-{agent_filename}.customize.yaml' configOutputFile: '{project-root}/_bmad/_config/agents/{target_module}-{agent_filename}.customize.yaml'
# Template References # Template References
customizationTemplate: '{workflow_path}/templates/agent-customization.md' customizationTemplate: '{workflow_path}/templates/agent-customization.md'

View File

@ -88,4 +88,4 @@ module_output_file: "{project-root}/\_bmad/{target_module}/agents/{agent_filenam
standalone_output_folder: "{custom_agent_location}/{agent_filename}" standalone_output_folder: "{custom_agent_location}/{agent_filename}"
standalone_output_file: "{standalone_output_folder}/{agent_filename}.agent.yaml" standalone_output_file: "{standalone_output_folder}/{agent_filename}.agent.yaml"
standalone_info_guide: "{standalone_output_folder}/info-and-installation-guide.md" standalone_info_guide: "{standalone_output_folder}/info-and-installation-guide.md"
config_output_file: "{project-root}/\_bmad/\_cfg/agents/{target_module}-{agent_filename}.customize.yaml" config_output_file: "{project-root}/\_bmad/\_config/agents/{target_module}-{agent_filename}.customize.yaml"

View File

@ -58,7 +58,7 @@ agent:
- trigger: epic-retrospective - trigger: epic-retrospective
workflow: "{project-root}/_bmad/bmm/workflows/4-implementation/retrospective/workflow.yaml" workflow: "{project-root}/_bmad/bmm/workflows/4-implementation/retrospective/workflow.yaml"
workflow-install: "{project-root}/_bmad/bmgd/workflows/4-production/retrospective/workflow.yaml" workflow-install: "{project-root}/_bmad/bmgd/workflows/4-production/retrospective/workflow.yaml"
data: "{project-root}/_bmad/_cfg/agent-manifest.csv" data: "{project-root}/_bmad/_config/agent-manifest.csv"
description: (Optional) Facilitate team retrospective after a game development epic is completed description: (Optional) Facilitate team retrospective after a game development epic is completed
- trigger: correct-course - trigger: correct-course

View File

@ -17,7 +17,7 @@ template: false
instructions: "{installed_path}/instructions.md" instructions: "{installed_path}/instructions.md"
required_inputs: required_inputs:
- agent_manifest: "{project-root}/_bmad/_cfg/agent-manifest.csv" - agent_manifest: "{project-root}/_bmad/_config/agent-manifest.csv"
# Smart input file references - handles both whole docs and sharded docs # Smart input file references - handles both whole docs and sharded docs
# Priority: Whole document first, then sharded version # Priority: Whole document first, then sharded version

View File

@ -38,7 +38,7 @@ agent:
- trigger: epic-retrospective - trigger: epic-retrospective
workflow: "{project-root}/_bmad/bmm/workflows/4-implementation/retrospective/workflow.yaml" workflow: "{project-root}/_bmad/bmm/workflows/4-implementation/retrospective/workflow.yaml"
data: "{project-root}/_bmad/_cfg/agent-manifest.csv" data: "{project-root}/_bmad/_config/agent-manifest.csv"
description: Facilitate team retrospective after an epic is completed (Optional) description: Facilitate team retrospective after an epic is completed (Optional)
- trigger: correct-course - trigger: correct-course

View File

@ -663,14 +663,14 @@ You can customize any agent's personality without modifying core agent files.
### Location ### Location
**Customization Directory:** `{project-root}/_bmad/_cfg/agents/` **Customization Directory:** `{project-root}/_bmad/_config/agents/`
**Naming Convention:** `{module}-{agent-name}.customize.yaml` **Naming Convention:** `{module}-{agent-name}.customize.yaml`
**Examples:** **Examples:**
``` ```
_bmad/_cfg/agents/ _bmad/_config/agents/
├── bmm-pm.customize.yaml ├── bmm-pm.customize.yaml
├── bmm-dev.customize.yaml ├── bmm-dev.customize.yaml
├── cis-storyteller.customize.yaml ├── cis-storyteller.customize.yaml
@ -770,9 +770,9 @@ Other agents collaborate with PM's specialized perspective.
```bash ```bash
# Create customization file at: # Create customization file at:
# {project-root}/_bmad/_cfg/agents/{module}-{agent-name}.customize.yaml # {project-root}/_bmad/_config/agents/{module}-{agent-name}.customize.yaml
# Example: _bmad/_cfg/agents/bmm-pm.customize.yaml # Example: _bmad/_config/agents/bmm-pm.customize.yaml
``` ```
**Step 2: Regenerate Agent Manifest** **Step 2: Regenerate Agent Manifest**

View File

@ -358,7 +358,7 @@ See [IDE Setup Guides](https://github.com/bmad-code-org/BMAD-METHOD/tree/main/do
### Q: Can I customize agents? ### Q: Can I customize agents?
**A:** Yes! Agents are installed as markdown files with XML-style content (optimized for LLMs, readable by any model). Create customization files in `_bmad/_cfg/agents/[agent-name].customize.yaml` to override default behaviors while keeping core functionality intact. See agent documentation for customization options. **A:** Yes! Agents are installed as markdown files with XML-style content (optimized for LLMs, readable by any model). Create customization files in `_bmad/_config/agents/[agent-name].customize.yaml` to override default behaviors while keeping core functionality intact. See agent documentation for customization options.
**Note:** While source agents in this repo are YAML, they install as `.md` files with XML-style tags - a format any LLM can read and follow. **Note:** While source agents in this repo are YAML, they install as `.md` files with XML-style tags - a format any LLM can read and follow.

View File

@ -27,7 +27,7 @@ Type `/bmad:core:workflows:party-mode` (or `*party-mode` from any agent), and su
**The basics:** **The basics:**
1. Party mode reads `_bmad/_cfg/agent-manifest.csv` 1. Party mode reads `_bmad/_config/agent-manifest.csv`
2. Loads ALL installed agents (already includes your customizations from install) 2. Loads ALL installed agents (already includes your customizations from install)
3. BMad Master orchestrates - picks 2-3 relevant agents per message based on topic 3. BMad Master orchestrates - picks 2-3 relevant agents per message based on topic
4. Agents respond in character, can agree/disagree/build on each other's ideas 4. Agents respond in character, can agree/disagree/build on each other's ideas
@ -130,7 +130,7 @@ Party mode uses agents from `_bmad/[module]/agents/*.md` - these already include
**To customize agents for party mode:** **To customize agents for party mode:**
1. Create customization file: `_bmad/_cfg/agents/bmm-pm.customize.yaml` 1. Create customization file: `_bmad/_config/agents/bmm-pm.customize.yaml`
2. Run `npx bmad-method install` to rebuild agents 2. Run `npx bmad-method install` to rebuild agents
3. Customizations now active in party mode 3. Customizations now active in party mode

View File

@ -17,7 +17,7 @@ template: false
instructions: "{installed_path}/instructions.md" instructions: "{installed_path}/instructions.md"
required_inputs: required_inputs:
- agent_manifest: "{project-root}/_bmad/_cfg/agent-manifest.csv" - agent_manifest: "{project-root}/_bmad/_config/agent-manifest.csv"
# Smart input file references - handles both whole docs and sharded docs # Smart input file references - handles both whole docs and sharded docs
# Priority: Whole document first, then sharded version # Priority: Whole document first, then sharded version

View File

@ -99,7 +99,7 @@ async function buildAgent(projectDir, agentName) {
// Build the standalone agent // Build the standalone agent
console.log(chalk.cyan(` Building standalone agent ${agentName}...`)); console.log(chalk.cyan(` Building standalone agent ${agentName}...`));
const customizePath = path.join(projectDir, '_bmad', '_cfg', 'agents', `${agentName}.customize.yaml`); const customizePath = path.join(projectDir, '_bmad', '_config', 'agents', `${agentName}.customize.yaml`);
const customizeExists = await fs.pathExists(customizePath); const customizeExists = await fs.pathExists(customizePath);
await builder.buildAgent(standaloneYamlPath, customizeExists ? customizePath : null, outputPath, { includeMetadata: true }); await builder.buildAgent(standaloneYamlPath, customizeExists ? customizePath : null, outputPath, { includeMetadata: true });
@ -125,7 +125,7 @@ async function buildAgent(projectDir, agentName) {
// Build the agent // Build the agent
console.log(chalk.cyan(` Building ${agentName}...`)); console.log(chalk.cyan(` Building ${agentName}...`));
const customizePath = path.join(projectDir, '.claude', '_cfg', 'agents', `${agentName}.customize.yaml`); const customizePath = path.join(projectDir, '.claude', '_config', 'agents', `${agentName}.customize.yaml`);
const customizeExists = await fs.pathExists(customizePath); const customizeExists = await fs.pathExists(customizePath);
await builder.buildAgent(agentYamlPath, customizeExists ? customizePath : null, outputPath, { includeMetadata: true }); await builder.buildAgent(agentYamlPath, customizeExists ? customizePath : null, outputPath, { includeMetadata: true });
@ -177,7 +177,7 @@ async function buildAllAgents(projectDir) {
console.log(chalk.cyan(` Building standalone agent ${agentName}...`)); console.log(chalk.cyan(` Building standalone agent ${agentName}...`));
const customizePath = path.join(projectDir, '_bmad', '_cfg', 'agents', `${agentName}.customize.yaml`); const customizePath = path.join(projectDir, '_bmad', '_config', 'agents', `${agentName}.customize.yaml`);
const customizeExists = await fs.pathExists(customizePath); const customizeExists = await fs.pathExists(customizePath);
await builder.buildAgent(agentYamlPath, customizeExists ? customizePath : null, outputPath, { includeMetadata: true }); await builder.buildAgent(agentYamlPath, customizeExists ? customizePath : null, outputPath, { includeMetadata: true });
@ -213,7 +213,7 @@ async function buildAllAgents(projectDir) {
console.log(chalk.cyan(` Building ${agentName}...`)); console.log(chalk.cyan(` Building ${agentName}...`));
const customizePath = path.join(projectDir, '.claude', '_cfg', 'agents', `${agentName}.customize.yaml`); const customizePath = path.join(projectDir, '.claude', '_config', 'agents', `${agentName}.customize.yaml`);
const customizeExists = await fs.pathExists(customizePath); const customizeExists = await fs.pathExists(customizePath);
await builder.buildAgent(agentYamlPath, customizeExists ? customizePath : null, outputPath, { includeMetadata: true }); await builder.buildAgent(agentYamlPath, customizeExists ? customizePath : null, outputPath, { includeMetadata: true });

View File

@ -15,7 +15,7 @@ class ConfigCollector {
/** /**
* Find the bmad installation directory in a project * Find the bmad installation directory in a project
* V6+ installations can use ANY folder name but ALWAYS have _cfg/manifest.yaml * V6+ installations can use ANY folder name but ALWAYS have _config/manifest.yaml
* @param {string} projectDir - Project directory * @param {string} projectDir - Project directory
* @returns {Promise<string>} Path to bmad directory * @returns {Promise<string>} Path to bmad directory
*/ */
@ -26,13 +26,13 @@ class ConfigCollector {
return path.join(projectDir, 'bmad'); return path.join(projectDir, 'bmad');
} }
// V6+ strategy: Look for ANY directory with _cfg/manifest.yaml // V6+ strategy: Look for ANY directory with _config/manifest.yaml
// This is the definitive marker of a V6+ installation // This is the definitive marker of a V6+ installation
try { try {
const entries = await fs.readdir(projectDir, { withFileTypes: true }); const entries = await fs.readdir(projectDir, { withFileTypes: true });
for (const entry of entries) { for (const entry of entries) {
if (entry.isDirectory()) { if (entry.isDirectory()) {
const manifestPath = path.join(projectDir, entry.name, '_cfg', 'manifest.yaml'); const manifestPath = path.join(projectDir, entry.name, '_config', 'manifest.yaml');
if (await fs.pathExists(manifestPath)) { if (await fs.pathExists(manifestPath)) {
// Found a V6+ installation // Found a V6+ installation
return path.join(projectDir, entry.name); return path.join(projectDir, entry.name);
@ -59,12 +59,12 @@ class ConfigCollector {
return null; return null;
} }
// Look for ANY directory with _cfg/manifest.yaml // Look for ANY directory with _config/manifest.yaml
try { try {
const entries = await fs.readdir(projectDir, { withFileTypes: true }); const entries = await fs.readdir(projectDir, { withFileTypes: true });
for (const entry of entries) { for (const entry of entries) {
if (entry.isDirectory()) { if (entry.isDirectory()) {
const manifestPath = path.join(projectDir, entry.name, '_cfg', 'manifest.yaml'); const manifestPath = path.join(projectDir, entry.name, '_config', 'manifest.yaml');
if (await fs.pathExists(manifestPath)) { if (await fs.pathExists(manifestPath)) {
// Found a V6+ installation, return just the folder name // Found a V6+ installation, return just the folder name
return entry.name; return entry.name;

View File

@ -1,6 +1,6 @@
/** /**
* Custom Module Source Cache * Custom Module Source Cache
* Caches custom module sources under _cfg/custom/ to ensure they're never lost * Caches custom module sources under _config/custom/ to ensure they're never lost
* and can be checked into source control * and can be checked into source control
*/ */
@ -11,7 +11,7 @@ const crypto = require('node:crypto');
class CustomModuleCache { class CustomModuleCache {
constructor(bmadDir) { constructor(bmadDir) {
this.bmadDir = bmadDir; this.bmadDir = bmadDir;
this.customCacheDir = path.join(bmadDir, '_cfg', 'custom'); this.customCacheDir = path.join(bmadDir, '_config', 'custom');
this.manifestPath = path.join(this.customCacheDir, 'cache-manifest.yaml'); this.manifestPath = path.join(this.customCacheDir, 'cache-manifest.yaml');
} }

View File

@ -92,7 +92,7 @@ class Detector {
// Fallback: scan directory for modules (legacy installations without manifest) // Fallback: scan directory for modules (legacy installations without manifest)
const entries = await fs.readdir(bmadDir, { withFileTypes: true }); const entries = await fs.readdir(bmadDir, { withFileTypes: true });
for (const entry of entries) { for (const entry of entries) {
if (entry.isDirectory() && entry.name !== 'core' && entry.name !== '_cfg') { if (entry.isDirectory() && entry.name !== 'core' && entry.name !== '_config') {
const modulePath = path.join(bmadDir, entry.name); const modulePath = path.join(bmadDir, entry.name);
const moduleConfigPath = path.join(modulePath, 'config.yaml'); const moduleConfigPath = path.join(modulePath, 'config.yaml');
@ -205,7 +205,7 @@ class Detector {
/** /**
* Detect legacy BMAD v4 footprints (case-sensitive path checks) * Detect legacy BMAD v4 footprints (case-sensitive path checks)
* V4 used _bmad-method as default folder name * V4 used _bmad-method as default folder name
* V6+ uses configurable folder names and ALWAYS has _cfg/manifest.yaml with installation.version * V6+ uses configurable folder names and ALWAYS has _config/manifest.yaml with installation.version
* @param {string} projectDir - Project directory to check * @param {string} projectDir - Project directory to check
* @returns {{ hasLegacyV4: boolean, offenders: string[] }} * @returns {{ hasLegacyV4: boolean, offenders: string[] }}
*/ */
@ -232,7 +232,7 @@ class Detector {
// Helper: check if a directory is a V6+ installation // Helper: check if a directory is a V6+ installation
const isV6Installation = async (dirPath) => { const isV6Installation = async (dirPath) => {
const manifestPath = path.join(dirPath, '_cfg', 'manifest.yaml'); const manifestPath = path.join(dirPath, '_config', 'manifest.yaml');
if (!(await fs.pathExists(manifestPath))) { if (!(await fs.pathExists(manifestPath))) {
return false; return false;
} }
@ -250,7 +250,7 @@ class Detector {
const offenders = []; const offenders = [];
// Strategy: // Strategy:
// 1. First scan for ANY V6+ installation (_cfg/manifest.yaml) // 1. First scan for ANY V6+ installation (_config/manifest.yaml)
// 2. If V6+ found → don't flag anything (user is already on V6+) // 2. If V6+ found → don't flag anything (user is already on V6+)
// 3. If NO V6+ found → flag folders with "bmad" in name as potential V4 legacy // 3. If NO V6+ found → flag folders with "bmad" in name as potential V4 legacy
@ -271,7 +271,7 @@ class Detector {
continue; // Skip empty folders continue; // Skip empty folders
} }
// Check if it's a V6+ installation by looking for _cfg/manifest.yaml // Check if it's a V6+ installation by looking for _config/manifest.yaml
// This works for ANY folder name (not just bmad-prefixed) // This works for ANY folder name (not just bmad-prefixed)
const isV6 = await isV6Installation(fullPath); const isV6 = await isV6Installation(fullPath);

View File

@ -4,7 +4,7 @@ const yaml = require('yaml');
/** /**
* Manages IDE configuration persistence * Manages IDE configuration persistence
* Saves and loads IDE-specific configurations to/from bmad/_cfg/ides/ * Saves and loads IDE-specific configurations to/from bmad/_config/ides/
*/ */
class IdeConfigManager { class IdeConfigManager {
constructor() {} constructor() {}
@ -15,7 +15,7 @@ class IdeConfigManager {
* @returns {string} Path to IDE config directory * @returns {string} Path to IDE config directory
*/ */
getIdeConfigDir(bmadDir) { getIdeConfigDir(bmadDir) {
return path.join(bmadDir, '_cfg', 'ides'); return path.join(bmadDir, '_config', 'ides');
} }
/** /**

View File

@ -38,27 +38,40 @@ class Installer {
/** /**
* Find the bmad installation directory in a project * Find the bmad installation directory in a project
* V6+ installations can use ANY folder name but ALWAYS have _cfg/manifest.yaml * V6+ installations can use ANY folder name but ALWAYS have _config/manifest.yaml
* Also checks for legacy _cfg folder for migration
* @param {string} projectDir - Project directory * @param {string} projectDir - Project directory
* @returns {Promise<string>} Path to bmad directory * @returns {Promise<Object>} { bmadDir: string, hasLegacyCfg: boolean }
*/ */
async findBmadDir(projectDir) { async findBmadDir(projectDir) {
// Check if project directory exists // Check if project directory exists
if (!(await fs.pathExists(projectDir))) { if (!(await fs.pathExists(projectDir))) {
// Project doesn't exist yet, return default // Project doesn't exist yet, return default
return path.join(projectDir, '_bmad'); return { bmadDir: path.join(projectDir, '_bmad'), hasLegacyCfg: false };
} }
// V6+ strategy: Look for ANY directory with _cfg/manifest.yaml // V6+ strategy: Look for ANY directory with _config/manifest.yaml or legacy _cfg/manifest.yaml
// This is the definitive marker of a V6+ installation let bmadDir = null;
let hasLegacyCfg = false;
try { try {
const entries = await fs.readdir(projectDir, { withFileTypes: true }); const entries = await fs.readdir(projectDir, { withFileTypes: true });
for (const entry of entries) { for (const entry of entries) {
if (entry.isDirectory()) { if (entry.isDirectory()) {
const manifestPath = path.join(projectDir, entry.name, '_cfg', 'manifest.yaml'); const bmadPath = path.join(projectDir, entry.name);
// Check for current _config folder
const manifestPath = path.join(bmadPath, '_config', 'manifest.yaml');
if (await fs.pathExists(manifestPath)) { if (await fs.pathExists(manifestPath)) {
// Found a V6+ installation // Found a V6+ installation with current _config folder
return path.join(projectDir, entry.name); return { bmadDir: bmadPath, hasLegacyCfg: false };
}
// Check for legacy _cfg folder
const legacyManifestPath = path.join(bmadPath, '_cfg', 'manifest.yaml');
if (await fs.pathExists(legacyManifestPath)) {
bmadDir = bmadPath;
hasLegacyCfg = true;
} }
} }
} }
@ -66,9 +79,14 @@ class Installer {
// Ignore errors, fall through to default // Ignore errors, fall through to default
} }
// If we found a bmad directory (with or without legacy _cfg)
if (bmadDir) {
return { bmadDir, hasLegacyCfg };
}
// No V6+ installation found, return default // No V6+ installation found, return default
// This will be used for new installations // This will be used for new installations
return path.join(projectDir, '_bmad'); return { bmadDir: path.join(projectDir, '_bmad'), hasLegacyCfg: false };
} }
/** /**
@ -473,10 +491,13 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
let existingBmadDir = null; let existingBmadDir = null;
let existingBmadFolderName = null; let existingBmadFolderName = null;
let hasLegacyCfg = false;
if (await fs.pathExists(projectDir)) { if (await fs.pathExists(projectDir)) {
existingBmadDir = await this.findBmadDir(projectDir); const result = await this.findBmadDir(projectDir);
existingBmadDir = result.bmadDir;
existingBmadFolderName = path.basename(existingBmadDir); existingBmadFolderName = path.basename(existingBmadDir);
hasLegacyCfg = result.hasLegacyCfg;
} }
// Create a project directory if it doesn't exist (user already confirmed) // Create a project directory if it doesn't exist (user already confirmed)
@ -501,6 +522,44 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
const bmadDir = path.join(projectDir, bmadFolderName); const bmadDir = path.join(projectDir, bmadFolderName);
// Check for legacy _cfg folder and prompt for rename
if (hasLegacyCfg && !config._quickUpdate) {
spinner.stop();
console.log(chalk.yellow('\n⚠ Legacy configuration folder detected'));
console.log(chalk.dim(` Found: ${path.join(bmadDir, '_cfg')}`));
console.log(chalk.dim(' The configuration folder has been renamed from "_cfg" to "_config"'));
const inquirer = require('inquirer');
const { shouldRename } = await inquirer.prompt([
{
type: 'confirm',
name: 'shouldRename',
message: 'Would you like the installer to rename "_cfg" to "_config" for you?',
default: true,
},
]);
if (!shouldRename) {
console.log(chalk.red('\n❌ Installation cancelled'));
console.log(chalk.dim('You must manually rename the "_cfg" folder to "_config" before proceeding.'));
return { success: false, cancelled: true };
}
// Perform the rename
spinner.start('Renaming configuration folder...');
try {
const oldCfgPath = path.join(bmadDir, '_cfg');
const newCfgPath = path.join(bmadDir, '_config');
await fs.move(oldCfgPath, newCfgPath);
spinner.succeed('Configuration folder renamed successfully');
} catch (error) {
spinner.fail('Failed to rename configuration folder');
console.error(chalk.red(`Error: ${error.message}`));
return { success: false, error: error.message };
}
}
// Check existing installation // Check existing installation
spinner.text = 'Checking for existing installation...'; spinner.text = 'Checking for existing installation...';
const existingInstall = await this.detector.detect(bmadDir); const existingInstall = await this.detector.detect(bmadDir);
@ -834,8 +893,11 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
customInfo = config._customModuleSources.get(moduleName); customInfo = config._customModuleSources.get(moduleName);
isCustomModule = true; isCustomModule = true;
// Check if this is a cached module (source path starts with _cfg) // Check if this is a cached module (source path starts with _config)
if (customInfo.sourcePath && (customInfo.sourcePath.startsWith('_cfg') || customInfo.sourcePath.includes('_cfg/custom'))) { if (
customInfo.sourcePath &&
(customInfo.sourcePath.startsWith('_config') || customInfo.sourcePath.includes('_config/custom'))
) {
useCache = true; useCache = true;
// Make sure we have the right path structure // Make sure we have the right path structure
if (!customInfo.path) { if (!customInfo.path) {
@ -939,9 +1001,9 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
if (finalCustomContent && finalCustomContent.cachedModules) { if (finalCustomContent && finalCustomContent.cachedModules) {
sourcePath = finalCustomContent.cachedModules.find((m) => m.id === moduleName)?.relativePath; sourcePath = finalCustomContent.cachedModules.find((m) => m.id === moduleName)?.relativePath;
} else { } else {
// During update, the sourcePath is already cache-relative if it starts with _cfg // During update, the sourcePath is already cache-relative if it starts with _config
sourcePath = sourcePath =
customInfo.sourcePath && customInfo.sourcePath.startsWith('_cfg') customInfo.sourcePath && customInfo.sourcePath.startsWith('_config')
? customInfo.sourcePath ? customInfo.sourcePath
: path.relative(bmadDir, customInfo.path || customInfo.sourcePath); : path.relative(bmadDir, customInfo.path || customInfo.sourcePath);
} }
@ -1061,7 +1123,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
// Customize templates are now created in processAgentFiles when building YAML agents // Customize templates are now created in processAgentFiles when building YAML agents
// Pre-register manifest files that will be created (except files-manifest.csv to avoid recursion) // Pre-register manifest files that will be created (except files-manifest.csv to avoid recursion)
const cfgDir = path.join(bmadDir, '_cfg'); const cfgDir = path.join(bmadDir, '_config');
this.installedFiles.push( this.installedFiles.push(
path.join(cfgDir, 'manifest.yaml'), path.join(cfgDir, 'manifest.yaml'),
path.join(cfgDir, 'workflow-manifest.csv'), path.join(cfgDir, 'workflow-manifest.csv'),
@ -1329,7 +1391,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
try { try {
const projectDir = path.resolve(config.directory); const projectDir = path.resolve(config.directory);
const bmadDir = await this.findBmadDir(projectDir); const { bmadDir } = await this.findBmadDir(projectDir);
const existingInstall = await this.detector.detect(bmadDir); const existingInstall = await this.detector.detect(bmadDir);
if (!existingInstall.installed) { if (!existingInstall.installed) {
@ -1414,7 +1476,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
*/ */
async getStatus(directory) { async getStatus(directory) {
const projectDir = path.resolve(directory); const projectDir = path.resolve(directory);
const bmadDir = await this.findBmadDir(projectDir); const { bmadDir } = await this.findBmadDir(projectDir);
return await this.detector.detect(bmadDir); return await this.detector.detect(bmadDir);
} }
@ -1430,7 +1492,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
*/ */
async uninstall(directory) { async uninstall(directory) {
const projectDir = path.resolve(directory); const projectDir = path.resolve(directory);
const bmadDir = await this.findBmadDir(projectDir); const { bmadDir } = await this.findBmadDir(projectDir);
if (await fs.pathExists(bmadDir)) { if (await fs.pathExists(bmadDir)) {
await fs.remove(bmadDir); await fs.remove(bmadDir);
@ -1447,9 +1509,9 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
*/ */
async createDirectoryStructure(bmadDir) { async createDirectoryStructure(bmadDir) {
await fs.ensureDir(bmadDir); await fs.ensureDir(bmadDir);
await fs.ensureDir(path.join(bmadDir, '_cfg')); await fs.ensureDir(path.join(bmadDir, '_config'));
await fs.ensureDir(path.join(bmadDir, '_cfg', 'agents')); await fs.ensureDir(path.join(bmadDir, '_config', 'agents'));
await fs.ensureDir(path.join(bmadDir, '_cfg', 'custom')); await fs.ensureDir(path.join(bmadDir, '_config', 'custom'));
} }
/** /**
@ -1466,7 +1528,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
// Get all installed module directories // Get all installed module directories
const entries = await fs.readdir(bmadDir, { withFileTypes: true }); const entries = await fs.readdir(bmadDir, { withFileTypes: true });
const installedModules = entries const installedModules = entries
.filter((entry) => entry.isDirectory() && entry.name !== '_cfg' && entry.name !== 'docs') .filter((entry) => entry.isDirectory() && entry.name !== '_config' && entry.name !== 'docs')
.map((entry) => entry.name); .map((entry) => entry.name);
// Generate config.yaml for each installed module // Generate config.yaml for each installed module
@ -1826,9 +1888,9 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
// Determine project directory (parent of bmad/ directory) // Determine project directory (parent of bmad/ directory)
const bmadDir = path.dirname(modulePath); const bmadDir = path.dirname(modulePath);
const projectDir = path.dirname(bmadDir); const projectDir = path.dirname(bmadDir);
const cfgAgentsDir = path.join(bmadDir, '_cfg', 'agents'); const cfgAgentsDir = path.join(bmadDir, '_config', 'agents');
// Ensure _cfg/agents directory exists // Ensure _config/agents directory exists
await fs.ensureDir(cfgAgentsDir); await fs.ensureDir(cfgAgentsDir);
// Get all agent files // Get all agent files
@ -1917,7 +1979,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
*/ */
async buildStandaloneAgents(bmadDir, projectDir) { async buildStandaloneAgents(bmadDir, projectDir) {
const standaloneAgentsPath = path.join(bmadDir, 'agents'); const standaloneAgentsPath = path.join(bmadDir, 'agents');
const cfgAgentsDir = path.join(bmadDir, '_cfg', 'agents'); const cfgAgentsDir = path.join(bmadDir, '_config', 'agents');
// Check if standalone agents directory exists // Check if standalone agents directory exists
if (!(await fs.pathExists(standaloneAgentsPath))) { if (!(await fs.pathExists(standaloneAgentsPath))) {
@ -2018,7 +2080,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
// Determine project directory (parent of bmad/ directory) // Determine project directory (parent of bmad/ directory)
const bmadDir = path.dirname(modulePath); const bmadDir = path.dirname(modulePath);
const projectDir = path.dirname(bmadDir); const projectDir = path.dirname(bmadDir);
const cfgAgentsDir = path.join(bmadDir, '_cfg', 'agents'); const cfgAgentsDir = path.join(bmadDir, '_config', 'agents');
const targetAgentsPath = path.join(modulePath, 'agents'); const targetAgentsPath = path.join(modulePath, 'agents');
// Ensure target directory exists // Ensure target directory exists
@ -2143,7 +2205,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
async compileAgents(config) { async compileAgents(config) {
try { try {
const projectDir = path.resolve(config.directory); const projectDir = path.resolve(config.directory);
const bmadDir = await this.findBmadDir(projectDir); const { bmadDir } = await this.findBmadDir(projectDir);
// Check if bmad directory exists // Check if bmad directory exists
if (!(await fs.pathExists(bmadDir))) { if (!(await fs.pathExists(bmadDir))) {
@ -2151,7 +2213,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
} }
// Get installed modules from manifest // Get installed modules from manifest
const manifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml'); const manifestPath = path.join(bmadDir, '_config', 'manifest.yaml');
let installedModules = []; let installedModules = [];
let manifest = null; let manifest = null;
if (await fs.pathExists(manifestPath)) { if (await fs.pathExists(manifestPath)) {
@ -2181,7 +2243,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
const entries = await fs.readdir(bmadDir, { withFileTypes: true }); const entries = await fs.readdir(bmadDir, { withFileTypes: true });
for (const entry of entries) { for (const entry of entries) {
if (entry.isDirectory() && entry.name !== '_cfg' && entry.name !== 'docs') { if (entry.isDirectory() && entry.name !== '_config' && entry.name !== 'docs') {
const modulePath = path.join(bmadDir, entry.name); const modulePath = path.join(bmadDir, entry.name);
// Special handling for standalone agents in bmad/agents/ directory // Special handling for standalone agents in bmad/agents/ directory
@ -2264,7 +2326,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
try { try {
const projectDir = path.resolve(config.directory); const projectDir = path.resolve(config.directory);
const bmadDir = await this.findBmadDir(projectDir); const { bmadDir } = await this.findBmadDir(projectDir);
// Check if bmad directory exists // Check if bmad directory exists
if (!(await fs.pathExists(bmadDir))) { if (!(await fs.pathExists(bmadDir))) {
@ -2287,8 +2349,8 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
// Ensure we have an absolute sourcePath // Ensure we have an absolute sourcePath
let absoluteSourcePath = customModule.sourcePath; let absoluteSourcePath = customModule.sourcePath;
// Check if sourcePath is a cache-relative path (starts with _cfg/) // Check if sourcePath is a cache-relative path (starts with _config/)
if (absoluteSourcePath && absoluteSourcePath.startsWith('_cfg')) { if (absoluteSourcePath && absoluteSourcePath.startsWith('_config')) {
// Convert cache-relative path to absolute path // Convert cache-relative path to absolute path
absoluteSourcePath = path.join(bmadDir, absoluteSourcePath); absoluteSourcePath = path.join(bmadDir, absoluteSourcePath);
} }
@ -2695,7 +2757,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
* @returns {Array} Array of file entries from files-manifest.csv * @returns {Array} Array of file entries from files-manifest.csv
*/ */
async readFilesManifest(bmadDir) { async readFilesManifest(bmadDir) {
const filesManifestPath = path.join(bmadDir, '_cfg', 'files-manifest.csv'); const filesManifestPath = path.join(bmadDir, '_config', 'files-manifest.csv');
if (!(await fs.pathExists(filesManifestPath))) { if (!(await fs.pathExists(filesManifestPath))) {
return []; return [];
} }
@ -2798,12 +2860,12 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
const relativePath = path.relative(bmadDir, fullPath); const relativePath = path.relative(bmadDir, fullPath);
const fileName = path.basename(fullPath); const fileName = path.basename(fullPath);
// Skip _cfg directory EXCEPT for modified agent customizations // Skip _config directory EXCEPT for modified agent customizations
if (relativePath.startsWith('_cfg/') || relativePath.startsWith('_cfg\\')) { if (relativePath.startsWith('_config/') || relativePath.startsWith('_config\\')) {
// Special handling for .customize.yaml files - only preserve if modified // Special handling for .customize.yaml files - only preserve if modified
if (relativePath.includes('/agents/') && fileName.endsWith('.customize.yaml')) { if (relativePath.includes('/agents/') && fileName.endsWith('.customize.yaml')) {
// Check if the customization file has been modified from manifest // Check if the customization file has been modified from manifest
const manifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml'); const manifestPath = path.join(bmadDir, '_config', 'manifest.yaml');
if (await fs.pathExists(manifestPath)) { if (await fs.pathExists(manifestPath)) {
const crypto = require('node:crypto'); const crypto = require('node:crypto');
const currentContent = await fs.readFile(fullPath, 'utf8'); const currentContent = await fs.readFile(fullPath, 'utf8');
@ -2824,7 +2886,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
} }
// Skip config.yaml files - these are regenerated on each install/update // Skip config.yaml files - these are regenerated on each install/update
// Users should use _cfg/agents/ override files instead // Users should use _config/agents/ override files instead
if (fileName === 'config.yaml') { if (fileName === 'config.yaml') {
continue; continue;
} }
@ -2832,8 +2894,8 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
if (!fileInfo) { if (!fileInfo) {
// File not in manifest = custom file // File not in manifest = custom file
// EXCEPT: Agent .md files in module folders are generated files, not custom // EXCEPT: Agent .md files in module folders are generated files, not custom
// Only treat .md files under _cfg/agents/ as custom // Only treat .md files under _config/agents/ as custom
if (!(fileName.endsWith('.md') && relativePath.includes('/agents/') && !relativePath.startsWith('_cfg/'))) { if (!(fileName.endsWith('.md') && relativePath.includes('/agents/') && !relativePath.startsWith('_config/'))) {
customFiles.push(fullPath); customFiles.push(fullPath);
} }
} else if (manifestHasHashes && fileInfo.hash) { } else if (manifestHasHashes && fileInfo.hash) {
@ -2866,7 +2928,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
* @param {Object} userInfo - User information including name and language * @param {Object} userInfo - User information including name and language
*/ */
async createAgentConfigs(bmadDir, userInfo = null) { async createAgentConfigs(bmadDir, userInfo = null) {
const agentConfigDir = path.join(bmadDir, '_cfg', 'agents'); const agentConfigDir = path.join(bmadDir, '_config', 'agents');
await fs.ensureDir(agentConfigDir); await fs.ensureDir(agentConfigDir);
// Get all agents from all modules // Get all agents from all modules
@ -2876,7 +2938,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
// Check modules for agents (including core) // Check modules for agents (including core)
const entries = await fs.readdir(bmadDir, { withFileTypes: true }); const entries = await fs.readdir(bmadDir, { withFileTypes: true });
for (const entry of entries) { for (const entry of entries) {
if (entry.isDirectory() && entry.name !== '_cfg') { if (entry.isDirectory() && entry.name !== '_config') {
const moduleAgentsPath = path.join(bmadDir, entry.name, 'agents'); const moduleAgentsPath = path.join(bmadDir, entry.name, 'agents');
if (await fs.pathExists(moduleAgentsPath)) { if (await fs.pathExists(moduleAgentsPath)) {
const agentFiles = await fs.readdir(moduleAgentsPath); const agentFiles = await fs.readdir(moduleAgentsPath);
@ -2994,7 +3056,7 @@ If AgentVibes party mode is enabled, immediately trigger TTS with agent's voice:
* @param {Array} agentDetails - Array of agent details * @param {Array} agentDetails - Array of agent details
*/ */
async generateAgentManifest(bmadDir, agentDetails) { async generateAgentManifest(bmadDir, agentDetails) {
const manifestPath = path.join(bmadDir, '_cfg', 'agent-manifest.csv'); const manifestPath = path.join(bmadDir, '_config', 'agent-manifest.csv');
await AgentPartyGenerator.writeAgentParty(manifestPath, agentDetails, { forWeb: false }); await AgentPartyGenerator.writeAgentParty(manifestPath, agentDetails, { forWeb: false });
} }

View File

@ -28,8 +28,8 @@ class ManifestGenerator {
* @param {Array} installedFiles - All installed files (optional, for hash tracking) * @param {Array} installedFiles - All installed files (optional, for hash tracking)
*/ */
async generateManifests(bmadDir, selectedModules, installedFiles = [], options = {}) { async generateManifests(bmadDir, selectedModules, installedFiles = [], options = {}) {
// Create _cfg directory if it doesn't exist // Create _config directory if it doesn't exist
const cfgDir = path.join(bmadDir, '_cfg'); const cfgDir = path.join(bmadDir, '_config');
await fs.ensureDir(cfgDir); await fs.ensureDir(cfgDir);
// Store modules list (all modules including preserved ones) // Store modules list (all modules including preserved ones)
@ -902,7 +902,7 @@ class ManifestGenerator {
for (const entry of entries) { for (const entry of entries) {
// Skip if not a directory or is a special directory // Skip if not a directory or is a special directory
if (!entry.isDirectory() || entry.name.startsWith('.') || entry.name === '_cfg') { if (!entry.isDirectory() || entry.name.startsWith('.') || entry.name === '_config') {
continue; continue;
} }

View File

@ -10,10 +10,10 @@ class Manifest {
* @param {Array} installedFiles - List of installed files (no longer used, files tracked in files-manifest.csv) * @param {Array} installedFiles - List of installed files (no longer used, files tracked in files-manifest.csv)
*/ */
async create(bmadDir, data, installedFiles = []) { async create(bmadDir, data, installedFiles = []) {
const manifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml'); const manifestPath = path.join(bmadDir, '_config', 'manifest.yaml');
const yaml = require('yaml'); const yaml = require('yaml');
// Ensure _cfg directory exists // Ensure _config directory exists
await fs.ensureDir(path.dirname(manifestPath)); await fs.ensureDir(path.dirname(manifestPath));
// Structure the manifest data // Structure the manifest data
@ -46,7 +46,7 @@ class Manifest {
* @returns {Object|null} Manifest data or null if not found * @returns {Object|null} Manifest data or null if not found
*/ */
async read(bmadDir) { async read(bmadDir) {
const yamlPath = path.join(bmadDir, '_cfg', 'manifest.yaml'); const yamlPath = path.join(bmadDir, '_config', 'manifest.yaml');
const yaml = require('yaml'); const yaml = require('yaml');
if (await fs.pathExists(yamlPath)) { if (await fs.pathExists(yamlPath)) {
@ -97,7 +97,7 @@ class Manifest {
ides: manifest.ides || [], ides: manifest.ides || [],
}; };
const manifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml'); const manifestPath = path.join(bmadDir, '_config', 'manifest.yaml');
await fs.ensureDir(path.dirname(manifestPath)); await fs.ensureDir(path.dirname(manifestPath));
const yamlContent = yaml.stringify(manifestData, { const yamlContent = yaml.stringify(manifestData, {

View File

@ -306,7 +306,7 @@ class CustomHandler {
const targetMdPath = path.join(targetDir, `${agentName}.md`); const targetMdPath = path.join(targetDir, `${agentName}.md`);
// Use the actual bmadDir if available (for when installing to temp dir) // Use the actual bmadDir if available (for when installing to temp dir)
const actualBmadDir = config._bmadDir || bmadDir; const actualBmadDir = config._bmadDir || bmadDir;
const customizePath = path.join(actualBmadDir, '_cfg', 'agents', `custom-${agentName}.customize.yaml`); const customizePath = path.join(actualBmadDir, '_config', 'agents', `custom-${agentName}.customize.yaml`);
// Read and compile the YAML // Read and compile the YAML
try { try {

View File

@ -136,7 +136,7 @@ class BaseIdeSetup {
// Get module agents // Get module agents
const entries = await fs.readdir(bmadDir, { withFileTypes: true }); const entries = await fs.readdir(bmadDir, { withFileTypes: true });
for (const entry of entries) { for (const entry of entries) {
if (entry.isDirectory() && entry.name !== 'core' && entry.name !== '_cfg' && entry.name !== 'agents') { if (entry.isDirectory() && entry.name !== 'core' && entry.name !== '_config' && entry.name !== 'agents') {
const moduleAgentsPath = path.join(bmadDir, entry.name, 'agents'); const moduleAgentsPath = path.join(bmadDir, entry.name, 'agents');
if (await fs.pathExists(moduleAgentsPath)) { if (await fs.pathExists(moduleAgentsPath)) {
const moduleAgents = await this.scanDirectory(moduleAgentsPath, '.md'); const moduleAgents = await this.scanDirectory(moduleAgentsPath, '.md');
@ -208,7 +208,7 @@ class BaseIdeSetup {
// Get module tasks // Get module tasks
const entries = await fs.readdir(bmadDir, { withFileTypes: true }); const entries = await fs.readdir(bmadDir, { withFileTypes: true });
for (const entry of entries) { for (const entry of entries) {
if (entry.isDirectory() && entry.name !== 'core' && entry.name !== '_cfg' && entry.name !== 'agents') { if (entry.isDirectory() && entry.name !== 'core' && entry.name !== '_config' && entry.name !== 'agents') {
const moduleTasksPath = path.join(bmadDir, entry.name, 'tasks'); const moduleTasksPath = path.join(bmadDir, entry.name, 'tasks');
if (await fs.pathExists(moduleTasksPath)) { if (await fs.pathExists(moduleTasksPath)) {
const moduleTasks = await this.scanDirectoryWithStandalone(moduleTasksPath, ['.md', '.xml']); const moduleTasks = await this.scanDirectoryWithStandalone(moduleTasksPath, ['.md', '.xml']);
@ -254,7 +254,7 @@ class BaseIdeSetup {
// Get module tools // Get module tools
const entries = await fs.readdir(bmadDir, { withFileTypes: true }); const entries = await fs.readdir(bmadDir, { withFileTypes: true });
for (const entry of entries) { for (const entry of entries) {
if (entry.isDirectory() && entry.name !== 'core' && entry.name !== '_cfg' && entry.name !== 'agents') { if (entry.isDirectory() && entry.name !== 'core' && entry.name !== '_config' && entry.name !== 'agents') {
const moduleToolsPath = path.join(bmadDir, entry.name, 'tools'); const moduleToolsPath = path.join(bmadDir, entry.name, 'tools');
if (await fs.pathExists(moduleToolsPath)) { if (await fs.pathExists(moduleToolsPath)) {
const moduleTools = await this.scanDirectoryWithStandalone(moduleToolsPath, ['.md', '.xml']); const moduleTools = await this.scanDirectoryWithStandalone(moduleToolsPath, ['.md', '.xml']);
@ -300,7 +300,7 @@ class BaseIdeSetup {
// Get module workflows // Get module workflows
const entries = await fs.readdir(bmadDir, { withFileTypes: true }); const entries = await fs.readdir(bmadDir, { withFileTypes: true });
for (const entry of entries) { for (const entry of entries) {
if (entry.isDirectory() && entry.name !== 'core' && entry.name !== '_cfg' && entry.name !== 'agents') { if (entry.isDirectory() && entry.name !== 'core' && entry.name !== '_config' && entry.name !== 'agents') {
const moduleWorkflowsPath = path.join(bmadDir, entry.name, 'workflows'); const moduleWorkflowsPath = path.join(bmadDir, entry.name, 'workflows');
if (await fs.pathExists(moduleWorkflowsPath)) { if (await fs.pathExists(moduleWorkflowsPath)) {
const moduleWorkflows = await this.findWorkflowYamlFiles(moduleWorkflowsPath); const moduleWorkflows = await this.findWorkflowYamlFiles(moduleWorkflowsPath);
@ -635,7 +635,7 @@ class BaseIdeSetup {
* @param {Object} agent - Agent information * @param {Object} agent - Agent information
*/ */
async createAgentConfig(bmadDir, agent) { async createAgentConfig(bmadDir, agent) {
const agentConfigDir = path.join(bmadDir, '_cfg', 'agents'); const agentConfigDir = path.join(bmadDir, '_config', 'agents');
await this.ensureDir(agentConfigDir); await this.ensureDir(agentConfigDir);
// Load agent config template // Load agent config template

View File

@ -85,7 +85,7 @@ Follow all instructions in the ${type} file exactly as written.
* Load task manifest CSV * Load task manifest CSV
*/ */
async loadTaskManifest(bmadDir) { async loadTaskManifest(bmadDir) {
const manifestPath = path.join(bmadDir, '_cfg', 'task-manifest.csv'); const manifestPath = path.join(bmadDir, '_config', 'task-manifest.csv');
if (!(await fs.pathExists(manifestPath))) { if (!(await fs.pathExists(manifestPath))) {
return null; return null;
@ -102,7 +102,7 @@ Follow all instructions in the ${type} file exactly as written.
* Load tool manifest CSV * Load tool manifest CSV
*/ */
async loadToolManifest(bmadDir) { async loadToolManifest(bmadDir) {
const manifestPath = path.join(bmadDir, '_cfg', 'tool-manifest.csv'); const manifestPath = path.join(bmadDir, '_config', 'tool-manifest.csv');
if (!(await fs.pathExists(manifestPath))) { if (!(await fs.pathExists(manifestPath))) {
return null; return null;

View File

@ -224,7 +224,7 @@ When running any workflow:
} }
async loadWorkflowManifest(bmadDir) { async loadWorkflowManifest(bmadDir) {
const manifestPath = path.join(bmadDir, '_cfg', 'workflow-manifest.csv'); const manifestPath = path.join(bmadDir, '_config', 'workflow-manifest.csv');
if (!(await fs.pathExists(manifestPath))) { if (!(await fs.pathExists(manifestPath))) {
return null; return null;

View File

@ -242,15 +242,15 @@ class ModuleManager {
} }
} }
// Also check for cached custom modules in _cfg/custom/ // Also check for cached custom modules in _config/custom/
if (this.bmadDir) { if (this.bmadDir) {
const customCacheDir = path.join(this.bmadDir, '_cfg', 'custom'); const customCacheDir = path.join(this.bmadDir, '_config', 'custom');
if (await fs.pathExists(customCacheDir)) { if (await fs.pathExists(customCacheDir)) {
const cacheEntries = await fs.readdir(customCacheDir, { withFileTypes: true }); const cacheEntries = await fs.readdir(customCacheDir, { withFileTypes: true });
for (const entry of cacheEntries) { for (const entry of cacheEntries) {
if (entry.isDirectory()) { if (entry.isDirectory()) {
const cachePath = path.join(customCacheDir, entry.name); const cachePath = path.join(customCacheDir, entry.name);
const moduleInfo = await this.getModuleInfo(cachePath, entry.name, '_cfg/custom'); const moduleInfo = await this.getModuleInfo(cachePath, entry.name, '_config/custom');
if (moduleInfo && !modules.some((m) => m.id === moduleInfo.id) && !customModules.some((m) => m.id === moduleInfo.id)) { if (moduleInfo && !modules.some((m) => m.id === moduleInfo.id) && !customModules.some((m) => m.id === moduleInfo.id)) {
moduleInfo.isCustom = true; moduleInfo.isCustom = true;
moduleInfo.fromCache = true; moduleInfo.fromCache = true;
@ -785,7 +785,7 @@ class ModuleManager {
async compileModuleAgents(sourcePath, targetPath, moduleName, bmadDir) { async compileModuleAgents(sourcePath, targetPath, moduleName, bmadDir) {
const sourceAgentsPath = path.join(sourcePath, 'agents'); const sourceAgentsPath = path.join(sourcePath, 'agents');
const targetAgentsPath = path.join(targetPath, 'agents'); const targetAgentsPath = path.join(targetPath, 'agents');
const cfgAgentsDir = path.join(bmadDir, '_cfg', 'agents'); const cfgAgentsDir = path.join(bmadDir, '_config', 'agents');
// Check if agents directory exists in source // Check if agents directory exists in source
if (!(await fs.pathExists(sourceAgentsPath))) { if (!(await fs.pathExists(sourceAgentsPath))) {
@ -827,7 +827,7 @@ class ModuleManager {
const originalHash = crypto.createHash('sha256').update(customizeContent).digest('hex'); const originalHash = crypto.createHash('sha256').update(customizeContent).digest('hex');
// Store in main manifest // Store in main manifest
const manifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml'); const manifestPath = path.join(bmadDir, '_config', 'manifest.yaml');
let manifestData = {}; let manifestData = {};
if (await fs.pathExists(manifestPath)) { if (await fs.pathExists(manifestPath)) {
const manifestContent = await fs.readFile(manifestPath, 'utf8'); const manifestContent = await fs.readFile(manifestPath, 'utf8');

View File

@ -29,7 +29,7 @@ const AgentPartyGenerator = {
let xmlContent = `<!-- Powered by BMAD-CORE™ --> let xmlContent = `<!-- Powered by BMAD-CORE™ -->
<!-- Agent Manifest - Generated during BMAD ${forWeb ? 'bundling' : 'installation'} --> <!-- Agent Manifest - Generated during BMAD ${forWeb ? 'bundling' : 'installation'} -->
<!-- This file contains a summary of all ${forWeb ? 'bundled' : 'installed'} agents for quick reference --> <!-- This file contains a summary of all ${forWeb ? 'bundled' : 'installed'} agents for quick reference -->
<manifest id="bmad/_cfg/agent-manifest.csv" version="1.0" generated="${new Date().toISOString()}"> <manifest id="bmad/_config/agent-manifest.csv" version="1.0" generated="${new Date().toISOString()}">
<description> <description>
Complete roster of ${forWeb ? 'bundled' : 'installed'} BMAD agents with summarized personas for efficient multi-agent orchestration. Complete roster of ${forWeb ? 'bundled' : 'installed'} BMAD agents with summarized personas for efficient multi-agent orchestration.
Used by party-mode and other multi-agent coordination features. Used by party-mode and other multi-agent coordination features.

View File

@ -410,7 +410,7 @@ function detectBmadProject(targetPath) {
const possibleNames = ['_bmad']; const possibleNames = ['_bmad'];
for (const name of possibleNames) { for (const name of possibleNames) {
const bmadFolder = path.join(checkPath, name); const bmadFolder = path.join(checkPath, name);
const cfgFolder = path.join(bmadFolder, '_cfg'); const cfgFolder = path.join(bmadFolder, '_config');
const manifestFile = path.join(cfgFolder, 'agent-manifest.csv'); const manifestFile = path.join(cfgFolder, 'agent-manifest.csv');
if (fs.existsSync(manifestFile)) { if (fs.existsSync(manifestFile)) {
@ -596,16 +596,16 @@ function addToManifest(manifestFile, agentData) {
} }
/** /**
* Save agent source YAML to _cfg/custom/agents/ for reinstallation * Save agent source YAML to _config/custom/agents/ for reinstallation
* Stores user answers in a top-level saved_answers section (cleaner than overwriting defaults) * Stores user answers in a top-level saved_answers section (cleaner than overwriting defaults)
* @param {Object} agentInfo - Agent info (path, type, etc.) * @param {Object} agentInfo - Agent info (path, type, etc.)
* @param {string} cfgFolder - Path to _cfg folder * @param {string} cfgFolder - Path to _config folder
* @param {string} agentName - Final agent name (e.g., "fred-commit-poet") * @param {string} agentName - Final agent name (e.g., "fred-commit-poet")
* @param {Object} answers - User answers to save for reinstallation * @param {Object} answers - User answers to save for reinstallation
* @returns {Object} Info about saved source * @returns {Object} Info about saved source
*/ */
function saveAgentSource(agentInfo, cfgFolder, agentName, answers = {}) { function saveAgentSource(agentInfo, cfgFolder, agentName, answers = {}) {
// Save to _cfg/custom/agents/ instead of _cfg/agents/ // Save to _config/custom/agents/ instead of _config/agents/
const customAgentsCfgDir = path.join(cfgFolder, 'custom', 'agents'); const customAgentsCfgDir = path.join(cfgFolder, 'custom', 'agents');
if (!fs.existsSync(customAgentsCfgDir)) { if (!fs.existsSync(customAgentsCfgDir)) {
@ -689,7 +689,7 @@ function saveAgentSource(agentInfo, cfgFolder, agentName, answers = {}) {
*/ */
async function createIdeSlashCommands(projectRoot, agentName, agentPath, metadata) { async function createIdeSlashCommands(projectRoot, agentName, agentPath, metadata) {
// Read manifest.yaml to get installed IDEs // Read manifest.yaml to get installed IDEs
const manifestPath = path.join(projectRoot, '_bmad', '_cfg', 'manifest.yaml'); const manifestPath = path.join(projectRoot, '_bmad', '_config', 'manifest.yaml');
let installedIdes = ['claude-code']; // Default to Claude Code if no manifest let installedIdes = ['claude-code']; // Default to Claude Code if no manifest
if (fs.existsSync(manifestPath)) { if (fs.existsSync(manifestPath)) {

View File

@ -650,11 +650,11 @@ class UI {
if (stats.isDirectory()) { if (stats.isDirectory()) {
const files = await fs.readdir(directory); const files = await fs.readdir(directory);
if (files.length > 0) { if (files.length > 0) {
// Check for any bmad installation (any folder with _cfg/manifest.yaml) // Check for any bmad installation (any folder with _config/manifest.yaml)
const { Installer } = require('../installers/lib/core/installer'); const { Installer } = require('../installers/lib/core/installer');
const installer = new Installer(); const installer = new Installer();
const bmadDir = await installer.findBmadDir(directory); const bmadDir = await installer.findBmadDir(directory);
const hasBmadInstall = (await fs.pathExists(bmadDir)) && (await fs.pathExists(path.join(bmadDir, '_cfg', 'manifest.yaml'))); const hasBmadInstall = (await fs.pathExists(bmadDir)) && (await fs.pathExists(path.join(bmadDir, '_config', 'manifest.yaml')));
console.log( console.log(
chalk.gray(`Directory exists and contains ${files.length} item(s)`) + chalk.gray(`Directory exists and contains ${files.length} item(s)`) +

View File

@ -525,7 +525,7 @@ class YamlXmlBuilder {
} else if (bmadIndex !== -1 && pathParts[bmadIndex + 1]) { } else if (bmadIndex !== -1 && pathParts[bmadIndex + 1]) {
// Path contains /bmad/{module}/ // Path contains /bmad/{module}/
const potentialModule = pathParts[bmadIndex + 1]; const potentialModule = pathParts[bmadIndex + 1];
// Check if it's a known module, not 'agents' or '_cfg' // Check if it's a known module, not 'agents' or '_config'
if (['bmm', 'bmb', 'cis', 'core'].includes(potentialModule)) { if (['bmm', 'bmb', 'cis', 'core'].includes(potentialModule)) {
module = potentialModule; module = potentialModule;
} }

View File

@ -95,7 +95,7 @@ async function migrate(directory) {
console.log(chalk.dim(`Project: ${projectRoot}`)); console.log(chalk.dim(`Project: ${projectRoot}`));
console.log(chalk.dim(`BMAD Directory: ${bmadDir}`)); console.log(chalk.dim(`BMAD Directory: ${bmadDir}`));
const manifestPath = path.join(bmadDir, '_cfg', 'manifest.yaml'); const manifestPath = path.join(bmadDir, '_config', 'manifest.yaml');
if (!fs.existsSync(manifestPath)) { if (!fs.existsSync(manifestPath)) {
console.error(chalk.red('✗ No manifest.yaml found')); console.error(chalk.red('✗ No manifest.yaml found'));