* feat(bmad-spec): add Spec kernel distiller skill
New 2-plan-workflows skill that distills any intent input (brain dump,
PRD, transcript, brief) into a spec.md carrying the five-field kernel:
Problem, Capabilities, Constraints, Non-goals, Success signal. Headless
callers receive JSON; interactive runs close conversationally with the
spec path and gap-coverage invitations.
Includes:
- SKILL.md with activation contract and conventions
- customize.toml exposing template path, output path, run-folder pattern
- assets/spec-template.md (five-field skeleton)
- assets/headless-schemas.md (JSON IO contracts)
* remove brain-dump fallback config from bmad-spec customize.toml
* refactor(bmad-spec): companions+sources model, routing tilt, flat output path
- Collapse `related:` into `companions:`; companion paths may point inside the spec folder (spec-authored) or outside it (adopted from an upstream skill), distinguished implicitly by path
- `sources:` reserved for fully-absorbed inputs; downstream does NOT read these
- Soften mutation contract: bmad-spec owns SPEC.md and spec-authored companions; adopted companions belong to their originating skill
- Add "when to spawn a companion" tilt: multi-item catalogs, tables, diagrams (always), editorial voice rules; sub-bullets in a kernel field signal it has outgrown the kernel
- Fix Spec Law rule 7 and Pass 2: load-bearing content lands in SPEC.md or a companion, not the decision log (the log records wrapper-drops only)
- Flatten output path to `{planning_artifacts}/specs/spec-{slug}-{date}/`, mirroring `prds/` and `ux-designs/`; drop `spec_folder_name` (no longer used)
- Extract Load-bearing definition into its own section above Spec Law
* chore(core): retire bmad-distillator, promote bmad-spec to core
- Delete bmad-distillator/ and all registry + doc references (superseded by bmad-spec; no skill or workflow in any BMad module invoked it)
- Add bmad-distillator to removals.txt so installer cleans it from existing IDE skill directories on update
- Move bmad-spec from bmm-skills/2-plan-workflows/ to core-skills/ (universal scope: game design, research hypotheses, editorial briefs, policy, business plans, not just software)
- Register bmad-spec in core module-help.csv and bmad-pro-skills marketplace plugin
- Drop bmad-distillator section from core-tools.md (en, vi-vn, cs, fr, zh-cn) and vi-vn dev guide; renumber subsequent sections
* refactor(bmad-spec): add lean-prose discipline + generalize help text
- Add Spec Law rule 8: lean prose. Every sentence carries load-bearing content; cut decoration, hedges, backstory, throat-clearing. Applies to SPEC.md, companions, and decision log.
- Update Self-Validate Pass 1 to enforce rules 1-6 and 8 (rule 7 stays in Pass 2)
- Prime the operation up-front: write lean from the first pass, every sentence must earn its place
- Note in Companions section that companions follow the same lean discipline
- Generalize core module-help.csv entry: domain-agnostic framing (software, game design, research, editorial, policy, business, anything intent-bearing); call out succinct, no-fluff and "locks the WHAT before the HOW" as the value props
* fix(bmad-spec): address PR review findings (CodeRabbit + Augment)
- headless-schemas.md: rewrite spec_path examples to point at the spec folder (not a file), rename source_artifact to sources[] array, add companions[] array, update verdict from "six rules" to "eight rules", disambiguate reason requirement (only when status=blocked)
- SKILL.md activation: fix config path from {project-root}/_bmad/config.yaml to {project-root}/_bmad/core/config.yaml (matches other BMM skills)
- customize.toml + SKILL.md Workspace: drop {date} from default run_folder_pattern (spec-{slug}); same slug = same folder = trivial in-place update, no glob-and-pick-most-recent needed. Override available for users who want dated history.
- spec-template.md: rename "## Success signals" (plural) to "## Success signal" (singular) to match SKILL.md kernel naming
- SKILL.md Frontmatter conventions: fix adopted-companion example path from _bmad-output/ux-designs/foo-ux/DESIGN.md to ../../ux-designs/ux-foo-bar-2026-05-23/DESIGN.md (matches actual flat-output convention)
- SKILL.md Spec Law: fix double-period typo in rule 2 ((stack, conventions)..)
- SKILL.md Overview: fix awkward "bloat with expansive line item details the kernel" phrasing; drop software-flavored downstream consumer list since bmad-spec is now a core skill serving any domain
* fix(bmad-spec): drop {planning_artifacts} dependency; output to {output_folder}/specs
bmad-spec is a core skill but its default path used {planning_artifacts}, a bmm-module variable. Core-only installs (no bmm) would fail at activation when the resolver tried to expand the path.
Land specs directly under {output_folder}/specs/spec-{slug}/ instead. Works in any install regardless of installed modules, and aligns with the long-term BMad direction of grouping artifacts as siblings under {output_folder}/<type>/ rather than nested under planning vs implementation parents.
In bmm installs, adopted-companion paths from spec to UX/PRD pick up one extra .. (e.g., ../planning-artifacts/ux-designs/<run>/DESIGN.md) since the spec folder is now one level up from planning-artifacts. Examples in SKILL.md and headless-schemas.md updated. module-help.csv output-location updated and stale -{date} fragment removed.
* docs(bmad-spec): add reference docs, trim headless schema, tighten defaults
- Add full bmad-spec entry to docs/reference/core-tools.md and table-row
stubs to cs/fr/vi-vn/zh-cn (full translation pending).
- Strip headless-schemas.md to a minimal {status, files} success response
and {status, error_code, reason} blocked response. Drop spec_path,
capabilities, verdict, decision_log_path — all derivable from the files
themselves.
- Narrow customize.toml persistent_facts default from recursive glob to
single {project-root}/project-context.md; document override path.
- Drop unused {doc_workspace} convention line from SKILL.md.
- Clarify Self-Validate verdict handling for interactive vs headless.
- Document missing_slug error code in SKILL.md + headless schema.
* refactor(bmad-ux): replace bmad-create-ux-design with lean spine-based bmad-ux
* refactor(bmad-ux): adopt DESIGN.md spec, split into two-file spine, align prd/brief
DESIGN.md (visual identity per the Google Labs spec) and EXPERIENCE.md
(behavior, flow, IA) replace the single design.md spine. EXPERIENCE.md
cross-references DESIGN.md tokens via the spec's {path.to.token} syntax.
Example suite restructure
- 3 DESIGN.md examples: editorial (Stitch source / Linen & Logic), calm
native mobile (Quill), shadcn-on-Tailwind web SaaS (Drift)
- 2 paired EXPERIENCE.md examples (Quill, Drift); Linen & Logic unpaired
to model the Stitch handoff scenario
- Replaces the prior 2-example combined spine set
Discovery additions (outcome-driven, one line each)
- Source scan: glob {planning_artifacts}/ for candidates, parent never reads
- Form-factor: resolve before IA closes; journeys often derive it
- Surface closure: every stated need has a surface, every surface a journey
- Named-protagonist journeys (Mary, not "the user")
- Design handoff working mode (extensible producer registry, default: Stitch)
PRD and brief alignment with same insights
- bmad-prd: dropped standalone Primary Persona section from template;
renamed "Personas + Journeys" entry to "Journey-led"; named-protagonist
rule on UJs; form-factor probe; validation checklist updated
- bmad-product-brief: form-factor surfaced in Discovery topics
Quality scan fixes
- Added ## Overview heading; renamed ## Activation to ## On Activation
- Replaced ../ paths in example assets with {planning_artifacts}/
- Sources section compressed (abstract delta-only rule)
- Working mode aligned to "Fast path" / "Coaching path" BMad-wide convention
New
- references/design-md-spec.md: working summary of the spec for the LLM
- customize.toml: design_md_examples, experience_md_examples,
design_handoffs registries
- .prettierignore: ignore .analysis/ quality-scan artifacts repo-wide
* refactor(bmad-ux): activation parity with prd/brief, opt-in reviewer gate, no headline grade
- Restructure On Activation as numbered six-step list mirroring bmad-prd
and bmad-product-brief, restoring the explicit key-resolution list that
earlier crammed-paragraph form had dropped (planning_artifacts and
friends were silently unresolved at Create).
- Make Reviewer Gate opt-in and lens-selectable. At Finalize, ask before
spending tokens on parallel reviewer subagents; at Validate intent,
skip that question but still confirm lens picks. Stops the auto-run
WCAG audit on hobby-stakes work.
- Drop the overall validation grade. Per-category verdicts and severity
counts already say what is true; a single headline grade conflated
design rigor with release readiness and led "POOR" pills landing on
reports whose own bodies described the work as strong. Removed from
references/validate.md (ladder rule + markdown twin), HTML template
(grade pill div + CSS vars + classes).
- Trim creative-tools.md: drop the Custom entries section. Runtime
prompt files should only carry what the LLM needs to act in this
moment; how-to-extend-via-TOML is setup-time human documentation
already covered by customize.toml comments.
* fix(bmad-ux): align validation report template with 8-category rubric
Template placeholders referenced 'Decision-readiness' and 'seven dimensions'
from the prior rubric. Replace with TEMPLATE_CATEGORY_NAME and inline the
eight canonical categories from references/validate.md so the synthesis pass
names them verbatim.
* fix(validate-skills): remove stale WF-01/WF-02 rules
WF-01/WF-02 were originally scoped to workflow.md files (now mostly gone)
but had been generalized to flag name/description in any non-SKILL.md
markdown. That over-captured legitimate spec files — e.g. DESIGN.md
examples in bmad-ux/assets/ that carry name/description per the Google
Labs DESIGN.md spec.
Step files are already covered by STEP-06. Rule count: 14 → 12.
* fix(bmad-ux): address PR review followups
- validation-report-template.html: severity badge class is badge-sev-*,
not sev-* (the comment misled the synthesis pass).
- Sweep dangling bmad-create-ux-design references: module-help.csv,
bmad-agent-ux-designer/customize.toml, bmad-prd/SKILL.md handoff list,
workflow-map.md (en + 4 translations), getting-started.md (en + 4
translations). Workflow-map output column updated to DESIGN.md +
EXPERIENCE.md.
- references/validate.md: Markdown capitalized as a proper noun.
Documents the fix landed in #2391 and the manual step required for users
who installed the experimental BMad Automator module under its previous
`baut` code.
* fix(installer): preserve stale installed modules on update
* test: drop stale baut regression case
* fix(installer): preserve source-backed modules and configs
* fix(installer): retain preserved module config in quick update
* fix(installer): preserve module config blocks for retained modules
* fix(installer): preserve user-scope blocks for retained modules
* fix(installer): retain stale modules during updates
* feat(installer): bundle module registry, retire marketplace, refresh display names
Prepares v6.7.0 for release:
- Moves bundled module list from tools/installer/modules/registry-fallback.yaml
to bmad-modules.yaml at repo root; renames to reflect single-source-of-truth role.
- Retires the remote marketplace registry fetch in ExternalModuleManager; the
installer now reads the bundled YAML only.
- Adds WDS (Whiteport Design Studio) entry alongside BMM, BMB, BMA, CIS, GDS, TEA.
- Refreshes display names and descriptions on every bundled module; TEA
repositioned after BMM in the picker.
- Adds plugin_name override field on registry entries so modules whose
marketplace.json declares a plugin under a different name than the installer
code (e.g. WDS uses bmad-wds) match without falling back to the single-plugin
heuristic.
- Removes the community modules picker from the interactive installer; previously
installed community modules are preserved on update and can still be installed
via --custom-source.
- Renames the custom-source confirm prompt for clarity.
CHANGELOG.md updated with the full v6.7.0 entry.
* feat(installer): fully retire community catalog plumbing
Removes the last marketplace network connections from the installer.
The v6.7.0 first pass retired the official-registry fetch but left
CommunityModuleManager + RegistryClient in place, which still
fetched community-index.yaml and categories.yaml on every install
to support the channel-gate and update flows.
This commit:
- Deletes tools/installer/modules/community-manager.js and
registry-client.js entirely.
- Strips CommunityModuleManager calls from ui.js (channel gate +
update channels), core/manifest.js (getModuleVersionInfo),
core/installer.js (resolution + installed-modules listing), and
modules/official-modules.js (findModuleSource fallback +
pre-install plugin resolution + post-install manifest entry).
- Simplifies installFromResolution: community branch removed; all
non-external installs are now treated as custom-source.
- Removes corresponding test suites (CommunityModuleManager unit
tests and the entire RegistryClient suite).
- Updates CHANGELOG with the migration note.
After this commit, grep confirms zero references to the bmad-plugins-
marketplace registry from the installer. The only remaining 'marketplace'
references are about per-repo .claude-plugin/marketplace.json files,
which the installer reads from cloned custom-source repos.
* feat(bmad-prd): voice rules, probing reference, and operational hardening
- Session Posture section (voice prohibitions, record-as-you-go, anti-caving, register-matching)
- New references/probing.md: seven probing categories, six critical assumptions, PRD/solution-design boundary
- Intent detection signals (create/update/validate) on activation step 6
- Update intent: inline conflict-detection procedure against decision-log.md
- Activation step 1 falls back to customize.toml instead of halting on resolver failure
- Restructure Discovery into five sub-sections (Posture, Brain dump, Four-dimension read, Right-skill check, Working mode)
- Regroup PRD Discipline into three clusters (Artifact shape, Substance, Honesty about scope)
- Define phase-blockers in Finalize step 4
- Em-dash strip in prose; preserve [v2 — out of MVP] callout convention
- Move bmad-party-mode / bmad-advanced-elicitation mention into the greeting step
* feat(bmad-prd): funnel discipline, UJ depth, and UX reframing
Template discipline for downstream AI extraction:
- §3 Glossary: exact-use enforcement (FRs, UJs, SMs use Glossary terms verbatim)
- §4 Features: FRs now use "#### FR-N: Name" heading with Realizes UJ-X cross-reference, testable consequences, and optional per-FR Out of Scope
- §7 Success Metrics: SM-N / SM-CN numbering with Validates FR-X cross-reference
User journeys:
- §2.4 UJ format expanded from one-liner to named-persona mini-flow (persona, 3-5 steps, edge cases, optional capability surfacing); hobby can collapse to one-liners
- Strip "job of UX" / "not this PRD" gatekeeping from template; depth is the team's call
- Strengthen UX-as-input / UX-as-output patterns for bidirectional PRD <-> UX flow
- SKILL.md Discovery Posture: push for two to three named-persona UJs in non-trivial scope
Validation checklist:
- Q-3 Traceability tightened to require Realizes UJ-X on FRs and Validates FR-X on SMs
- Q-7 (new): FR testability — every FR has at least one testable consequence
- S-1 Glossary integrity: now covers FR descriptions, consequences, UJ flows, SM definitions
- S-2: SM added to ID continuity scope
- S-5 (new): UJ persona linkage — every UJ names a persona by exact §2 label
- STK-2 (new): UJ density gate — non-hobby scope needs at least two UJs
* docs(bmad-prd): anonymize validation-findings JSON example
Replace project-specific values (Plantsona prd_name, frozen timestamp, §16 location, premium-conversion finding) with generic placeholder content. Swap the example finding to demonstrate Q-7 FR testability so it doubles as a primer on the new checklist item.
* feat(bmad-prd): reviewer pass redesign and consolidate facilitation
- finalize_reviewers TOML field replaces inline review lenses; entries
follow the skill:/file:/plain-text prefix convention, resolved on-demand
so reviewer data has zero context cost on runs that skip the pass.
- Subagent contract: reviewers write to {doc_workspace}/review-{slug}.md
and return summary-only (verdict, top findings, file path); parent
never holds full review text.
- Section-by-section walk-through UX at Finalize and Validate; user
decides per finding whether to autofix, discuss, defer, or ignore.
- Finalize entry names the sequence in one sentence so users understand
the polish-last order.
- Template philosophy moved from prd-template.md to SKILL.md PRD
Discipline; template is now pure shape menu (preamble and Notes for
facilitator stripped).
- facilitation-guide.md content folded into SKILL.md Discovery posture
(story-shape UJ walk, four MVP types, state-inference-don't-quiz);
guide file deleted.
* feat(bmad-prd): tighten SKILL.md, extract Reviewer Gate and Validate playbook
- SKILL.md: trim activation/posture/discovery bloat; sharpen Right-skill
check; extract Reviewer Gate to its own section (dedup with Finalize
step 3 and Validate intent).
- references/validate.md: rename from validation-render.md and expand to
the full Validate intent playbook (orient, run gate, structural
validator pipeline, render, close).
- references/probing.md: drop stale facilitation-guide.md reference.
- assets/prd-template.md: redesign §2.4 User Journeys with named-scene
default shape, worked example, and scope dial.
* fix(bmad-prd): make Brain dump a hard first-move rule
Discovery was being skipped: the LLM treated the user's opening
message as the full picture and jumped to multiple-choice intake.
Strengthen the ordering so Brain dump always comes first for Create
and Update, before any questions or working-mode choices.
- Add explicit Discovery ordering at the section top.
- Rewrite Brain dump as a non-negotiable first move with an anti-
pattern callout naming the exact failure mode.
- Add timing prefix to Working mode reinforcing the order.
* refactor(bmad-prd): aggressive trim and quality fixes from analysis
SKILL.md cut 49% (143 -> 84 lines); references/validate.md 35%;
references/headless.md 22%. Package-wide ~21% reduction.
Customization sweep:
- {finalize_reviewers} -> {workflow.finalize_reviewers} (was a silent
override no-op)
- Add canonical ## Conventions block
- Rename decision-log.md -> .decision-log.md across SKILL, refs, schemas
- customize.toml: validation_checklist -> validation_checklist_template,
output_dir -> prd_output_path, output_folder_name -> run_folder_pattern;
lifecycle comments on external_sources / external_handoffs
New behavior:
- Activation step 4: explicit by-name greeting using {user_name},
{communication_language} persisted for every turn (not just greeting)
- Right-skill scan on first message before brain dump
- Neutral defaults when config.yaml is missing; never block on it
- Headless: Detection section + per-intent Inputs section + 'partial'
status semantics + Update conflict-override rationale
- Brownfield Update bootstraps .decision-log.md via subagent when absent
- Reviewer Gate findings-overwhelm fix: tiered surfacing
(verdict -> critical/high -> medium/low rolled into tail)
- Discovery edge cases: conditional MVP question, persona/UJ push
contextually triggered, working modes renamed as outcomes
(Fast path / Coaching path)
- Subagent discipline: Finalize step 2 return-format contract,
step 5 structure->prose ordering, explicit no-subagent fallback
Tests:
- scripts/tests/test_render_validation_html.py (17 passing, covers
grade thresholds, category mapping, stats, score-bar rendering)
* refactor(bmad-prd): replace mechanical checklist+renderer with quality rubric and LLM-synthesized report
The structural checklist + Python renderer produced mechanical pass/warn/fail
reports that didn't speak to actual PRD quality, and additional reviewers
(adversarial) wrote separate review-*.md files that never made it into the
HTML. Replaces that pipeline with:
- A judgment rubric across seven PRD-quality dimensions (decision-readiness,
substance over theater, strategic coherence, done-ness clarity, scope
honesty, downstream usability, shape fit) that adapts to stakes and PRD
shape. Rubric walker writes review-rubric.md with per-dimension verdicts.
- HTML skeleton with TEMPLATE_* placeholders the synthesis pass fills
directly — no substitution engine, no Python.
- Synthesis pipeline in references/validate.md: parent reads every
review-*.md, fills the skeleton, writes validation-report.html plus
markdown twin, opens via webbrowser. Folds every reviewer's findings
into one report; grade derives from rubric verdicts and severity counts.
- Drops scripts/render-validation-html.py and scripts/tests/ entirely.
- finalize_reviewers defaults to empty (adversarial removed from defaults —
too brutal and frequently wrong against PRDs; teams can append in
override TOML).
- Headless mode now writes both HTML and markdown; skips browser-open.
* refactor(bmad-prd): faster working-mode entry, elicitation discipline, drop probing.md
Discovery rewrite: Brain dump -> Stakes calibration -> Working mode -> mode-scoped
work. Users in a hurry reach the Fast/Coaching choice in two or three turns instead
of ten. Brain dump explicitly invites existing inputs (briefs, research,
transcripts, prior PRD draft, design docs) alongside verbal context.
Elicitation discipline made explicit: Discovery pulls the user's vision out, never
inserts the LLM's. UJs and phasing must be user-articulated, not strawman-proposed
for rubber-stamp.
Coaching path now offers entry-point choice: Vision+Features (capability-first),
Personas+Journeys (user-first), or let-me-suggest. Capability-thinkers walk
features directly.
Template framing in PRD Discipline: Essential Spine is the expected default,
Adapt-In Menu is conditional, and the LLM is authorized to invent sections when
concerns don't match any cluster. Concern scan beat in Discovery surfaces real
domain concerns without forcing a fixed shape.
Web grounding: light targeted use at load-bearing moments authorized; deep
research is suggested to the user via dedicated research skills, accepting
gracefully if declined.
references/probing.md deleted; its load-bearing content was either LLM-default
PM instincts or already covered by SKILL.md.
Misroute list now includes bmad-workflow-builder for agent/custom-agent signals.
* fix(bmad-prd): align opener with Fast path naming, normalize misroute list
* refactor(bmad-prd, bmad-product-brief): bring skills to parity, default-on web research
Cross-skill consistency fixes:
- Brief renames {workflow.output_dir} -> {workflow.brief_output_path} and
{workflow.output_folder_name} -> {workflow.run_folder_pattern} to match PRD's
naming pattern.
- Decision-log filename unified on .decision-log.md (dotfile convention) across
both skills.
- Brief picks up PRD's fallback on customization-resolve failure (read TOML
directly instead of halt).
- Brief picks up PRD's persistent_facts default that auto-loads
project-context.md.
- Brief greeting now enforces {communication_language} for the entire run, not
just the greeting.
PRD additions, propagated from brief:
- File-roles paragraph in Conventions (boundary rules for .decision-log.md vs
addendum.md; capture during conversation, not at finalize; audit/override
never goes in addendum).
- Greeting now tells the user they can invoke bmad-party-mode or
bmad-advanced-elicitation at any point.
- Create intent now writes prd.md with status: draft and creates the
.decision-log.md skeleton at workspace init.
- Resume-check on activation: scans prd_output_path for prior in-progress runs
(status not final) and offers to resume.
- Finalize Close sets status: final + updated date so resume-check can
distinguish finalized from in-progress.
- Stakes-calibrated length guidance in PRD Discipline.
Web research, default-on for any scope:
- Reframed external_sources lines in both skills to distinguish org-configured
registry (internal tools) from generic web research; both fire on the same
triggers.
- New Research subagents (default) beat in PRD Discovery: spawn web-research
subagents to ground the picture; AI especially where training data ages by
the week. Subagent searches; parent receives a digest. Deep work routes to
bmad-market-research / bmad-domain-research / bmad-technical-research.
- Brief Discovery picks up the same posture in lighter form.
* fix(bmad-prd, bmad-product-brief): drop phantom v2 callout, add Fast/Coaching to brief
- Drop `[v2 — out of MVP]` from PRD validation rubric Dimension 5. It was
flagged for absence but never instructed for use anywhere — the template uses
`[NOTE FOR PM]` for v2/v3 deferrals, which is the de-facto convention.
- Add Fast path / Coaching path working-mode choice to brief Discovery so the
"I'm pitching tomorrow" user has an express option. Note that the opener's
pressure-calibration philosophy primarily shapes Coaching path; Fast path
swaps pushback for [ASSUMPTION] tags the user can correct in review.
* refactor(bmad-prd): tighten Research subagents beat
* chore(deps): update @clack/core and @clack/prompts to latest versions and adjust Node.js engine requirement
* feat(prompts): add directory prompt with autocomplete and create-directory support
* chore(docs): update Node.js version requirement to 20.12+ across multiple documentation files
* fix(prompts): code review fixes
* feat(bmm): add bmad-prd skill and extend product-brief with external integrations
Consolidates the legacy create-prd/edit-prd/validate-prd trio into a single
lean facilitator with create/update/validate intent modes, following the
bmad-product-brief pattern. Both skills gain external_sources and
external_handoffs customize.toml fields for routing through corporate MCP
tools (Confluence, Jira, etc.) with graceful degradation, plus a File roles
constraint clarifying decision-log (audit trail) vs addendum (preserved
depth for downstream docs).
* refactor(bmad-prd): tighten SKILL.md and operationalize source-extractor pattern
- Compress Overview to remove coaching prose duplicated in Discovery
- Operationalize "Extract, don't ingest" with explicit subagent return contract; reference from Update, Validate, and Finalize input reconciliation instead of inline "read N documents"
- Fix Overview H1 -> H2 (was breaking pre-pass tooling)
- Move full headless JSON schemas to assets/headless-schemas.md; keep minimal example inline
- Compress File roles bullet; tighten Finalize step 1
SKILL.md: 124 -> 105 lines, ~4729 -> ~4467 tokens
* feat(bmad-prd): open-items gate, drop distillate, persona discipline, decision-log metadata
- Add Finalize "Open-items review" step (new step 4): counts OQs / [ASSUMPTION] / [NOTE FOR PM], walks them with user, flags high density as red flag against agreed stakes
- Validate now treats open-items density as a first-class finding category
- Resume / continuity surfaces open items deterministically as the first orientation step
- Drop the PRD's own distillate output and the bmad-distillator finalize step. Downstream workflows (UX, architecture, story creation) source-extract from prd.md directly via the canonical source-extractor pattern. Headless schemas, customize.toml comments, and template updated accordingly.
- Drop "status: draft" from PRD frontmatter and template; version/state transitions logged to decision-log.md instead. Finalize step 7 records the version transition entry.
- Add PRD Discipline bullet: personas must be research-grounded or marked [ILLUSTRATIVE]; must drive decisions; 2-4 personas max. Discipline pass enforces.
- Expand File roles bullet: competitive-analysis detail beyond a one-line landscape and operational/cost mechanics (rate-limiting, compression) belong in addendum
* feat(bmad-prd): outcome-driven trim, swappable validation checklist, HTML report
SKILL.md trim (4.7K -> ~3.2K tokens, 124 -> 93 lines):
- Cut anchor enumerations (HIPAA/PCI/NIST list, API/Mobile/Web list, hobby->regulated list, "fast/easy/scalable/intuitive", input enumerations, etc.) the LLM already knows
- Cut derivable reasoning (synonyms-cause-drift explanation, hobby-vs-enterprise examples, etc.)
- Cut good/bad examples that anchor LLM attention (password/SendGrid example, persona quote, "let me also add this nearby thing")
- Drop SMART-ceremony language from Measurable bullet (keep judgment-not-ritual; SMART principles fine)
Progressive disclosure to references/:
- Headless mode rules + JSON minimal example moved to references/headless.md (loaded only when invoked headless)
- On Activation step 6 gates mode detection: headless -> read references/headless.md and follow
Swappable validation checklist:
- New assets/prd-validation-checklist.md (15 items: Quality / Discipline / Structural / Stakes-gated, each one line)
- New customize.toml field validation_checklist (override per org)
- Used by Validate intent AND Finalize Step 3 -- same subagent, same checklist, two moments
- Replaces bmad-validate-prd's 13-step micro-file architecture; kept the valuable check dimensions (density, measurability, traceability, implementation leakage, etc.) and dropped the ceremony
HTML validation report:
- New scripts/render-validation-html.py (PEP 723, stdlib only, ~175 lines) renders structured findings JSON into a styled HTML report with pass/warn/fail grade, inline SVG score bar, category grouping
- New assets/validation-report-template.html (inline CSS, native <details>, no JS, no external deps) -- swappable via customize.toml validation_report_template
- New references/validation-render.md documents the subagent output contract and renderer invocation; loaded only when validate flow runs
- Auto-opens browser on interactive runs; headless skips the open
Mode flow consistency:
- Create and Update both now explicitly "proceed to ## Finalize"
- Validate / analyze is standalone -- explicit "does NOT enter ## Finalize"; renderer auto-opens the HTML
- analyze is a synonym for validate; intent detection routes both
- Update mode no longer has its own light-close validation step (Finalize Step 3 covers it)
* refactor(product-brief,bmad-prd): remove distillation from brief and PRD workflows
Drop bmad-distillator integration from bmad-product-brief (finalize step,
update mode, headless JSON, constraints) and clean up customize.toml comments.
Distillation is the wrong layer — story self-containment via epic solution
design docs is the right answer for downstream context.
Also commit pending bmad-prd changes: working mode selector (Express vs
Facilitative), open-items triage into phase-blocking/resolvable/deferred
buckets, persistence wording fix, and facilitation-guide reference.
* refactor(bmad-prd): aggressive SKILL.md compression, remove LLM-obvious content
* feat(bmad-prd,bmad-product-brief): surface party-mode and advanced-elicitation at opening
* refactor(bmm): retire bmad-create-prd/edit/validate, point docs and PM agent at bmad-prd
Removes the three separate PRD skills (create, edit, validate) in favor of the
unified bmad-prd skill. Updates module-help.csv, PM agent menu, workflow map,
getting-started tutorial, commands reference, customize/help SKILL.md examples,
and the website workflow-map diagram. Adds Recipe 6 (Advanced Integration
Patterns) to expand-bmad-for-your-org.md covering external_sources,
external_handoffs, doc_standards, and swappable templates.
* test(bmad-product-brief): drop distillate from evals
Distillate was removed from the product-brief workflow in 1a88f001
but the eval suite still checked for distillate.md artifacts, the
bmad-distillator subagent invocation, and the polish→distillate phase
ordering. Strip all distillate references from A1/A5/B1/B2/B3/B5/B6,
remove B4 (phase-ordering eval centered on distillate) and B8 (pure
distillate eval), update _design_notes, and delete the orphan
distillate.md fixture from the forkbird-brief input set. IDs preserved
(gaps at B4, B8) so existing references stay stable.
* fix(bmad-prd): validation report only on explicit analysis request
Reconciles a contradiction across SKILL.md, validation-render.md,
headless.md, and headless-schemas.md about when validation-report.{html,md}
gets written. Rule: a report file is only written when the user has
specifically asked for analysis — Validate intent, or a mid-session
"produce a report" request. The Finalize discipline pass during
Create/Update keeps findings in-conversation: autofix obvious issues,
ask on ambiguous ones, never write a file.
- SKILL.md: Finalize step 3 no longer renders a report; Validate intent
wording softened from "HTML report" to "validation report".
- references/validation-render.md: drops the severity-based conditional
for markdown emission. Script now always writes both HTML and MD
side-by-side when invoked; trigger gating happens upstream.
- assets/headless-schemas.md: drops the "may be omitted in interactive
mode" caveat; validation_report is required for Validate intent.
- scripts/render-validation-html.py: adds render_markdown_report()
emitting a severity-grouped markdown companion at output_path.with_suffix('.md').
Returns markdown path in the stdout JSON summary alongside HTML path.
* fix(bmm-skills): address remaining PR review nits
- headless-schemas.md: Update schema gains `external_handoffs` to match
SKILL.md which routes Update through Finalize (handoffs execute there).
- bmad-product-brief/SKILL.md: "Use the bmad-help skill" → "Invoke
bmad-help" to align with REF-03 and the bmad-prd phrasing.
- bmad-product-brief/SKILL.md: hyphenate "high-quality draft".
* feat(bmm): add deprecation shims for retired PRD skills
Re-adds bmad-create-prd, bmad-edit-prd, bmad-validate-prd as thin
compatibility shims so existing invocations by name and
_bmad/custom/bmad-{create,edit,validate}-prd.toml override files keep
working post-consolidation. Each shim contains only SKILL.md and
customize.toml — no steps, data, or templates.
On activation, each shim:
1. Resolves customization via resolve_customization.py, picking up any
legacy override files for the four legacy fields (activation_steps_*,
persistent_facts, on_complete).
2. Emits a one-time deprecation notice in {communication_language},
pointing at bmad-prd and the migration path for override files.
3. Invokes bmad-prd with the appropriate intent (create / update /
validate), passes through the resolved legacy customization with
instruction to use these values instead of re-resolving from
bmad-prd's own customize.toml, and forwards the original user input
verbatim.
bmad-prd continues to read its own customize.toml + bmad-prd.toml
overrides for the new-only fields (prd_template, validation_checklist,
doc_standards, output_dir, output_folder_name, external_sources,
external_handoffs, validation_report_template). Users wanting those
fields must migrate to invoking bmad-prd directly.
* polish(bmm): refine PRD deprecation shim wording
Three small revisions applied uniformly to all three shims
(bmad-create-prd, bmad-edit-prd, bmad-validate-prd):
- Tighten the frontmatter description to a single sentence naming the
intent and signaling v7 removal.
- Drop the redundant "On failure, surface the diagnostic and halt."
trailer from the resolve-customization step; resolve_customization.py
surfaces errors itself.
- Extend the user-facing deprecation notice to clarify that legacy
override fields still resolve under bmad-prd, so migration is for
unlocking new fields rather than restoring lost functionality.
* fix(bmad-prd): normalize status casing and add friendly file errors
- compute_stats: lower-case `status` before bucketing so findings with
any casing (e.g. "Pass") feed the stat buckets and the score bar
fills correctly. Matches the .lower() pattern already used in
render_finding and render_finding_md.
- main: wrap findings/template read_text calls; emit a one-line error
to stderr and return 1 on FileNotFoundError or JSONDecodeError
instead of dumping a raw traceback. Script is LLM-invoked, so a
clean diagnostic is the contract.
Addresses augmentcode review comments 3235100013 and 3235100018.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(expand): refresh "five recipes" copy to reflect Recipe 6
Recipe 6 (Advanced Integration Patterns) was added but three earlier
mentions still said "five": the frontmatter description, the intro
sentence at line 8, and the "Combining Recipes" paragraph. Update all
three to "six" and extend the Combining-Recipes example to call out
Recipe 6 (external_sources / external_handoffs) alongside the others.
Addresses coderabbitai review comment 3235107194 and the two
outside-diff observations on lines 3 and 8.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(bmad-prd): utf-8 encoding on render script, correct workflow-map outputs
- render-validation-html.py reads findings/template and writes HTML/MD with
explicit utf-8 encoding so non-ASCII content (smart quotes, em-dashes,
non-English text under {document_output_language}) does not break on
platforms whose default encoding is not utf-8.
- workflow-map.md 'Produces' column for bmad-prd now distinguishes
Create/Update outputs from the Validate intent's validation-report
artifacts.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(installer): throw descriptive error when module definition missing after clone
When a stable tag predates a module restructure (e.g. baut v1.14.0 had
payload/source dirs, but the registry pointed to skills/module.yaml which
only exists on main), findExternalModuleSource silently returned the
configured but non-existent path. This caused a confusing ENOENT inside
getFileList/copyModuleWithFiltering rather than a clear error.
Now throws with the version that was cloned and a --next hint when the
install channel was stable, so users know exactly how to recover.
Closes#2372
* style: fix prettier formatting in external-manager.js
* style: apply prettier formatting
* refactor(bmm): streamline bmad-product-brief into lean facilitator
Rewrites bmad-product-brief as an outcome-driven, intent-routed
facilitator with a configurable reviewer panel.
- Replace scripted prompt files with a concise SKILL.md
- Add brief-shape detection and intent routing
- Make the reviewer panel config-driven via customize.toml
- Harden the required-reviewer gate
- Add helper scripts and tests for panel resolution
- Replace embedded resources with a single brief-template asset
- Register skill metadata in module.yaml
* refactor(bmm): tighten bmad-product-brief discovery and polish flow
- Discovery now invites a brain dump and source material upfront,
followed by "anything else?" before drilling
- Create and Update modes explicitly invoke Discovery before drafting
- Calibrate "make them sweat" to ease as the brief firms up
- Update mode regenerates distillate.md when changes apply
- Replace polish_skills with polish_passes: polymorphic entries
(skill:/file:/plain-text), parallel subagents, applied automatically
so the user sees a polished draft, not a polish review
- Default persistent_facts to empty with opt-in examples instead of an
unbounded project-context.md glob
- Remove research-librarian, field-researcher, and skeptic agents no
longer needed with this rework
* refactor(bmm): make persistence and resume explicit in bmad-product-brief
- Replace "Hold a working memory" with "Persistence is real-time": the
workspace exists on disk and the user knows the path the moment Create
intent is confirmed; decision-log.md is canonical memory so walk-away
leaves nothing in the conversation
- Add "Continuity across sessions": prior in-progress drafts for this
project surface a resume offer
* test(bmm): scaffold evals for bmad-product-brief
Adds an eval suite for bmad-product-brief following the Anthropic skill-creator
schema, plus a new "Extract, don't ingest" constraint on the skill itself.
Skill change:
- New constraint: source artifacts (user-provided or run-discovered) enter the
parent conversation as relevance-filtered extracts via subagents, not loaded
wholesale. Keeps the parent context lean against transcripts, brainstorms,
research reports, code, web results, and prior briefs.
Evals (evals/bmm-skills/bmad-product-brief/):
- evals.json: 8 artifact/behavioral evals covering Create one-shot,
source-memo ingest, Update with contradiction surfacing, Validate inline,
Headless mode, brainstorm filtering, research-report filtering, persona
filtering. All scenarios use fictional entities (InsuLens, Branfield CC,
Forkbird Kitchen, Mossridge Library, Sproutkeeper, Hatchet & Loop Studio,
Brightway, Pantry Bridge).
- triggers.json: 15 description-firing checks (7 should-fire, 8 should-not-fire)
to catch under-triggering and adjacent-skill poaching.
- files/: realistic fixtures including a brainstorm with the relevant idea
buried at the end, a 3000-word market research report with the relevant
section in the middle, and customer interviews with the target persona in
position 3 of 4 — each shaped to test that filtering happens against the
user's stated focus regardless of where the relevant material sits.
Eval directory placement: top-level evals/ outside src/, matching the convention
in anthropics/skills (zero of 17 production skills include an evals/ subdir;
their skill-creator places dev workspaces as siblings to skill folders). Keeps
evals out of any installer or marketplace.json distribution path.
* refactor(bmm): rename brief workflow knobs and resolve PR review
- polish_passes -> doc_standards (TOML key + SKILL.md reference). Name
generalizes for every doc-producing skill: encodes standards applied at
finalize, not options.
- {run_folder} -> {doc_workspace}. Bound in Create to
{workflow.output_dir}/{workflow.output_folder_name}/; reused by Update,
Validate, Headless, and Finalize as the active brief's folder.
- On Activation Step 4 now resolves {date} explicitly (used by
output_folder_name default).
- Headless Mode: ambiguous-intent fallback is a `blocked` JSON status with
a `reason` field, no prompting. Resolves the activation/headless
contradiction flagged in review.
* test(bmm): overhaul product-brief evals into A/B/C pattern split
Refactor evals from 8 numbered single-shot tests into 16 typed evals:
- Pattern A (A1-A8): artifact-correctness tests with headless prompts and
precise, falsifiable expectations (no invented facts, right-sized output,
file boundary enforcement)
- Pattern B (B1-B8): process-discipline tests verifying decision-log fidelity,
polish phase ordering, contradiction detection, and distillate generation
- Pattern C (C1): config-compliance test for custom output paths and
document_output_language
Also tighten SKILL.md: add dependencies frontmatter, clarify headless override
autonomy in Update (proceed when intent is clear; block when ambiguous), and
make distillate skip explicit when bmad-distillator is not installed.
Two PR review fixes:
- Strip the surrounding markdown code fence from case-file-template.md
so initializing a case file doesn't nest the whole artifact inside a
code block. The template is now the structure directly, with usage
notes in an HTML comment that doesn't render. Matches the BMM idiom
used by bmad-create-story/template.md.
- Drop the stale `*-archaeology.md` reference from bmad-create-prd
step-01 discovery. The single-procedure restructure removed
archaeology as a distinct mode, so case files only carry the
`*-investigation.md` suffix. Tighten the glob accordingly.
Forensic case investigation under Amelia's menu (IN). Evidence-graded
findings (Confirmed / Deduced / Hypothesized), hypothesis discipline,
structured case-file artifact. Single procedure that calibrates between
defect-chasing and area-exploration based on the input.
Wires bmad-create-prd discovery to pick up case files as PRD input.
Public explainer doc, workflow-map Phase 4 row, EN + FR.
* refactor(catalog): rename after/before columns to preceded-by/followed-by
The bare prepositions `after` and `before` had no subject anchor, leaving
the dependency direction ambiguous: "X has Y in its `after` column" reads
plausibly as either "Y comes after X" or "X comes after Y". An LLM
catalog consumer just got the direction wrong because of this.
`preceded-by` / `followed-by` are passive-voice participles whose grammar
locks the subject (the skill in this row) and forces a single reading:
"X is preceded by Y" can only mean Y comes first.
Rename applied to:
- module-help.csv headers (bmm-skills, core-skills)
- bmad-help SKILL.md schema doc + descriptions
- installer.js mergeModuleHelpCatalogs header string
- plugin-resolver.js _buildSynthesizedHelpCsv header string
- bmad-manifest.json keys (bmad-product-brief, bmad-prfaq)
- distillate-format-reference.md example manifest
The separate `required` column continues to carry hard-gate semantics;
the renamed columns are pure soft sequencing hints, as already documented
in bmad-help.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* style(installer): wrap long header strings per prettier
* feat(installer): warn on non-canonical module-help.csv headers
mergeModuleHelpCatalogs now compares each per-module file's header
against the canonical schema and emits a one-shot prompts.log.warn per
module on drift, naming both the expected and actual header. Data
continues to load positionally so external modules built against the
old after/before schema still install cleanly — the warning is the
maintainer signal to rename their columns.
Centralize the canonical header in modules/module-help-schema.js so the
merger and the synthesizer (PluginResolver._buildSynthesizedHelpCsv)
read the same source of truth; future column renames are one edit.
Verified by installing all four bmad-org external modules
(bmb, cis, gds, tea) — every one ships the legacy after/before header
today and now fires an advisory warning while still merging cleanly
into _bmad/_config/bmad-help.csv with the canonical column names.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(installer): remove bmad-help from Copilot Custom Agents picker
Per @BMadCode's feedback after #2324 merged: every persona agent's
activation message already advertises bmad-help, so its picker entry is
redundant AND confusing (looks like a peer agent when it's actually the
meta-help). Removes the ALWAYS_AGENT_IDS allowlist exception that put it
there.
The toml-driven filter (the mechanism BMadCode endorsed in his PR review)
remains the sole signal: a skill is a persona iff its source
customize.toml has an [agent] section. bmad-help has no customize.toml,
so under the cleaned-up filter it's correctly excluded.
Tests: replaces the inclusion assertion in Suite 17 with an exclusion
assertion. Suite still covers persona / non-conventional persona /
workflow / meta-skill-with-`-agent-`-in-name cases.
Refs #2324
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test: clarify Suite 17 fixture comment per PR review
The fixture creates no customize.toml at all for bmad-help, so the
exclusion path being exercised is the missing-file branch — not the
file-without-[agent]-section branch. Reword the comment accordingly.
Per @augmentcode review on #2359.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(installer): generate OpenCode /<skill> slash commands
Adds .opencode/commands/<canonicalId>.md pointer files for each installed
skill so users can invoke skills directly (e.g. /bmad-quick-dev) instead
of going through the /skills menu.
- platform-codes.yaml: add commands_target_dir field for opencode
- _config-driven.js: installCommandPointers() with skip-if-exists default,
reserved-name collision guard, YAML-safe description quoting
- _config-driven.js: cleanupCommandPointers() for symmetric uninstall
- test-installation-components.js: extend OpenCode suite with assertions
covering pointer creation, content, and idempotency
OpenCode-only and opt-in via the new yaml field; other adapters unchanged.
Refs #2267
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(installer): address PR #2324 review feedback
Six fixes from CodeRabbit + Augment review on the OpenCode command
pointer generation:
- skipTarget no longer suppresses installCommandPointers in multi-IDE
shared-target_dir batches. Pointers live in a per-IDE directory and
are not deduped across peers, so OpenCode must still generate them
even when a peer (e.g. openhands) won the .agents/skills write race.
- skipTarget no longer suppresses cleanupCommandPointers either, so
partial uninstalls leave no stale pointers when a peer remains.
- canonicalId is validated as a safe basename before being interpolated
into a file path (defense in depth against a malformed manifest entry
writing outside commands_target_dir).
- yamlSafeSingleLine now quotes descriptions starting with `[` or `{`
so YAML doesn't parse them as a sequence/map.
- Per-record fs.writeFile failures are caught and counted (writeFailures)
rather than aborting the whole IDE install — pointer files are a
non-essential adjunct to the skill copy.
- Generator-shaped pointer files are refreshed when the manifest
description changes; hand-modified files (body diverges from the
generator pattern) are still preserved unless forceCommands is set.
Tests: extends Suite 8 with description-update propagation; adds new
Suite 40c covering OpenCode + openhands batches in both orderings plus
partial-IDE uninstall pointer cleanup. 308 tests pass (was 296).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(installer): address PR #2324 follow-up nitpicks
Four nitpicks from CodeRabbit's original review that were missed in the
first triage pass:
- Hand-edited pointers now survive the production install flow.
cleanupCommandPointers spares pointers for canonicalIds that are still
in the new manifest when called from the install/update flow (signal:
options.previousSkillIds is set). Uninstall and partial-IDE removal
flows still wipe pointers as before. The previous behavior wiped every
pointer in removalSet before installCommandPointers could run, so its
skip-if-exists guard never fired and hand edits were lost on every
reinstall — contradicting the docstring's preservation claim.
- RESERVED_OPENCODE_COMMANDS is now gated on this.name === 'opencode'
so future adapters opting into commands_target_dir don't silently
inherit OpenCode's reserved-name set.
- printSummary now surfaces results.commands so users see how many
pointers were created/refreshed/skipped per install, plus a warning
for any per-file write failures.
- Dropped a dead `typeof entry !== 'string'` check; fs.readdir without
withFileTypes always yields strings.
Tests: extends Suite 8 with a hand-edit-preservation regression that
calls setup with previousSkillIds (the production shape) and asserts a
sentinel byte sequence in the pointer body survives. 310 tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(installer): extend command-pointer generation to Copilot Custom Agents
Re-scopes #2324 to cover the second user-facing pain: GitHub Copilot's
Custom Agents picker, where installed BMAD skills currently don't show up
even though slash commands work natively.
Generalizes the per-platform pointer-file mechanism so the same
installCommandPointers / cleanupCommandPointers code path serves both
OpenCode (slash commands palette) and Copilot (Custom Agents picker), with
all platform-specific shape pushed into platform-codes.yaml as data:
- commands_target_dir — where pointer files live (existing)
- commands_extension — file extension (default '.md'; Copilot uses
'.agent.md' per VS Code Custom Agents docs)
- commands_body_template — pointer body, supports {canonicalId} and
{target_dir} placeholders. Default matches
OpenCode's `@skills/<id>` resolver. Copilot
has no such resolver, so its template uses
the {project-root}/<target_dir>/<id>/SKILL.md
LOAD pattern (consistent with PR #1769).
OpenCode behavior is unchanged. Copilot users now get a per-skill
.github/agents/<canonicalId>.agent.md file that surfaces the skill in the
Custom Agents picker — addressing the "agents being gone" complaint
flagged by enterprise users.
Tests: extends Suite 17 with assertions for Copilot agent pointer
creation, body content (LOAD pattern with {project-root}-rooted path),
and idempotency. 318 tests pass (was 310).
Refs #2267
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(installer): filter Copilot Custom Agents picker to persona agents only
Earlier commit naively wrote a `.github/agents/<id>.agent.md` for every
installed skill, which would clutter the Custom Agents picker with 90+
workflow/tool entries that don't belong there.
Adds an `agents-only` filter that gates the per-skill emission on whether
the canonical id signals a persona agent:
- Primary rule: id contains `-agent-` (e.g. `bmad-agent-pm`,
`gds-agent-game-dev`, `wds-agent-freya-ux`,
`bmad-cis-agent-storyteller`).
- Allowlist: `bmad-tea` — TEA's Murat persona uses the bare module code
rather than the `-agent-` convention. Listed explicitly so the rule
still surfaces it.
Verified against the full installed manifest (114 skills): catches all
20 description-confirmed personas across BMM, CIS, GDS, WDS, TEA;
excludes all 94 workflows/tools.
Wired through a new yaml field on github-copilot:
commands_filter: agents-only
OpenCode is unaffected — it has no `commands_filter` set, so the loop
behaves as before (every skill becomes a slash command).
Tests: extends Suite 17 with a multi-skill manifest fixture covering
persona/agent + bmad-tea + workflow cases; asserts persona agents and
bmad-tea get .agent.md files while workflows do not. 322 tests pass.
Refs #2267
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(installer): detect personas via customize.toml [agent] section
Per maintainer review on PR #2324: the `-agent-` naming convention isn't
a load-bearing contract anywhere else in the codebase, and the bmad-tea
allowlist already shows it starting to break. A future persona that
doesn't follow the convention would silently disappear from the Copilot
Custom Agents picker.
Replaces the name-based filter with a behavior-based signal: read each
skill's source `customize.toml` and check for an `[agent]` section. This
is the actual configuration source of truth — every BMAD persona is
configured under `[agent]`, every workflow under `[workflow]`, every
standalone skill has no customize.toml.
Verified on disk against the full installed manifest (114 skills):
- 20 personas detected — exactly the description-confirmed count across
BMM, CIS, GDS, WDS, TEA. bmad-tea is caught natively (no allowlist).
- 94 workflows/tools correctly excluded.
- `bmad-agent-builder` (meta-skill that builds agent skills) is now
CORRECTLY excluded — its canonical id contains `-agent-` but its
customize.toml has [workflow], not [agent], because it isn't a
persona itself. The previous naming-based filter was including it in
the agents picker, which would have been a silent UX bug.
`NON_CONVENTIONAL_AGENT_IDS` constant is removed entirely — the toml
signal subsumes it.
Tests: extends Suite 17 with a 4-skill fixture that covers persona +
non-conventional persona + workflow + meta-skill cases. 388 tests pass.
Refs #2267
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(installer): always include bmad-help in Copilot agents picker
Adds a single, deliberate exception to the toml-based agents-only filter:
`bmad-help` is the structural meta-skill across BMAD — the orientation
helper that points users at every other skill. Users invoke it
persona-style ("ask the helper") even though it has no `[agent]`
customize.toml of its own (it isn't a configurable persona).
Implemented as a one-element ALWAYS_AGENT_IDS set rather than a hardcode
in the function body so the exception is named, documented, and
discoverable. The skill is structurally unique — there is no second
meta-help skill — so this is not the start of a growing allowlist; it's
a one-off for the one orientation surface BMAD ships.
Verified on disk: agents picker now shows 21 entries (20 personas via
[agent] in customize.toml + bmad-help). bmad-agent-builder stays
correctly excluded (its customize.toml has [workflow], not [agent]).
Tests: extends Suite 17 with a `bmad-help` fixture (no customize.toml,
must still appear in agents picker). 389 tests pass.
Refs #2267
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Brian <bmadcode@gmail.com>
* fix(installer): handle deep-path URLs in custom module source parser
Rewrite parseSource() from host-specific regex to generic URL-based
parser so Azure DevOps _git paths and other multi-segment repo URLs
are preserved in cloneUrl and cacheKey.
Closes#2268
* test(installer): add Azure DevOps URL tests and wire into CI
- Add 18 assertions for dev.azure.com and visualstudio.com URLs
- Cover modern ADO, legacy ADO, .git suffix, ?path= subdir variants
- Add test:urls script to test and quality npm chains
---------
Co-authored-by: Brian <bmadcode@gmail.com>
Add Chinese translations for the two remaining untranslated docs
(named-agents, expand-bmad-for-your-org) and add i18n translations
for the BMad Ecosystem sidebar group and its items across all locales.
Co-authored-by: leon <leon.liang@hairobotics.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Closes#1663.
Adds two installer flags so module config options can be set without
interactive prompts. Designed for CI scripts, Dockerfiles, and
enterprise rollouts where the user wants to bake answers into the
install command rather than answer prompts.
`--set <module>.<key>=<value>` (repeatable) sets any module config
option. `--list-options [module]` lists every key the installer can
discover locally — built-in modules (`core`, `bmm`) plus any cached
official modules. One flag scales to every module without growing the
CLI surface per option.
```bash
npx bmad-method install --yes \
--modules bmm --tools claude-code \
--set bmm.project_knowledge=research \
--set bmm.user_skill_level=expert \
--set core.user_name=Brian
```
## How it works
`--set` is a post-install patch. The installer runs its normal flow
untouched, then `applySetOverrides` upserts each value into the
relevant config files:
- `_bmad/config.toml` (team scope, default)
- `_bmad/config.user.toml` (user scope, when the key already lives
there — so user-scope keys like `core.user_name` and
`bmm.user_skill_level` keep their proper file)
- `_bmad/<module>/config.yaml` (so declared schema keys carry forward
via the existingValue path on the next install)
A module without `_bmad/<module>/config.yaml` is skipped silently —
no orphan sections in `config.toml` for uninstalled modules.
## Tradeoffs documented in install-bmad.md
- **Verbatim values.** `--set bmm.project_knowledge=research` writes
`"research"`, not `"{project-root}/research"`. The `result:`
template is not applied. Pass it explicitly if you want the
rendered form: `--set bmm.project_knowledge='{project-root}/research'`.
- **Carry-forward, declared keys.** Free — values land in the
per-module `config.yaml`, so the next install reads them as
`existingValue` and they become the prompt default (accepted under
`--yes`).
- **Carry-forward, undeclared keys.** Best-effort. The value lives in
`config.toml` for the current install but won't be re-emitted on
the next install (the manifest writer's schema-strict partition
drops unknown keys). Re-pass `--set` if needed.
- **No "key not in schema" validation.** Whatever you assert is
written.
## Security
Prototype-pollution defense: `--set __proto__.x=1` would otherwise
reach `overrides.__proto__[x] = 1` and pollute `Object.prototype`,
cascading into every plain-object lookup in the process. Defense-in-
depth via parser-level reserved-name rejection (`__proto__`,
`prototype`, `constructor`) AND `Object.create(null)` for the
override maps. Verified the attack reproduces without the guard and
is blocked with it.
## What's intentionally NOT integrated
`--set` deliberately does not touch the prompt / template / schema
collection flow. No pre-seeding answers, no question filtering, no
function-default evaluation, no schema-strict partition exemption.
That earlier integration approach was tried and scrapped: it
spread state across `Config`, `OfficialModules`,
`manifest-generator`, both collection helpers, and required parallel
plumbing for quick-update — every bug fix touched a different layer.
The post-install patch model covers the actual user need (set a
config value from CI) in ~330 lines of `set-overrides.js` without
the schema gymnastics.
## Files
- `tools/installer/set-overrides.js` (new): parser, prototype-pollution
guard, `applySetOverrides` post-install patch, `upsertTomlKey` /
`tomlString` / `tomlHasKey` line-based TOML helpers
- `tools/installer/list-options.js` (new): module.yaml discovery +
formatter for `--list-options`
- `tools/installer/commands/install.js`: register `--set` /
`--list-options` flags, early validation, `--list-options` exit-code
handling (await `stream.write` callback then `process.exitCode` to
avoid truncating piped output), thread `setOverrides` through to
quick-update
- `tools/installer/core/config.js`: carry `setOverrides` field for
the post-install patch step
- `tools/installer/core/installer.js`: invoke `applySetOverrides`
after `writeCentralConfig` (covers regular install + quick-update
via the shared install path)
- `tools/installer/ui.js`: parse `--set` for early validation, warn
about overrides targeting modules not in `--modules`, drop those
entries before threading
- `docs/how-to/install-bmad.md`, `README.md`: usage, routing rules,
carry-forward semantics, tradeoffs
## Test plan
Suite 44 (24 cases): parser, prototype-pollution guard, `tomlString`
escaping, `upsertTomlKey` across insert/replace/missing-section/
empty-file/preserved-newline cases, `applySetOverrides` happy path +
uninstalled-module skip + missing-user-toml-creation + empty-input
no-op, `discoverOfficialModuleYamls` / `formatOptionsList` sanity
(hermetic via `BMAD_EXTERNAL_MODULES_CACHE` temp dir). 355 total
passing. Lint + prettier + markdownlint clean.
E2E smoke verified across:
- [x] `--set` writes correct files (team toml / user toml / per-module
yaml) for declared and undeclared keys
- [x] Quick-update without `--set` carries forward declared keys via
`existingValue` path
- [x] Quick-update WITH `--set` applies cleanly (uniform behavior
across action types)
- [x] `--set` for unselected module: warned, no orphan section
- [x] Prototype pollution: rejected with non-zero exit
- [x] `--list-options bmm` exit 0 with full output through pipe;
`--list-options nope` exit 1
- [x] Translated docs (`docs/{cs,fr,vi-vn,zh-cn}/`) intentionally not
touched — they'll lag behind English until the translation pipeline
runs
* fix(installer): preserve module-help.csv schema in merged bmad-help.csv (#2278)
The installer's mergeModuleHelpCatalogs was rewriting the merged catalog
under a different schema (module,phase,name,code,sequence,workflow-file,...)
than the documented source schema in every module's module-help.csv
(module,skill,display-name,menu-code,description,action,args,phase,...).
Worse, the parsing assumed the wrong source column order, so column data
was scrambled in the merged output. SKILL.md docs the source schema, so
the bmad-help skill was navigating a catalog whose actual columns no
longer matched its mental model.
Drop the transformation and the agent enrichment columns (which had no
consumers anywhere in the codebase). Emit rows verbatim in the source
schema, padding short rows and filling empty module fields. Sort by
module then phase, stable within phase to preserve authored order.
Closes#2278
* fix(catalog): normalize module-help.csv rows to documented 13-column schema
Many rows in core-skills/module-help.csv and bmm-skills/module-help.csv
were missing one column between description and phase, leaving them at
12 fields instead of 13. CSV consumers that read by header position
were silently mapping data into the wrong columns (description into
action, phase into args, required into before, etc).
Inserted an empty cell at column index 5 across all 31 affected rows
to restore alignment with the documented header
(module,skill,display-name,menu-code,description,action,args,phase,
after,before,required,output-location,outputs).
* fix(config): promote project_name to core, fixes#2279
project_name was a bmm-specific prompt despite being a universal
project-level concept used by every module — including core skills like
bmad-brainstorming, which loads from _bmad/core/config.yaml and was
silently broken because project_name lived under bmm. Users without bmm
installed could not run brainstorming at all.
Move:
- src/core-skills/module.yaml: declare project_name with prompt
"What is your project called?" and default {directory_name}, matching
what bmm previously had.
- src/bmm-skills/module.yaml: remove the bmm definition; add project_name
to the "Variables from Core Config inserted" header comment so
contributors can see what's inherited.
Migration for existing installs:
- tools/installer/modules/official-modules.js: after loadExistingConfig
reads each per-module config.yaml, hoist any keys that are now declared
in core but appear under non-core modules. Without this, the partition
logic in writeCentralConfig (which strips core keys from non-core
buckets) would silently drop the user's prior project_name on the next
quick-update. Generic — handles project_name today and any future
module→core promotions.
- The hoist preserves precedence: an existing core value beats a stale
module-side copy.
--yes seed:
- tools/installer/ui.js: add project_name to the hardcoded core seed
(using path.basename(directory) to match the {directory_name} default)
so non-interactive fresh installs populate it. Without this the seed
silently omits project_name and core skills fall back to literals.
Tests:
- test/test-installation-components.js Suite 43 (9 assertions) covers
the schema move, the loadExistingConfig hoist, and the precedence rule.
- Suite 35 fixture updated: project_name moved from bmm bucket to core,
with a stale bmm copy left in place to verify it gets stripped.
Verified manually:
- Fresh install -y: project_name lands in [core] of config.toml.
- Existing install with project_name in bmm/config.yaml: quick-update
hoists it to [core] and strips it from [modules.bmm].
* fix(installer): harden config-load against malformed config.yaml
Per augment review on #2348: loadExistingConfig stored any truthy
yaml.parse result (including scalars like '42'), which would later crash
_hoistCoreKeysFromLegacyModuleConfigs at \`key in cfg\` with
"Cannot use 'in' operator to search for ... in 42".
- loadExistingConfig: only keep parses that are plain objects (not
scalars or arrays). A corrupt config.yaml is now treated the same as
a parse error — skipped, not crashed-on.
- _hoistCoreKeysFromLegacyModuleConfigs: belt-and-suspenders type guards
on _existingConfig.core (in case it's populated by some other path)
and on each module cfg in the loop.
- Test Suite 43 adds 2 assertions covering a scalar core/config.yaml:
loadExistingConfig must not crash, and bmm.project_name must still
hoist into a clean core bucket.
step-07-validation template shipped with all 16 completeness checkboxes
pre-checked and Overall Status hard-coded to READY FOR IMPLEMENTATION,
defeating the gate. Reset checkboxes to unchecked, replace status with a
templated choice tied to the checklist and gap analysis, and instruct the
agent to only mark items the validation actually confirms.
Closes#2292
* fix(installer): require --tools for fresh --yes installs; remove --tools none (closes#2326)
Fresh non-interactive installs without --tools previously produced a
config-only install (~35 files vs ~1400 in the manifest) with no warning
and a "BMAD is ready to use" success card, leaving slash commands
unreachable. --tools none was an explicit opt-in for the same broken
state.
Now: fresh install + -y without --tools throws a helpful error pointing
at --list-tools. --tools none is rejected as an unknown ID. Empty and
typo'd tool IDs are also rejected. Existing-install paths (--action
update, quick-update, modify) are unchanged - they continue to reuse
previously-configured tools when --tools is omitted.
Adds --list-tools flag that prints all 42 supported tool IDs (id, name,
target_dir, preferred star) sourced from platform-codes.yaml.
English docs updated; localized docs (vi-vn, fr, cs, etc.) will sync via
the normal translation pass.
* fix(installer): address review for #2326 — single source of truth, drop dead code, add tests
- Refactor formatPlatformList to use IdeManager so --list-tools and --tools
validation see the same set of platforms. Eliminates the drift where suspended
platforms appeared in --list-tools but were rejected at validation.
- Drop unused getValidPlatformIds export.
- Flatten redundant block scope around the throw in the --yes-without-tools
branch (refactor leftover).
- Drop dead String() defensive cast (Commander always passes a string).
- Add Test Suite 42: 8 unit tests covering _parseToolsFlag empty/whitespace/
unknown/typo cases plus an integration check that --list-tools output and
--tools validation agree on the ID set.
* fix(installer): close --tools "" bypass and drop hardcoded tool count
- Replace truthy `if (options.tools)` guard with `!== undefined` in both
upgrade and fresh-install branches. Empty string now reaches
_parseToolsFlag and produces the specific "passed empty" error
instead of falling through to a generic message (fresh-install) or
being silently ignored (existing-install).
- Drop the hardcoded "42 supported tools" count from the prereqs in
install-bmad.md so the doc doesn't drift as platform-codes.yaml
changes.
Addresses augment / coderabbit review on #2346.
* fix: use full update path when --custom-source is passed with --yes
When --yes is used on an existing install, the installer auto-selects
quick-update. However, quick-update never re-clones custom module repos
— it only reads whatever is already in the cache. This means
--custom-source with a new version tag (e.g. @1.1.0) is silently
ignored and the previously cached version (e.g. 1.0.1) is reported as
"already up to date".
Default to the full update path when --custom-source is present, so the
custom repo gets re-cloned at the requested version. Also ensure all
installed modules are included in the selection when --yes is combined
with --custom-source, preventing previously installed modules from being
removed.
* fix: address review feedback on choices.find() and comment clarity
* style: prettier fix for empty-body methods in custom-module-manager
---------
Co-authored-by: Brian <bmadcode@gmail.com>
* fix(installer): preserve http protocol in custom module clone URLs
Previously, parseSource() hardcoded 'https://' when building cloneUrl,
forcing http:// Git URLs (e.g., internal LAN hosts) to upgrade to https.
This broke cloning for self-hosted Git servers that only serve over HTTP.
- Capture the protocol from the regex match instead of discarding it
- Update JSDoc and inline comments to document HTTP support
- Update install-custom-modules docs (EN, ZH, VN) to list HTTP URL type
Fixes the --custom-source flag for http:// addresses.
* docs(installer): update JSDoc to mention HTTP support in cloneRepo
Add HTTP to the cloneRepo method's JSDoc param description.
Also fixes minor spacing in empty arrow functions (formatting).
* docs(installer): fix JSDoc annotation for cloneRepo param
Correct @param backtick escaping in cloneRepo JSDoc.
Also documents HTTP as a supported protocol alongside HTTPS and SSH.
---------
Co-authored-by: 关惠民 <9155544@qq.com>
* fix(installer): route community installs through PluginResolver when marketplace.json ships
Community-catalog installs ignored .claude-plugin/marketplace.json, so modules
that nest module.yaml inside a setup skill's assets/ directory (e.g. Strategy 2
in PluginResolver) ended up half-installed: only module-help.csv and the
generated config.yaml landed in _bmad/<code>/, while the actual skill source
trees and module.yaml never got copied. The install would silently emit
"could not locate module.yaml" warnings and leave .agents/skills/ without
the module's skills.
The fix wires the existing PluginResolver onto the community path:
- CommunityModuleManager.cloneModule now detects marketplace.json after the
clone+ref-checkout completes and runs PluginResolver. The resolution is
stamped with channel/sha/registryApprovedTag/registryApprovedSha and cached
in _pluginResolutions, mirroring the existing _resolutions cache.
- OfficialModules.install consults the community plugin resolution and
delegates to installFromResolution (the same code path custom-source
installs already use). installFromResolution branches on communitySource
to write source: 'community' with the registry's approved tag/sha and
channel.
- resolveInstalledModuleYaml now searches the community-modules cache root
in addition to the external-modules cache, and the BMB setup-skill detector
walks src/skills/ and skills/ (not just the repo root) so collectAgents
FromModuleYaml and writeCentralConfig can find module.yaml in nested
marketplace-plugin layouts.
Backward compatibility: repos without marketplace.json (e.g. WDS, which
declares module_definition: src/module.yaml at the root) continue through
the legacy findModuleSource path with no behavior change. Verified against
the live zarlor/suno-band-manager community module and a 23-check fixture
suite covering Suno-shape, WDS-shape, and bare-repo layouts.
* fix(installer): harden community marketplace.json resolution path
Address review feedback on the community marketplace.json install path:
- Wrap PluginResolver.resolve() in try/catch so a malformed plugin entry
falls through to the legacy install path with a warn instead of
crashing cloneModule.
- Stop mutating the resolver's return object; shallow-clone before
stamping community provenance so install state cannot leak back into
resolver-owned objects.
- Warn when _selectPluginForModule lands on the single-plugin fallback
with a name that doesn't match the registry code or module_definition
hint, so a misconfigured marketplace.json can't silently install the
wrong plugin.
- Add CommunityModuleManager.resolveFromCache() and call it from
OfficialModules.install() when the in-process plugin cache is empty,
so callers that reach install() without pre-cloning still get the
marketplace-aware path. Reuses an existing channel resolution when
present, otherwise synthesizes a stable-channel stub from the registry
entry plus the cached repo's HEAD.
- Align installFromResolution()'s returned versionInfo.version with
manifestEntry.version precedence (communityVersion || cloneRef || ...)
so downstream summaries match what was written to the manifest.
Tests: lint, format:check, lint:md, test:install (290), test:channels
(83), test:refs (7) all green.
* fix(installer): resolve url-source custom modules from custom-modules cache
resolveInstalledModuleYaml previously only searched ~/.bmad/cache/external-modules/,
so modules installed via --custom-source <git-url> (cached at
~/.bmad/cache/custom-modules/<host>/<owner>/<repo>/) could not be located on
re-install runs. This caused warnings during npx bmad-method install:
[warn] collectAgentsFromModuleYaml: could not locate module.yaml for '<name>'
[warn] writeCentralConfig: could not locate module.yaml for '<name>'
Adds a fallback that walks the custom-modules cache via _findCacheRepoRoots
(identifying repo roots by .bmad-source.json or .claude-plugin/, not
marketplace.json, so direct-mode modules are also covered), reuses the same
searchRoot candidate-path logic, and matches by the discovered yaml's code
or name field.
Works without needing _resolutionCache to be populated, which fixes the
re-install scenario where no --custom-source flag is passed.
Closes#2312
* fix(installer): enumerate all module.yamls when walking custom-modules cache
A url-source custom-modules repo can host multiple plugins in discovery
mode (e.g. skills/module-a/module.yaml and skills/module-b/module.yaml).
The previous walk used searchRoot which returned only the first match,
so asking for module-b would surface module-a's yaml, fail the code/name
check, and skip the repo entirely — never inspecting module-b.
Splits the candidate-path traversal into searchRootAll (returns every
module.yaml in priority order) and a thin searchRoot wrapper for the
existing single-module fallbacks. The custom-modules walk now iterates
every yaml per repo and matches each against code or name.
- resolveInstalledModuleYaml: fall back to CustomModuleManager._resolutionCache for local
custom-source modules (external cache path doesn't exist for these); refactor candidate-path
search into shared searchRoot() helper; add *-setup/assets/module.yaml BMB standard path
- manifest-generator: use module code field (not display name) as TOML section key [modules.X]
Co-authored-by: cidemaxio <cidemaxio@users.noreply.github.com>
* fix(installer): mirror launch channel as default for external modules
When the user runs `npx bmad-method@next install`, the installer itself
runs from a prerelease, but the interactive channel gate previously hardcoded
"(all stable)" — defaulting tea/community modules to stable while bmad-method
itself was on next. The bleeding-edge launch did not flow through.
Detect the installer's own version via semver.prerelease() and default the
gate (and per-module picker) to match — "all next" for prerelease launches,
"all stable" for stable. Users keep full control: hit "n" to customize per
module, or pass explicit --channel / --pin / --next flags to override.
* fix(installer): seed channelOptions before module picker, not gate
CodeRabbit caught a label/install mismatch in the previous approach: the
module picker resolves version labels via decideChannelForModule, which runs
before _interactiveChannelGate. With channelOptions.global still null at
picker time, labels rendered from stable tags — then the gate flipped global
to 'next' and externals installed from main HEAD. Net effect on @next launches:
"tea (v1.6.0)" in the picker, but install pulled HEAD.
Move the launch detection up into promptInstall, immediately after
parseChannelOptions. Seeding channelOptions.global = 'next' before the picker
makes labels resolve from main HEAD (matching the install) and lets the
existing gate's haveFlagIntent check skip cleanly — the @next user already
declared their intent by typing it. Per-module customization remains available
via --pin / --next / --channel flags, same as for any pre-set global.
* fix(publish): advance @next dist-tag after stable release
When a stable release publishes via workflow_dispatch, @latest can leapfrog
the existing @next prerelease (e.g. latest=6.5.0 while next=6.4.1-next.0),
turning `npx bmad-method@next install` into a silent downgrade until the
next qualifying push to main republishes a fresh -next.0.
- publish.yaml: after stable publish, repoint @next at the just-published
stable version. The existing derive-prerelease step picks max(latest, next)
as its base, so subsequent push-driven prereleases bump from there.
- bmad-cli.js: checkForUpdate was querying the @beta dist-tag (which this
package does not use). Replace string-matching with semver.prerelease()
and query @next for prerelease users.
* fix(publish): harden next-tag advance step and broaden path filter
- continue-on-error on the dist-tag advance: failure leaves @next stale
until the next push-driven prerelease, which is recoverable; failing the
job after a successful publish + git tag + GH release is not.
- Status echo so release-log triage can confirm the advance ran.
- Add removals.txt to the push-trigger path filter. Installer-affecting
changes outside src/** (like the post-6.5.0 removals.txt fix) should
still trigger a fresh -next.0 publish.
Adds 32 entries to removals.txt covering the module-prefixed wrapper
skill names used pre-v6.2.0 (bmad-bmm-* and bmad-agent-bmm-*). Users
upgrading from v6.0.x / v6.1.x had these installed in their IDE skill
directories, but the v6.2.0 architecture switch dropped the module
prefix and the cleanup never knew the old names. Stale wrappers stayed
behind alongside the new self-contained skills, causing duplicates and
broken-file errors when invoked (referenced files no longer exist).
The removals.txt entries get added to the cleanup removalSet on every
install/update, so the next install run for an upgrading user removes
the stale wrappers automatically.
* refactor(installer): replace legacy_targets auto-cleanup with upgrade warnings
Removes the legacy_targets YAML field and its install-time auto-migration
of pre-v6.1.0 directories (.claude/commands, .opencode/agents, etc.). On
install, surface a warning instead: read manifest version and scan 24
known legacy paths, then print rm -rf commands the user can run themselves.
Also deletes orphan tools/platform-codes.yaml (never loaded by any code)
and fixes a stale URL in the cs translation.
* feat(installer): consolidate to .agents/skills and add global_target_dir for all platforms
Updates platform-codes.yaml against verified primary docs for all 24 supported
platforms. 14 platforms (auggie, codex, crush, cursor, gemini, github-copilot,
kilo, kimi-code, opencode, pi, roo, rovo-dev, windsurf) move their project
target_dir to the cross-tool .agents/skills/ standard. Junie moves from the
broken .agents/skills/ to its own .junie/skills/ per JetBrains docs.
Adds global_target_dir to every platform: 11 share ~/.agents/skills/, Crush
uses XDG ~/.config/agents/skills/, Codex global stays ~/.codex/skills/, the
rest are tool-specific. Ona and Trae omit global (no documented home path).
Note: installer logic does not yet dedupe writes for platforms sharing a
target_dir — users installing multiple .agents/skills/ tools together will
overwrite the same files (harmless on install, but uninstalling one clears
the dir for the others). Coordination logic is the next step.
* feat(installer): add 18 new platforms, dedup shared target_dir, ownership-aware cleanup
Adds 18 platforms from the verified Vercel list (adal, amp, bob, command-code,
cortex, droid, firebender, goose, kode, mistral-vibe, mux, neovate, openclaw,
openhands, pochi, replit, warp, zencoder). Marks codex and github-copilot as
preferred alongside claude-code and cursor.
Coordination for platforms sharing a target_dir:
- IdeManager.setupBatch dedups skill writes when multiple selected platforms
point at the same target_dir (e.g. .agents/skills/). The first platform
writes, peers skip the redundant wipe-and-rewrite. Result reports the same
count and target dir for every member so the install summary is consistent.
- IdeManager.cleanupByList accepts remainingIdes; when removing one platform
from a shared dir while another co-installed platform still owns it, the
target_dir wipe is skipped. Platform-specific hooks (copilot markers, kilo
modes, rovodev prompts) still run.
- _setupIdes uses setupBatch; _removeDeselectedIdes passes remainingIdes so
partial reconfigure preserves shared skills.
Skill ownership now uses skill-manifest.csv canonicalIds, not the bmad- prefix.
This unblocks custom modules that ship skills with non-bmad names (e.g.
fred-cool-skill). Affected sites:
- _config-driven.detect: reads canonicalIds from the project's bmadDir
- _config-driven.findAncestorConflict: reads canonicalIds from the ancestor's
own bmadDir, falling back to the prefix only when no manifest exists
- legacy-warnings.findStaleLegacyDirs: same canonicalId-based detection
Migration warnings: LEGACY_SKILL_PATHS adds 12 skill dirs that moved to the
.agents/skills/ standard (cursor, gemini, github-copilot, kimi, opencode, pi,
roo, rovodev, windsurf, plus their globals). Users with stale skills in those
locations get a one-line warning with the rm command per dir.
New shared helper tools/installer/ide/shared/installed-skills.js exposes
getInstalledCanonicalIds(bmadDir) and isBmadOwnedEntry(entry, canonicalIds).
Tests: 9 new assertions across two suites covering dedup, partial uninstall
preservation, and custom-module skill detection. All 286 tests pass.
* fix(installer): setupBatch must not claim a shared target_dir on failure
If the first platform's setup throws or returns success: false, the dedup map
previously still recorded the claim with skillCount: 0, causing every peer
sharing the target_dir to skip its install — leaving the dir empty/broken
behind a cascade of misleading "shares with X" rows.
Now the claim is only recorded when the install succeeded and wrote skills.
On failure, the next peer becomes the new first writer and recovers.
Adds Suite 40b regression test that monkey-patches cursor.setup to throw
and verifies gemini still populates the shared dir.
* fix(installer): address PR #2313 review findings
Three issues raised by augmentcode and coderabbit bot reviewers:
1. _removeDeselectedIdes silently swallowed cleanup failures after the
refactor to cleanupByList. The old per-IDE try/catch logged a warning;
the new path discarded the result array. Now logs a warning per failed
ide so failures stay visible.
2. The legacy-dir cleanup hint printed `rm -rf "<path>"/bmad*` which both
matched bmad-os-* utility skills the user should keep AND missed the
custom-module skills (e.g. fred-cool-skill) that the new canonical-id
detection now finds. Findings now carry the exact entry names from the
scan, and the warning prints one precise rm line per entry.
3. warnPreNativeSkillsLegacy did unguarded fs reads at install start. A
permission/IO error would have aborted the whole install. Wrapped the
call site in try/catch so legacy-scan failures only emit a warning.