Compare commits
6 Commits
62c5582fc8
...
315497d9d8
| Author | SHA1 | Date |
|---|---|---|
|
|
315497d9d8 | |
|
|
0b11b48dcf | |
|
|
9ed88e428a | |
|
|
75e1fa2323 | |
|
|
e6cdc93b79 | |
|
|
e174bebc60 |
|
|
@ -13,7 +13,7 @@
|
||||||
"name": "bmad-pro-skills",
|
"name": "bmad-pro-skills",
|
||||||
"source": "./",
|
"source": "./",
|
||||||
"description": "Next level skills for power users — advanced prompting techniques, agent management, and more.",
|
"description": "Next level skills for power users — advanced prompting techniques, agent management, and more.",
|
||||||
"version": "6.3.0",
|
"version": "6.6.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Brian (BMad) Madison"
|
"name": "Brian (BMad) Madison"
|
||||||
},
|
},
|
||||||
|
|
@ -35,7 +35,7 @@
|
||||||
"name": "bmad-method-lifecycle",
|
"name": "bmad-method-lifecycle",
|
||||||
"source": "./",
|
"source": "./",
|
||||||
"description": "Full-lifecycle AI development framework — agents and workflows for product analysis, planning, architecture, and implementation.",
|
"description": "Full-lifecycle AI development framework — agents and workflows for product analysis, planning, architecture, and implementation.",
|
||||||
"version": "6.3.0",
|
"version": "6.6.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Brian (BMad) Madison"
|
"name": "Brian (BMad) Madison"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
26
CHANGELOG.md
26
CHANGELOG.md
|
|
@ -1,5 +1,31 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v6.6.0 - 2026-04-28
|
||||||
|
|
||||||
|
### 💥 Breaking Changes
|
||||||
|
|
||||||
|
* `--tools none` is no longer accepted; fresh `--yes` installs now require an explicit `--tools <id>`. Existing-install flows are unchanged. Run `npx bmad-method --list-tools` to see supported IDs (#2346)
|
||||||
|
* `project_name` has moved from `[modules.bmm]` to `[core]` in `config.toml`. Existing installs are auto-migrated on next install/update — no manual action required (#2348)
|
||||||
|
|
||||||
|
### 🎁 Features
|
||||||
|
|
||||||
|
* **Non-interactive config for CI/Docker** — new `--set <module>.<key>=<value>` (repeatable) and `--list-options [module]` flags allow installer configuration without prompts. Routes values to the correct config file with prototype-pollution defenses (#2354)
|
||||||
|
* **Brownfield epic scoping** — Create Epics and Stories workflow now detects file-overlap between epics and applies an Implementation Efficiency principle plus a design completeness gate, reducing unnecessary file churn (#1826)
|
||||||
|
|
||||||
|
### 🐛 Fixes
|
||||||
|
|
||||||
|
* **Custom module installer** — Azure DevOps URLs now parse correctly with multi-segment paths and `_git` prefixes (#2269); HTTP (non-HTTPS) Git URLs are preserved for self-hosted servers (#2344); community installs route through `PluginResolver` so marketplace plugins with nested `module.yaml` install all skills (#2331); URL-source modules resolve from disk cache on re-install instead of warning (#2323); local `--custom-content` modules resolve correctly and `[modules.<code>]` TOML keys use the module code rather than display name (#2316); `--yes` with `--custom-source` now runs the full update path so version tags are respected (#2336)
|
||||||
|
* **Installer safety** — `--list-tools` flag added; empty/typo'd tool IDs rejected with specific errors (#2346)
|
||||||
|
* **Channel and dist-tag handling** — installer launched from a prerelease (e.g. `@next`) now defaults external module channels to `next` instead of silently downgrading to stable (#2321); stable publishes advance the `@next` dist-tag so prerelease users no longer leapfrog or miss update notifications (#2320)
|
||||||
|
* **Architecture validation gate** — step-07 validation template no longer ships pre-checked; status field is now templated against actual checklist completion (#2347)
|
||||||
|
* **bmad-help data integrity** — `bmad-help.csv` is no longer transformed at merge time and is emitted in its documented schema; 31 misaligned rows in core/bmm `module-help.csv` repaired (#2349)
|
||||||
|
* **Config robustness** — malformed `module.yaml` (scalars, arrays) is now rejected before crash (#2348)
|
||||||
|
* **Legacy cleanup** — pre-v6.2.0 wrapper skills (`bmad-bmm-*`, `bmad-agent-bmm-*`) are removed automatically on upgrade so they no longer error with missing-file warnings (#2315)
|
||||||
|
|
||||||
|
### 📚 Docs
|
||||||
|
|
||||||
|
* Complete Chinese (zh-CN) translations for `named-agents.md` and `expand-bmad-for-your-org.md`; localized BMad Ecosystem sidebar (CIS, BMB, TEA, WDS) across zh-cn, vi-vn, fr-fr, cs-cz (#2355)
|
||||||
|
|
||||||
## v6.5.0 - 2026-04-26
|
## v6.5.0 - 2026-04-26
|
||||||
|
|
||||||
### 🎁 Features
|
### 🎁 Features
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "bmad-method",
|
"name": "bmad-method",
|
||||||
"version": "6.5.0",
|
"version": "6.6.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "bmad-method",
|
"name": "bmad-method",
|
||||||
"version": "6.5.0",
|
"version": "6.6.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@clack/core": "^1.0.0",
|
"@clack/core": "^1.0.0",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package.json",
|
"$schema": "https://json.schemastore.org/package.json",
|
||||||
"name": "bmad-method",
|
"name": "bmad-method",
|
||||||
"version": "6.5.0",
|
"version": "6.6.0",
|
||||||
"description": "Breakthrough Method of Agile AI-driven Development",
|
"description": "Breakthrough Method of Agile AI-driven Development",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"agile",
|
"agile",
|
||||||
|
|
|
||||||
|
|
@ -574,22 +574,66 @@ async function runTests() {
|
||||||
const tempProjectDir17 = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-copilot-test-'));
|
const tempProjectDir17 = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-copilot-test-'));
|
||||||
const installedBmadDir17 = await createTestBmadFixture();
|
const installedBmadDir17 = await createTestBmadFixture();
|
||||||
|
|
||||||
// Extend the fixture: add a persona-style agent skill (`-agent-` in id)
|
// Extend the fixture to exercise the agents-only filter, which detects
|
||||||
// and the `bmad-tea` non-conventional agent so we can verify that the
|
// persona agents by the `[agent]` section in each skill's source
|
||||||
// agents-only filter routes them to .github/agents/ while leaving the
|
// customize.toml. Five skill types covered:
|
||||||
// workflow-style `bmad-master` out.
|
//
|
||||||
|
// 1. Persona agent — has customize.toml with [agent] → INCLUDED
|
||||||
|
// 2. Persona with non-conventional id — also has [agent] → INCLUDED
|
||||||
|
// (verifies the filter doesn't depend on `-agent-` naming)
|
||||||
|
// 3. Meta-skill whose id contains `-agent-` but isn't a
|
||||||
|
// persona — has customize.toml with [workflow] → EXCLUDED
|
||||||
|
// (mirrors `bmad-agent-builder` in the real manifest)
|
||||||
|
// 4. Workflow skill — no customize.toml at all → EXCLUDED
|
||||||
|
// 5. `bmad-help` — structural exception via ALWAYS_AGENT_IDS;
|
||||||
|
// has no customize.toml of its own but surfaces in the
|
||||||
|
// agents picker because it's the meta-help skill → INCLUDED
|
||||||
const fixtureCsvPath17 = path.join(installedBmadDir17, '_config', 'skill-manifest.csv');
|
const fixtureCsvPath17 = path.join(installedBmadDir17, '_config', 'skill-manifest.csv');
|
||||||
await fs.writeFile(
|
await fs.writeFile(
|
||||||
fixtureCsvPath17,
|
fixtureCsvPath17,
|
||||||
[
|
[
|
||||||
'canonicalId,name,description,module,path',
|
'canonicalId,name,description,module,path',
|
||||||
'"bmad-master","bmad-master","Workflow-style fixture (no -agent- in id, should NOT appear in Copilot agents picker)","core","_bmad/core/bmad-master/SKILL.md"',
|
'"bmad-master","bmad-master","Workflow with no customize.toml — should NOT appear in Copilot agents picker","core","_bmad/core/bmad-master/SKILL.md"',
|
||||||
'"bmad-agent-fixture","bmad-agent-fixture","Persona agent fixture (-agent- in id, SHOULD appear in Copilot agents picker)","core","_bmad/core/bmad-agent-fixture/SKILL.md"',
|
'"bmad-agent-fixture","bmad-agent-fixture","Persona agent — customize.toml has [agent], SHOULD appear","core","_bmad/core/bmad-agent-fixture/SKILL.md"',
|
||||||
'"bmad-tea","bmad-tea","Non-conventional persona agent fixture (Murat-style, SHOULD appear despite no -agent- segment)","core","_bmad/core/bmad-tea/SKILL.md"',
|
'"bmad-tea","bmad-tea","Non-conventional id but [agent] in customize.toml — SHOULD appear","core","_bmad/core/bmad-tea/SKILL.md"',
|
||||||
|
'"bmad-agent-builder","bmad-agent-builder","Skill-builder workflow — id contains -agent- but customize.toml has [workflow] — should NOT appear","core","_bmad/core/bmad-agent-builder/SKILL.md"',
|
||||||
|
'"bmad-help","bmad-help","Meta-help skill — no customize.toml but ALWAYS_AGENT_IDS exception; SHOULD appear in agents picker","core","_bmad/core/bmad-help/SKILL.md"',
|
||||||
'',
|
'',
|
||||||
].join('\n'),
|
].join('\n'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Materialise the source skill directories so the agents-only filter
|
||||||
|
// can read their customize.toml. The bmad-master and bmad-agent-builder
|
||||||
|
// SKILL.md files were already populated by createTestBmadFixture (they
|
||||||
|
// share the bmad-master target_dir layout); only the customize.toml
|
||||||
|
// and the new agent fixtures need to be created here.
|
||||||
|
for (const id of ['bmad-agent-fixture', 'bmad-tea', 'bmad-agent-builder', 'bmad-help']) {
|
||||||
|
const dir17 = path.join(installedBmadDir17, 'core', id);
|
||||||
|
await fs.ensureDir(dir17);
|
||||||
|
await fs.writeFile(
|
||||||
|
path.join(dir17, 'SKILL.md'),
|
||||||
|
['---', `name: ${id}`, `description: fixture for ${id}`, '---', '', `Body of ${id}.`].join('\n'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Note: bmad-help intentionally has NO customize.toml — it's the
|
||||||
|
// structural exception for which the ALWAYS_AGENT_IDS allowlist
|
||||||
|
// exists.
|
||||||
|
// [agent] customize.toml for the two persona fixtures.
|
||||||
|
await fs.writeFile(
|
||||||
|
path.join(installedBmadDir17, 'core', 'bmad-agent-fixture', 'customize.toml'),
|
||||||
|
['[agent]', 'name = "Fixture Agent"', 'title = "Test Persona"', ''].join('\n'),
|
||||||
|
);
|
||||||
|
await fs.writeFile(
|
||||||
|
path.join(installedBmadDir17, 'core', 'bmad-tea', 'customize.toml'),
|
||||||
|
['[agent]', 'name = "Murat"', 'title = "Test Architect"', ''].join('\n'),
|
||||||
|
);
|
||||||
|
// [workflow] customize.toml for the meta-skill — its id contains `-agent-`
|
||||||
|
// but it is NOT a persona (mirrors bmad-agent-builder in production).
|
||||||
|
await fs.writeFile(
|
||||||
|
path.join(installedBmadDir17, 'core', 'bmad-agent-builder', 'customize.toml'),
|
||||||
|
['[workflow]', '', '# Meta-skill that builds agents but is not itself a persona.', ''].join('\n'),
|
||||||
|
);
|
||||||
|
|
||||||
const copilotInstructionsPath17 = path.join(tempProjectDir17, '.github', 'copilot-instructions.md');
|
const copilotInstructionsPath17 = path.join(tempProjectDir17, '.github', 'copilot-instructions.md');
|
||||||
await fs.ensureDir(path.dirname(copilotInstructionsPath17));
|
await fs.ensureDir(path.dirname(copilotInstructionsPath17));
|
||||||
await fs.writeFile(
|
await fs.writeFile(
|
||||||
|
|
@ -625,19 +669,31 @@ async function runTests() {
|
||||||
'GitHub Copilot setup preserves user content in copilot-instructions.md',
|
'GitHub Copilot setup preserves user content in copilot-instructions.md',
|
||||||
);
|
);
|
||||||
|
|
||||||
// Custom Agents picker integration: persona agents (and bmad-tea) get
|
// Custom Agents picker integration: persona agents (those with [agent]
|
||||||
// .agent.md files in .github/agents/. Workflows do NOT — the
|
// in their source customize.toml) get .agent.md files in
|
||||||
// agents-only filter keeps the picker uncluttered.
|
// .github/agents/. Workflows and meta-skills with [workflow] (or no
|
||||||
|
// customize.toml at all) do NOT — the agents-only filter keeps the
|
||||||
|
// picker uncluttered and the signal is naming-independent.
|
||||||
const agentsDir17 = path.join(tempProjectDir17, '.github', 'agents');
|
const agentsDir17 = path.join(tempProjectDir17, '.github', 'agents');
|
||||||
const agentFileForPersona17 = path.join(agentsDir17, 'bmad-agent-fixture.agent.md');
|
const agentFileForPersona17 = path.join(agentsDir17, 'bmad-agent-fixture.agent.md');
|
||||||
const agentFileForTea17 = path.join(agentsDir17, 'bmad-tea.agent.md');
|
const agentFileForTea17 = path.join(agentsDir17, 'bmad-tea.agent.md');
|
||||||
const agentFileForWorkflow17 = path.join(agentsDir17, 'bmad-master.agent.md');
|
const agentFileForWorkflow17 = path.join(agentsDir17, 'bmad-master.agent.md');
|
||||||
|
const agentFileForMetaSkill17 = path.join(agentsDir17, 'bmad-agent-builder.agent.md');
|
||||||
|
const agentFileForBmadHelp17 = path.join(agentsDir17, 'bmad-help.agent.md');
|
||||||
|
|
||||||
assert(await fs.pathExists(agentFileForPersona17), 'Persona agent (-agent- in id) gets a .agent.md file in .github/agents/');
|
|
||||||
assert(await fs.pathExists(agentFileForTea17), 'bmad-tea persona (non-conventional id) is allowlisted into .github/agents/');
|
|
||||||
assert(
|
assert(
|
||||||
!(await fs.pathExists(agentFileForWorkflow17)),
|
await fs.pathExists(agentFileForPersona17),
|
||||||
'Workflow skill (no -agent- in id, not in allowlist) is FILTERED OUT of .github/agents/',
|
'Persona agent ([agent] in customize.toml) gets a .agent.md file in .github/agents/',
|
||||||
|
);
|
||||||
|
assert(await fs.pathExists(agentFileForTea17), 'Non-conventional id with [agent] in customize.toml is included (no allowlist needed)');
|
||||||
|
assert(!(await fs.pathExists(agentFileForWorkflow17)), 'Workflow skill (no customize.toml) is FILTERED OUT of .github/agents/');
|
||||||
|
assert(
|
||||||
|
await fs.pathExists(agentFileForBmadHelp17),
|
||||||
|
'bmad-help is INCLUDED in agents picker via ALWAYS_AGENT_IDS exception (structural meta-skill, no customize.toml)',
|
||||||
|
);
|
||||||
|
assert(
|
||||||
|
!(await fs.pathExists(agentFileForMetaSkill17)),
|
||||||
|
'Meta-skill with -agent- in id but [workflow] in customize.toml is FILTERED OUT (signal is behavior, not naming)',
|
||||||
);
|
);
|
||||||
|
|
||||||
// Body content of the persona agent file: frontmatter description +
|
// Body content of the persona agent file: frontmatter description +
|
||||||
|
|
|
||||||
|
|
@ -57,22 +57,46 @@ function isSafeCanonicalId(value) {
|
||||||
// OpenCode's native `@skills/<id>` skill-reference syntax.
|
// OpenCode's native `@skills/<id>` skill-reference syntax.
|
||||||
const DEFAULT_COMMANDS_BODY_TEMPLATE = '@skills/{canonicalId}';
|
const DEFAULT_COMMANDS_BODY_TEMPLATE = '@skills/{canonicalId}';
|
||||||
|
|
||||||
// Persona-agent id outside the `-agent-` naming convention.
|
// `bmad-help` is the structural meta-skill across BMAD: the orientation
|
||||||
// TEA's Murat is the only persona whose canonical id is the bare module code
|
// helper that points users at every other skill. It is invoked
|
||||||
// rather than `<module>-agent-<role>`. Listed here so platforms that filter
|
// persona-style ("ask the helper") even though it has no [agent]
|
||||||
// for "agents only" (e.g. GitHub Copilot's Custom Agents picker) include it.
|
// customize.toml of its own (it isn't a configurable persona). Surfacing
|
||||||
const NON_CONVENTIONAL_AGENT_IDS = new Set(['bmad-tea']);
|
// it in agents-picker contexts mirrors how users actually reach for it,
|
||||||
|
// and the inclusion is unique and stable — there is no second meta-help
|
||||||
|
// skill to encourage growth of this exception.
|
||||||
|
const ALWAYS_AGENT_IDS = new Set(['bmad-help']);
|
||||||
|
|
||||||
// Is this skill a persona agent (vs. a workflow/tool/standalone skill)?
|
// Is this skill a persona agent (vs. a workflow/tool/standalone skill)?
|
||||||
// Used by platforms that surface only persona agents (e.g. Copilot's Custom
|
// Used by platforms that surface only persona agents (e.g. Copilot's Custom
|
||||||
// Agents picker). Rule: canonical id contains `-agent-` OR is in the
|
// Agents picker). Signal: the skill's source `customize.toml` has an
|
||||||
// known non-conventional allowlist. Tested against the full installed
|
// `[agent]` section. This is the actual configuration source of truth —
|
||||||
// manifest — catches all 20 description-confirmed personas across BMM,
|
// every BMAD persona is configured via [agent] in its customize.toml,
|
||||||
// CIS, GDS, WDS, TEA without false positives.
|
// every workflow uses [workflow], every standalone skill has no
|
||||||
function isAgentSkill(canonicalId) {
|
// customize.toml at all. Verified against the full installed manifest:
|
||||||
if (typeof canonicalId !== 'string') return false;
|
// catches exactly the 20 description-confirmed personas across BMM, CIS,
|
||||||
if (NON_CONVENTIONAL_AGENT_IDS.has(canonicalId)) return true;
|
// GDS, WDS, TEA, and correctly excludes meta-skills like
|
||||||
return canonicalId.includes('-agent-');
|
// `bmad-agent-builder` (a skill-builder workflow whose canonical id
|
||||||
|
// contains `-agent-` but which has no [agent] section because it isn't a
|
||||||
|
// persona itself). Plus the explicit `ALWAYS_AGENT_IDS` set for the one
|
||||||
|
// structural exception (`bmad-help`).
|
||||||
|
//
|
||||||
|
// Reading the source toml — at install time the source skill directory
|
||||||
|
// (resolved from manifest record.path) still exists; cleanup runs later
|
||||||
|
// in the install flow.
|
||||||
|
async function isAgentSkill(record, bmadDir) {
|
||||||
|
if (!record?.path || !bmadDir) return false;
|
||||||
|
if (record.canonicalId && ALWAYS_AGENT_IDS.has(record.canonicalId)) return true;
|
||||||
|
const bmadFolderName = path.basename(bmadDir);
|
||||||
|
const bmadPrefix = bmadFolderName + '/';
|
||||||
|
const relativePath = record.path.startsWith(bmadPrefix) ? record.path.slice(bmadPrefix.length) : record.path;
|
||||||
|
const tomlPath = path.join(bmadDir, path.dirname(relativePath), 'customize.toml');
|
||||||
|
if (!(await fs.pathExists(tomlPath))) return false;
|
||||||
|
try {
|
||||||
|
const content = await fs.readFile(tomlPath, 'utf8');
|
||||||
|
return /^\[agent\]/m.test(content);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve placeholders in a body template. Supported placeholders:
|
// Resolve placeholders in a body template. Supported placeholders:
|
||||||
|
|
@ -319,7 +343,7 @@ class ConfigDrivenIdeSetup {
|
||||||
// persona agents (e.g. Copilot's Custom Agents picker) skip
|
// persona agents (e.g. Copilot's Custom Agents picker) skip
|
||||||
// workflow/tool skills here so the picker isn't cluttered with
|
// workflow/tool skills here so the picker isn't cluttered with
|
||||||
// 90+ unrelated entries.
|
// 90+ unrelated entries.
|
||||||
if (filter === 'agents-only' && !isAgentSkill(canonicalId)) {
|
if (filter === 'agents-only' && !(await isAgentSkill(record, bmadDir))) {
|
||||||
result.skippedFiltered++;
|
result.skippedFiltered++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -136,12 +136,16 @@ platforms:
|
||||||
commands_extension: .agent.md
|
commands_extension: .agent.md
|
||||||
commands_body_template: "LOAD the FULL {project-root}/{target_dir}/{canonicalId}/SKILL.md, READ its entire contents and follow its directions exactly!"
|
commands_body_template: "LOAD the FULL {project-root}/{target_dir}/{canonicalId}/SKILL.md, READ its entire contents and follow its directions exactly!"
|
||||||
# The Custom Agents picker should only show persona agents (not
|
# The Custom Agents picker should only show persona agents (not
|
||||||
# workflows/tools). BMAD's persona agents are conventionally named
|
# workflows/tools). Detected by reading each skill's source
|
||||||
# with an `-agent-` segment in their canonical id (e.g.
|
# `customize.toml` and checking for an `[agent]` section — that's
|
||||||
# `bmad-agent-pm`, `gds-agent-game-dev`, `wds-agent-freya-ux`,
|
# the actual configuration source of truth: every BMAD persona is
|
||||||
# `bmad-cis-agent-storyteller`). The one exception is `bmad-tea` —
|
# configured under `[agent]`, every workflow under `[workflow]`,
|
||||||
# TEA's Murat persona uses the module code as its id rather than the
|
# every standalone skill has no customize.toml. This signal is
|
||||||
# `-agent-` convention. This filter keeps the picker uncluttered.
|
# naming-independent, so personas like `bmad-tea` (which doesn't
|
||||||
|
# follow the `-agent-` convention) are still included, and
|
||||||
|
# meta-skills like `bmad-agent-builder` (which contains `-agent-`
|
||||||
|
# but is a skill-builder workflow, not a persona) are correctly
|
||||||
|
# excluded.
|
||||||
commands_filter: agents-only
|
commands_filter: agents-only
|
||||||
|
|
||||||
goose:
|
goose:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue