diff --git a/src/bmm-skills/1-analysis/bmad-prfaq/bmad-manifest.json b/src/bmm-skills/1-analysis/bmad-prfaq/bmad-manifest.json index 9c3ad043c..74fb2b2e3 100644 --- a/src/bmm-skills/1-analysis/bmad-prfaq/bmad-manifest.json +++ b/src/bmm-skills/1-analysis/bmad-prfaq/bmad-manifest.json @@ -7,8 +7,8 @@ "description": "Produces battle-tested PRFAQ document and optional LLM distillate for PRD input.", "supports-headless": true, "phase-name": "1-analysis", - "after": ["brainstorming", "perform-research"], - "before": ["create-prd"], + "preceded-by": ["brainstorming", "perform-research"], + "followed-by": ["create-prd"], "is-required": false, "output-location": "{planning_artifacts}" } diff --git a/src/bmm-skills/1-analysis/bmad-product-brief/bmad-manifest.json b/src/bmm-skills/1-analysis/bmad-product-brief/bmad-manifest.json index 28e2f2b17..e147f4014 100644 --- a/src/bmm-skills/1-analysis/bmad-product-brief/bmad-manifest.json +++ b/src/bmm-skills/1-analysis/bmad-product-brief/bmad-manifest.json @@ -8,8 +8,8 @@ "description": "Produces executive product brief and optional LLM distillate for PRD input.", "supports-headless": true, "phase-name": "1-analysis", - "after": ["brainstorming", "perform-research"], - "before": ["create-prd"], + "preceded-by": ["brainstorming", "perform-research"], + "followed-by": ["create-prd"], "is-required": true, "output-location": "{planning_artifacts}" } diff --git a/src/bmm-skills/module-help.csv b/src/bmm-skills/module-help.csv index 78326a02e..81f475efd 100644 --- a/src/bmm-skills/module-help.csv +++ b/src/bmm-skills/module-help.csv @@ -1,4 +1,4 @@ -module,skill,display-name,menu-code,description,action,args,phase,after,before,required,output-location,outputs +module,skill,display-name,menu-code,description,action,args,phase,preceded-by,followed-by,required,output-location,outputs BMad Method,_meta,,,,,,,,,false,https://docs.bmad-method.org/llms.txt, BMad Method,bmad-document-project,Document Project,DP,Analyze an existing project to produce useful documentation.,,,anytime,,,false,project-knowledge,* BMad Method,bmad-generate-project-context,Generate Project Context,GPC,Scan existing codebase to generate a lean LLM-optimized project-context.md. Essential for brownfield projects.,,,anytime,,,false,output_folder,project context diff --git a/src/core-skills/bmad-distillator/resources/distillate-format-reference.md b/src/core-skills/bmad-distillator/resources/distillate-format-reference.md index efdac4cfc..f8db6a2b2 100644 --- a/src/core-skills/bmad-distillator/resources/distillate-format-reference.md +++ b/src/core-skills/bmad-distillator/resources/distillate-format-reference.md @@ -139,7 +139,7 @@ parts: 1 ## Solution Architecture - Plugins: skill bundles with Anthropic plugin standard as base format + bmad-manifest.json extending for BMAD-specific metadata (installer options, capabilities, help integration, phase ordering, dependencies) -- Existing manifest example: `{"module-code":"bmm","replaces-skill":"bmad-create-product-brief","capabilities":[{"name":"create-brief","menu-code":"CB","supports-headless":true,"phase-name":"1-analysis","after":["brainstorming"],"before":["create-prd"],"is-required":true}]}` +- Existing manifest example: `{"module-code":"bmm","replaces-skill":"bmad-create-product-brief","capabilities":[{"name":"create-brief","menu-code":"CB","supports-headless":true,"phase-name":"1-analysis","preceded-by":["brainstorming"],"followed-by":["create-prd"],"is-required":true}]}` - Vercel skills CLI handles platform translation; integration pattern (wrap/fork/call) is PRD decision - bmad-setup: global skill scanning installed bmad-manifest.json files, registering capabilities, configuring project settings; always included as base skill in every bundle (solves bootstrapping) - bmad-update: plugin update path without full reinstall; technical approach (diff/replace/preserve customizations) is PRD decision diff --git a/src/core-skills/bmad-help/SKILL.md b/src/core-skills/bmad-help/SKILL.md index e829543cf..62b06a747 100644 --- a/src/core-skills/bmad-help/SKILL.md +++ b/src/core-skills/bmad-help/SKILL.md @@ -33,16 +33,16 @@ When this skill completes, the user should: The catalog uses this format: ``` -module,skill,display-name,menu-code,description,action,args,phase,after,before,required,output-location,outputs +module,skill,display-name,menu-code,description,action,args,phase,preceded-by,followed-by,required,output-location,outputs ``` **Phases** determine the high-level flow: - `anytime` — available regardless of workflow state - Numbered phases (`1-analysis`, `2-planning`, etc.) flow in order; naming varies by module -**Dependencies** determine ordering within and across phases: -- `after` — skills that should ideally complete before this one -- `before` — skills that should run after this one +**Sequencing** determines recommended ordering within and across phases (these are soft suggestions, not hard gates — see `required` for gating): +- `preceded-by` — skills that should ideally complete before this one +- `followed-by` — skills that should ideally run after this one - Format: `skill-name` for single-action skills, `skill-name:action` for multi-action skills **Required gates**: diff --git a/src/core-skills/module-help.csv b/src/core-skills/module-help.csv index fec435f18..910411ada 100644 --- a/src/core-skills/module-help.csv +++ b/src/core-skills/module-help.csv @@ -1,4 +1,4 @@ -module,skill,display-name,menu-code,description,action,args,phase,after,before,required,output-location,outputs +module,skill,display-name,menu-code,description,action,args,phase,preceded-by,followed-by,required,output-location,outputs Core,_meta,,,,,,,,,false,https://docs.bmad-method.org/llms.txt, Core,bmad-brainstorming,Brainstorming,BSP,Use early in ideation or when stuck generating ideas.,,,anytime,,,false,{output_folder}/brainstorming,brainstorming session Core,bmad-party-mode,Party Mode,PM,Orchestrate multi-agent discussions when you need multiple perspectives or want agents to collaborate.,,,anytime,,,false,, diff --git a/tools/installer/core/installer.js b/tools/installer/core/installer.js index c52de9a7f..90bdf0fbb 100644 --- a/tools/installer/core/installer.js +++ b/tools/installer/core/installer.js @@ -12,6 +12,7 @@ const { BMAD_FOLDER_NAME } = require('../ide/shared/path-utils'); const { InstallPaths } = require('./install-paths'); const { ExternalModuleManager } = require('../modules/external-manager'); const { resolveModuleVersion } = require('../modules/version-resolver'); +const { MODULE_HELP_CSV_HEADER } = require('../modules/module-help-schema'); const { ExistingInstall } = require('./existing-install'); const { warnPreNativeSkillsLegacy } = require('./legacy-warnings'); @@ -951,7 +952,7 @@ class Installer { */ async mergeModuleHelpCatalogs(bmadDir, _agentEntries = []) { const allRows = []; - const headerRow = 'module,skill,display-name,menu-code,description,action,args,phase,after,before,required,output-location,outputs'; + const headerRow = MODULE_HELP_CSV_HEADER; const COLUMN_COUNT = 13; const PHASE_INDEX = 7; @@ -984,9 +985,19 @@ class Installer { const content = await fs.readFile(helpFilePath, 'utf8'); const lines = content.split('\n').filter((line) => line.trim() && !line.startsWith('#')); + let headerWarned = false; for (const line of lines) { - // Skip header row + // Header row: warn on drift from canonical schema, then skip. + // Data rows are loaded positionally regardless, so the warning + // is advisory — the maintainer should rename their columns. if (line.startsWith('module,')) { + if (!headerWarned && line.trim() !== headerRow) { + await prompts.log.warn( + ` ${moduleName}/module-help.csv header does not match canonical schema. ` + + `Expected: ${headerRow} | Found: ${line.trim()} | Data loaded positionally.`, + ); + headerWarned = true; + } continue; } diff --git a/tools/installer/modules/module-help-schema.js b/tools/installer/modules/module-help-schema.js new file mode 100644 index 000000000..08951b808 --- /dev/null +++ b/tools/installer/modules/module-help-schema.js @@ -0,0 +1,13 @@ +/** + * Canonical schema for per-module `module-help.csv` files. + * + * Both the merger (`Installer.mergeModuleHelpCatalogs`) and the synthesizer + * (`PluginResolver._buildSynthesizedHelpCsv`) emit this exact header. The + * merger compares each per-module file's header against this string and + * warns on drift, so any rename here must be matched in external module + * authors' CSVs (or accepted as a positional fall-through with a warning). + */ +const MODULE_HELP_CSV_HEADER = + 'module,skill,display-name,menu-code,description,action,args,phase,preceded-by,followed-by,required,output-location,outputs'; + +module.exports = { MODULE_HELP_CSV_HEADER }; diff --git a/tools/installer/modules/plugin-resolver.js b/tools/installer/modules/plugin-resolver.js index 58e20ab88..8cef26d27 100644 --- a/tools/installer/modules/plugin-resolver.js +++ b/tools/installer/modules/plugin-resolver.js @@ -1,6 +1,7 @@ const fs = require('../fs-native'); const path = require('node:path'); const yaml = require('yaml'); +const { MODULE_HELP_CSV_HEADER } = require('./module-help-schema'); /** * Resolves how to install a plugin from marketplace.json by analyzing @@ -338,8 +339,7 @@ class PluginResolver { * @returns {string} CSV content */ _buildSynthesizedHelpCsv(moduleName, skillInfos) { - const header = 'module,skill,display-name,menu-code,description,action,args,phase,after,before,required,output-location,outputs'; - const rows = [header]; + const rows = [MODULE_HELP_CSV_HEADER]; for (const info of skillInfos) { const displayName = this._formatDisplayName(info.name || info.dirName);