BMAD-METHOD/tools/installer
jheyworth 65b810a11f
fix(installer): generate slash-command and Agent pointer files (OpenCode + GitHub Copilot) (#2324)
* 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>
2026-04-29 22:13:06 -05:00
..
commands feat(installer): add --set and --list-options for non-interactive config (#2354) 2026-04-28 20:15:57 -05:00
core feat(installer): add --set and --list-options for non-interactive config (#2354) 2026-04-28 20:15:57 -05:00
ide fix(installer): generate slash-command and Agent pointer files (OpenCode + GitHub Copilot) (#2324) 2026-04-29 22:13:06 -05:00
modules Fix/azure devops url parsing (#2269) 2026-04-28 22:06:37 -05:00
README.md refactor(installer): restructure installer with clean separation of concerns (#2129) 2026-03-27 06:50:07 -06:00
bmad-cli.js fix(publish): advance @next dist-tag after stable release (#2320) 2026-04-26 10:30:41 -05:00
cli-utils.js chore(installer): remove 1,683 lines of dead code (#2247) 2026-04-10 20:24:50 -07:00
file-ops.js fix(installer): replace fs-extra with native node:fs to prevent file loss 2026-04-13 00:44:28 -05:00
fs-native.js fix(installer): add missing sync and async methods to fs-native wrapper 2026-04-13 09:59:41 -05:00
install-messages.yaml feat(installer): overhaul branding, versioning, and skill cleanup (#2223) 2026-04-07 02:31:36 -05:00
list-options.js feat(installer): add --set and --list-options for non-interactive config (#2354) 2026-04-28 20:15:57 -05:00
message-loader.js fix(installer): replace fs-extra with native node:fs to prevent file loss 2026-04-13 00:44:28 -05:00
project-root.js fix(installer): route community installs through PluginResolver when marketplace.json ships (#2331) 2026-04-26 22:50:47 -05:00
prompts.js chore(installer): remove 1,683 lines of dead code (#2247) 2026-04-10 20:24:50 -07:00
set-overrides.js feat(installer): add --set and --list-options for non-interactive config (#2354) 2026-04-28 20:15:57 -05:00
ui.js feat(installer): add --set and --list-options for non-interactive config (#2354) 2026-04-28 20:15:57 -05:00
yaml-format.js refactor(installer): restructure installer with clean separation of concerns (#2129) 2026-03-27 06:50:07 -06:00

README.md

BMad CLI Tool

Installing external repo BMad official modules

For external official modules to be discoverable during install, ensure an entry for the external repo is added to external-official-modules.yaml.

For community modules - this will be handled in a different way. This file is only for registration of modules under the bmad-code-org.

Post-Install Notes

Modules can display setup guidance to users after configuration is collected during npx bmad-method install. Notes are defined in the module's own module.yaml — no changes to the installer are needed.

Simple Format

Always displayed after the module is configured:

post-install-notes: |
  Thank you for choosing the XYZ Cool Module
  For Support about this Module call 555-1212  

Conditional Format

Display different messages based on a config question's answer:

post-install-notes:
  config_key_name:
    value1: |
      Instructions for value1...      
    value2: |
      Instructions for value2...      

Values without an entry (e.g., none) display nothing. Multiple config keys can each have their own conditional notes.

Example: TEA Module

The TEA module uses the conditional format keyed on tea_browser_automation:

post-install-notes:
  tea_browser_automation:
    cli: |
      Playwright CLI Setup:
        npm install -g @playwright/cli@latest
        playwright-cli install --skills      
    mcp: |
      Playwright MCP Setup (two servers):
        1. playwright    — npx @playwright/mcp@latest
        2. playwright-test — npx playwright run-test-mcp-server      
    auto: |
      Playwright CLI Setup:
        ...
      Playwright MCP Setup (two servers):
        ...      

When a user selects auto, they see both CLI and MCP instructions. When they select none, nothing is shown.