Commit Graph

687 Commits

Author SHA1 Message Date
Alex Verkhovsky 7d68d38222 docs: add Start documentation section 2026-08-26 05:53:59 -07:00
Brian 825099b2cb fix(installer): ask about deprecated shims during Quick Update, and report the outcome (#2746)
* feat(installer): ask about shims during Quick Update

Quick Update returned before the shim prompt, so anyone who only ever
runs it carried their compatibility shims forward release after release
without once being offered the chance to drop them.

Quick Update now asks, defaulting to keeping the shims so pressing enter
never removes a skill in active use. It stays quiet for an installation
that already dropped its shims rather than re-asking every update. The
prompt carries the recommendation to remove them and names the one case
that justifies keeping them: a customized shim not yet migrated.

Whenever an install retains shims, it now lists every one of them and
what it forwards to. That notice is emitted where the policy is resolved
rather than at the prompt, so it also reaches the paths that never
prompt: --yes, --shims, and scripted quick updates.

* fix(installer): never prompt for shims without a TTY, and report removal

Two gaps in the Quick Update shim prompt.

The prompt could be reached by a scripted run. `--action quick-update`
is a documented scripting flag and is not tied to `--yes`, so a headless
invocation on an install that still had shims fell through to a confirm.
clack's confirm never resolves without a TTY: the process drained its
event loop and exited silently, mid-install, with status 0. It now keeps
the standing answer whenever stdin is not a TTY, leaving --shims and
--no-shims as the way to change it from a script.

Removing shims was also completely silent. Source filtering just skips
the directories, and the IDE cleanup that deletes the stale skill dirs
suppresses its logging on purpose, so nothing anywhere told the user
that a skill they may still invoke had just gone. Any run that removes
shims now lists them and says how to put them back, mirroring the
retained notice. Between the two, every run that has shims either way
reports which way it went, on interactive and headless paths alike.

* feat(installer): carry the shim outcome into the final summary

Both shim notices print before the install tasks start, so a long run
buries them well above the fold. The summary box already repeats the uv
warning for exactly this reason; the shim outcome now rides along the
same way, as a single line next to the preserved/backed-up file counts.

Retained reads "Deprecated shim skills retained: N (re-run to remove
them)" in yellow, removed reads "Deprecated shim skills removed: N" in
green, and an install with no shims either way adds no line at all.

* fix(installer): say what an empty module selection installs

The official module picker allows an empty selection on purpose: core is
always installed and is not a row in the list, so selecting nothing is a
valid core-only install. The prompt did not say so, and collapsed to a
bare "0 items selected", which reads as though the install is about to
do nothing.

autocompleteMultiselect takes an optional emptyLabel, shown while
selecting as "Nothing selected: installs core only" and on submit as
"0 items selected (core only)". Pickers that pass no emptyLabel are
unchanged. Also fixes the count to say "1 item" rather than "1 items".

* refactor(installer): trim explanatory comments to what the code cannot say

Cuts 35 comment lines added across this branch down to seven, keeping
only the non-obvious constraints: clack's confirm hanging without a TTY,
core not being a row in the module picker, and why the shim notices are
emitted where they are.

* fix(installer): report shims removed after they are retired from source

Removal reporting was derived from the shims the incoming release ships,
so a shim retired from source fell out of the report entirely: it was
absent from discovery, yet the update cleanup still deleted its installed
target using the previous manifest. The v7 cut is exactly that case, and
it would have removed every shim in silence.

Removal is now derived from what is installed, read back from
skill-manifest.csv, and the retained/removed split moves into
selectShimOutcome. This also covers the mixed run where one shim is
retired while the rest stay enabled: both notices fire, and the summary
carries both counts. The recovery line no longer offers --shims when the
release cannot reinstall them.

Raised by greptile and coderabbit on #2746.
2026-08-15 18:53:03 -05:00
Alex Verkhovsky c96b7d1db2 feat(installer): add Grok as a tool target (#2732)
Install Grok skills to .agents/skills and ~/.grok/skills,
matching the shared agents-skills path used by most CLIs.
2026-08-13 17:37:22 -07:00
Alex Verkhovsky db7f96dd93 feat(installer): make compatibility shims optional (#2728) 2026-08-12 20:34:47 -07:00
Theo 401814f2de fix(installer): stop copying __pycache__ into IDE skill trees (#2695)
Fixes #2694.
2026-08-11 16:51:20 -07:00
mindcarver eeb6ad9cf4 feat: add ZCode as supported installer platform (#2613)
* feat: add ZCode as supported installer platform

ZCode keeps a private skills tree (workspace `.zcode/skills`, global
`~/.zcode/skills`) distinct from the cross-tool `.agents/skills`
standard, so it needs its own platform entry. The installer is
config-driven from platform-codes.yaml, so adding the platform is a
config-only change — no new handler code.

Follows the same pattern as the Antigravity CLI (AGY) addition (#2551):
one platform-codes.yaml entry plus a Test Suite asserting the config and
a real IdeManager.setup('zcode') install into a temp project.

* test(installer): harden ZCode test cleanup with try/finally

Move temp directory cleanup into a finally block with nullable guards so
fixtures are removed even when setup throws mid-flight. Aligns Test Suite 6c
with the existing pattern in Suite 28 (Pi) and Suite 32 (Ona).

Addresses CodeRabbit review comment on PR #2613.

---------

Co-authored-by: mindcarver <mindcarver@users.noreply.github.com>
Co-authored-by: Brian <bmadcode@gmail.com>
2026-08-10 13:45:36 -05:00
Brian ade7a966e9 fix(installer,skills): make uv a real requirement and stop assuming a system Python (#2704)
The installer told users uv was optional while bmad-build had already made
it mandatory. uv-check.js called it "becoming the de facto standard",
install-messages.yaml led with HEADS UP, and installer.js printed a Tip
inside a box titled "BMAD is ready to use!" — while bmad-build and
bmad-build-auto HALT on activation without `uv run`. The probe's result
was discarded (`await checkUvEnvironment();`), so nothing branched on it.

Messaging now names the consequence, and the post-install summary repeats
the warning when it applies — the pre-install probe fires before every
prompt, so by then it is far up the scrollback. Still warn-don't-block:
core-only, docs-only, and CI installs never render a skill, so a missing
uv must not fail the run.

Adds a python3 probe used only when uv is absent, since that is the only
case where the interpreter on PATH matters. It reports whether the
direct-interpreter skills still work (3.11+) or nothing Python-backed will
(below 3.11, or no python3 at all).

Separately, 25 call sites still ran resolve_customization.py under a bare
`python3`. That script requires 3.11+ for tomllib, so on macOS without
Homebrew or Ubuntu 22.04 they fell through to their "if the script fails"
path and hand-merged the TOML in-context — no error surfaced. All 25 now
use `uv run`, which provisions a matching interpreter from the script's
own requires-python.

Four more spawned Python purely to open an HTML file:

  python3 -c "import webbrowser, pathlib; webbrowser.open(...)"

Replaced with the platform opener bmad-brainstorming already uses — open /
xdg-open / start. src/ now contains no bare Python invocation at all, so
"Python 3.11+" leaves the user contract: uv provisions its own.

docs/how-to/customize-bmad.md described a transition that this ends.

Test suite 46 grows from 12 to 29 assertions: Python parsing, the 3.11
boundary in both directions, that uv-present skips the python3 probe, and
all three missing-uv sub-branches.
2026-08-09 18:25:48 -05:00
Brian 47bab7d15c refactor(project-context): conversational skill, no script, AGENTS.md block (#2698)
* feat(project-context): rewrite as prescriptive AGENTS.md generator

Replace the kernel+bundle context system with a single product: a short
verified agent guide (AGENTS.md). A field trial of the first version showed
repo scanning produces polished-but-useless factoids; the rewrite fills a
fixed section plan from ranked evidence channels (executable config and CI,
targeted git history, session logs, human interview) and uses the repository
only to verify claims, never as the source of knowledge.

- Intents: bootstrap, refresh, record (capture an observed agent mistake),
  audit; query is gone with the bundle
- Per-fact entry files, trust frontmatter, index, placement machinery, and
  the skill's context.py mechanics script are removed; accountability moves
  to one plain ledger file recording every candidate claim and its
  disposition
- Skill directory only; docs, forwarding husks, and shared scripts untouched

* refactor(project-context): per-section admission rules, two-tier guide

Revisions from two end-to-end trials plus review:

- Replace the global non-derivable test with per-section admission rules:
  brevity (orientation), authority (policy), universal need verified by
  execution (commands, verification), wrong-default-assumption (conventions),
  localization value (pointers), observed failure only (pitfalls)
- Two-tier output: AGENTS.md (orientation + policy + pointer) for every
  session, AGENTS-dev.md for coding sessions; single file when tiny
- Pitfalls can never be nominated by scans: sources are recorded lessons,
  maintainer recall, session evidence, and the writing session's own caught
  mistakes; retirement only when the guarded thing is gone or the human says
  so, since a working rule erases its own evidence
- Interview ergonomics: recall questions, never review lists; testimony the
  repo contradicts is surfaced with evidence, never written or dropped
- Trial-driven fixes: guide-to-filesystem link check, mutating-command
  go-ahead as the interview's first question, plain-English rewrite
  throughout

* fix(project-context): bidirectional coverage trace, history-evidenced pitfalls

Round-3 trial findings: an unsourced pitfall entered the guide at
composition time because coverage only checked ledger-to-guide; and
repeat-fix git history, the strongest pitfall evidence observed, was
not an explicitly admitted source.

* refactor(project-context): move Where-things-are to AGENTS.md, imperative lines

Where-things-are pointers serve planning sessions as much as coding
ones, so they belong in the always-loaded file. Shape rules now require
every line to state an action (bare facts only as justification clauses)
and stable contract headings across runs.

* docs(project-context): session-kind guides as a third structural axis

A maintainer-named frequent session kind (UX, manual testing, data
work) may earn its own AGENTS-<kind>.md behind a pointer; module-level
differences stay with scoped guides.

* refactor(project-context): action-gated dev-guide pointer, two-file example

The AGENTS-dev.md hop is the most common progressive-discovery trigger,
so it is now gated on the first hands-on action rather than session
self-classification, names its payoff, and names the exemption. The
contract's worked example shows the two-file form with the pointer in
situ. Scoped-guide discovery no longer assumes harness nearest-file
loading: the root-guide pointer is the mechanism.

* refactor(project-context): adopt shared memlog, drop unearned claims

The run record is now a standard memlog kept with the shared
memlog.py script — append-only typed entries, latest entry wins —
replacing the bespoke ledger format; stale-disposition notes become
structurally impossible. Two appeal-to-measurement assertions cut:
the operative admission and exclusion rules carry that load.

* docs(project-context): guard handwritten guides

The skill never commits — its output stays as working-tree changes for
the user. Headless runs never rewrite a guide the memlog doesn't record
writing; they leave an AGENTS.md.proposed for an interactive merge.

* docs(project-context): fold in prior-art research findings

Five adoptions from the generator prior-art survey: prohibitions name
their permitted alternative; an emphasis-marker budget; a
git-log --diff-filter=DR drift check on refresh; TODO placeholders over
guessed greenfield commands; commit and branch conventions mined from
history.

* docs(project-context): route candidates to enforcement before prose

Compose now asks, per accepted candidate, whether a hook, lint rule, or
CI check enforces it better than a guide line; the line is the fallback
and a landed check deletes it.

* docs(project-context): narrow refresh interview and contradiction flagging

Refresh interviews shrink to one recall question — what changed since the
last run. Cross-file contradictions are flagged only when they change
behavior; rewording and overlap are not contradictions.

* refactor(project-context): conversational skill, no script, AGENTS.md block

Refine the skill into an implementation-layer capability: a conversation that
produces one small verified block inside the repo's AGENTS.md. The human is in
the loop for every write; there is no autonomous mode.

- Drop src/scripts/context.py and its tests. Nothing it did is needed once the
  output is a single spliced block rather than a bundle of files.
- Replace guide-contract.md and evidence.md with best-practices.md (admission,
  exclusion, retirement, retrieval, maintenance) and template.md (section list
  plus a worked example, no placeholders).
- Collapse the two-file AGENTS.md/AGENTS-dev.md split into one block. A pointer
  the agent must choose to follow gets skipped; anything load-bearing goes in
  the always-loaded file.
- Replace per-section admission rules with one test: anything derivable from
  source is read live, never stored. Commands stated in package.json, a
  Makefile, or CI config no longer earn a line; their caveats do.
- Ask up front whether a run covers the root only or named sub-projects, gated
  on observable evidence (a workspace manifest, per-directory build manifests).
- Husk bmad-document-project and bmad-generate-project-context onto setup
  intent, and say plainly that the deeper system-explanation altitude is a
  separate capability rather than shipping a thin substitute.
- Align module-help.csv, bmad-correct-course, the analyst menu, and the docs
  set with the block as the output.

---------

Co-authored-by: Alex Verkhovsky <alexey.verkhovsky@gmail.com>
2026-08-08 23:03:12 -05:00
Brian 5247108ba3 fix(installer): plain-text directory prompt, retire WDS, position on AiDD (#2680)
* fix(installer): submit the path shown and retire WDS from the picker

Directory prompt

The installation-directory prompt was a clack AutocompletePrompt whose
render() drew only the text line. The candidate list existed but was never
shown, and Enter returns the focused option rather than the typed text.
Focus was sticky: it only reset when the previously focused value left the
list, so a subdirectory selected while narrowing survived deleting back to
the parent. Typing /path/to/workspace could install to
/path/to/workspace/some-child with no sign of it on screen.

Rebuilt on TextPrompt so the input line is the value:

- the candidate list is visible, windowed, with an active-row marker
- arrow keys and Tab write the highlighted candidate onto the input line
- the list is frozen against the last typed text while browsing, so arrows
  walk siblings instead of descending (this also unsticks Tab cycling)
- index -1 is the typed text, so backing out of the list restores it
- Tab completes to real directories only, skipping "Create/use:" entries
- directory() takes optional input/output streams so it is testable

Module registry

- WDS is marked deprecated: hidden from the picker unless already
  installed, shown with a notice when it is, never removed and still
  resolvable from its source so existing installs keep updating
- deprecation notices now reach the CLI paths (--modules, --yes) and
  quick-update, which never render the picker's option hints
- picker order is now bmm, bmb, cis, tea, bmad-loop, gds
- the core row is hidden; it was a locked always-on checkbox. core is
  still added to the result, and the picker no longer requires a
  selection so a core-only install stays possible

* fix(installer): replace the whole line when browsing directories

_clearUserInput() sends readline ctrl+u, which deletes only what is left
of the cursor, and _setUserInput() inserts at the cursor. Browsing after
an arrow-key edit therefore left the surviving tail appended to the
selected candidate: typing a path, pressing left three times, then down
twice submitted ".../workspaceace" instead of ".../workspace/alpha".
validateDirectorySync accepts that path when its parent exists, so the
install went somewhere the user never typed - the same silent-divergence
class this prompt was rebuilt to prevent.

replaceLine() now moves to end of line (ctrl+e) before clearing. This
also fixes the pre-existing instance of the bug on Tab.

Alongside it:

- shift+tab steps back through completions instead of acting as tab
- the "... N more" counter counts only entries below the window, not
  every off-window entry, which overstated it once scrolled
- an empty line resolves the default through expandHome/path.resolve,
  and seeds the candidate list from the same place, so the list always
  describes what Enter would submit
- selectAllModules JSDoc no longer claims core is excluded
- test escape sequences are written as escapes rather than raw bytes,
  and the keystroke driver has wider timing margins for CI

* refactor(installer): make the directory prompt a plain text entry

The candidate list, key hints and completion cycling were noise for the
common case: people run the installer from the directory they want to
install into, or one under it. Enter on an empty line already accepts
that, so the list mostly served to push the actual question off screen.

Removed the list rendering, the hint line, arrow/Tab browsing and the
helpers that fed them (listDirectoryOptions, directoryWindow and the
directory-probing utilities). What remains is a clack TextPrompt with a
placeholder showing the default.

The original defect stays fixed by construction rather than by
bookkeeping: TextPrompt's value is the text on the input line, so there
is no hidden selection that Enter could submit instead. Net effect on
prompts.js versus main is -66 lines.

* docs(installer): shorten module descriptions in the picker

The hint beside a highlighted module ran long enough to wrap, which made
the list harder to scan than the module names alone. Each description is
now a single short phrase:

- bmm  Agile AI driven development
- bmb  Skill, workflow, and agent builder
- cis  Brainstorming, ideation, and creative problem solving
- tea  Enterprise testing BMM add-on
- loop Builds, verifies, and retros a whole epic unattended
- gds  Ideate, design, and build games in any framework

TEA is the only module that depends on BMM, and its description now says
so. The others no longer imply it. "Loop" means nothing to a new user, so
that description leads with what the module does rather than its name,
and gds no longer enumerates engines.

* feat(installer): pre-fill the directory prompt with the current directory

The default was shown as dim placeholder text, so choosing anything near
it meant typing the whole path by hand. It is now the real starting value
on the input line: press Enter to take it, append to install one level
down, or backspace to move up. Clearing the line and pressing Enter still
accepts the default, and the placeholder remains for that case.

* docs: reposition on Agile Ai Driven Development

The tagline was absent from the installer and the README, and the slot
under the wordmark where a tagline belongs was carrying the company line
instead. AiDD is the category BMad Method operates in; the agile part is
what BMad adds to it.

Installer:

- the banner reads tagline, then positioning, then company credit, in
  descending weight
- bmm and cis picker descriptions match, with cis short enough that its
  row no longer wraps and shifts the list as you arrow onto it

README:

- the opening states the phrase, defines AiDD on first use, and drops the
  rhetorical "heard BMad means heavyweight process?" framing while
  keeping what it was defending
- greenfield lean corrected: the opening now states the range, "add BMad
  to an existing codebase" is a CTA above the fold rather than a link at
  line 57, and a bullet names working from verified context on inherited
  code. Everything above the fold previously scaled by change size and
  nothing by codebase maturity, so a brownfield reader had no answer.
- the module table matches the installer descriptions, uses full module
  names instead of letter codes, and adds BMad Loop, which was missing

* docs: carry the module descriptions into the translated READMEs

Game Dev Studio was the last picker row wide enough to wrap an 80-column
terminal, which shifts the list as you arrow onto it. The engine list
stays in the README tables, where there is room for it.

The Chinese and Vietnamese READMEs have their own structure rather than
being a translation of the current English one, so this only touches the
two parts that had gone stale against the installer: the opening
positioning line and the module table. Both tables now match the English
one - installer descriptions, full module names instead of letter codes,
and BMad Loop, which none of the three had.

The translated prose needs a native reviewer before release.
2026-08-03 19:54:31 -05:00
Brian 57e70562e3 feat: bmad-project-context skill — verified kernel + bundle context system (#2674)
* Add bmad-project-context skill; husk document-project and generate-project-context

- New bmad-project-context: one engine, three intents (ingest/query/audit)
  building a verified kernel + bundle context system; interactive default,
  auto/headless mode; works with a BMad install or standalone via bootstrap
- context.py core runtime script (validate/index/map/sweep/resolve/compass/
  sync/bootstrap/config) with 52 tests; config resolution delegates to the
  installed BMad resolver so script and session never disagree
- bmad-document-project and bmad-generate-project-context reduced to
  10-line deprecation shims forwarding to the new skill
- Docs updated: project-context explanation/how-to rewritten, established
  projects guide + FAQ, agents references, workflow map; deprecation notes
  kept for old-name searches
- module-help.csv single PC row; analyst menu DP -> PC
- validate-file-refs: context.yaml is runtime-generated

* refactor: remove map command from context.py — discovery is the model's job

Real-repo testing showed map's descriptor pass grinding through large
asset trees. Discovery is judgment work the model does better with its
own tools; the script keeps only measurement, mutation, and resolution
(validate/index/sweep/resolve/compass/sync/bootstrap/config). SKILL.md
brownfield flow de-prescribed to outcome-driven wording; added a
bounding-question rule for huge external sources.

* feat: closing message when the harness may not load AGENTS.md

43+ harnesses make per-harness load verification impractical. Whenever
AGENTS.md carries the kernel, the run now closes by telling the user:
if your harness doesn't auto-load AGENTS.md, make the context file it
does load pull this one in (e.g. a CLAUDE.md containing @AGENTS.md).
Found in real-repo testing: the kernel sat unloaded under Claude Code
until a CLAUDE.md pointer was hand-made.

* docs: add The Theory of Project Context explanation

Why the skill captures so little: the evidence against generated docs,
the pruning test and what earns a place, the deliberate exclusions with
their reasons, context-as-liability, and an honest comparison with the
two replaced skills.

* fix: address PR review findings

- Force-add eval fixture files the repo gitignore silently dropped
  (pnpm-lock.yaml, _bmad/context.yaml, context/.memlog.md)
- docs/reference/agents.md Analyst row: DP/Document Project -> PC/Project Context
- context.py: cmd_index no longer crashes on an empty index.md (and
  allows overwriting one); inline # comments in frontmatter values are
  only stripped when preceded by whitespace (C#-style values survive);
  cache_lookup tolerates corrupt pointer files; pointer writes are atomic
- triggers.json: positive trigger for the query intent
2026-08-02 23:41:34 -05:00
Alex Verkhovsky 770d425985 fix(installer): apply --set core overrides before config collection (#2671)
`--set core.<key>` was applied only as a post-install TOML patch, but core
values are dependency-bearing: module artifact paths are built from
output_folder during config collection, the output directory is created
from those paths, and each module's config.yaml snapshots the core values
at generate time. A patch that lands after all of that leaves the sources
disagreeing.

`--set core.output_folder=generated` produced output_folder: generated in
core config, BMM paths under _bmad-output, and a _bmad-output/ directory
on disk. `--set core.project_name=Foo` left BMM's copy on the default.
The docs present --set core.<key> and the legacy shortcuts as equivalent
and label --set the preferred form, so both were reachable by following
the documented advice.

Seed core config from setOverrides.core alongside the legacy shortcut
flags, so every core key takes effect during collection rather than only
the four that have a dedicated flag. Non-core overrides keep the existing
post-install patch path.
2026-08-02 05:23:16 -07:00
Brian 57ad793167 refactor(bmm): reorganize skills into agents / plan / ship; retire tech-writer agent (#2658)
* refactor(bmm): move agent skills into agents/

* refactor(bmm): collapse phase folders into planning/ and shipping/

Skills reorganize from numbered pipeline folders (1-analysis,
2-plan-workflows, 3-solutioning, 4-implementation) into two sets:
planning/ and shipping/. Path and phase-label references updated
across marketplace.json, module-help.csv, tests, and bmad-help;
also trues up two marketplace paths that were stale on main
(create-story/dev-story already lived in v6-shims).

* refactor(bmm): shorten skill folders to plan/ and ship/

* refactor(bmm): retire tech-writer agent (Paige on hiatus)

Paige's capabilities were generic LLM defaults with no domain substance;
her one real menu item (DP) dispatches bmad-document-project, which stays
directly invocable and remains on the Analyst menu. Added to removals.txt
so installs clean up, and docs (all languages) carry a hiatus notice —
she returns in the future far more capable.
2026-08-01 01:52:51 -05:00
Alex Verkhovsky 022bcbc66d Rename Quick Dev to Build (#2651)
* feat(bmm): rename quick dev to build

* fix: address build rename review findings

* fix: clarify deprecated build shims

* fix: offer legacy customization migration
2026-07-29 19:40:05 -07:00
Alex Verkhovsky 029ba287bc docs: make Quick Dev the canonical implementation workflow (#2643)
Rewrite published documentation and maintained translations around variable
planning depth with one Phase 4 implementation loop. Update diagrams and AI
indexes, and reject obsolete workflow terminology in deployable output.
2026-07-28 22:30:22 -07:00
Alex Verkhovsky c2530ea53f feat: add inspectable workflow snapshots (#2601)
Render complete dev-auto workflows into root-scoped immutable snapshots
using shared declarative rendering and strict TOML configuration layers.

Keep generated render state out of installer module discovery and custom
file preservation, preserve quick-dev behavior, and provide deterministic
Python version failures for standalone resolver use.
2026-07-28 16:54:22 -07:00
Brian c23f23400d feat: streamline core to an 8-skill set with merged review and editorial skills (#2603)
* feat: streamline core to a 5-skill kernel with standalone skill modules

Core installs 14 -> 5 catalog-visible skills; atoms exit to standalone
modules; installer gains real dependency resolution; zero npm deps.

- Merge bmad-editorial-review-prose/-structure into bmad-editorial-review
  (structure models JIT-loaded, new customize.toml)
- Merge bmad-review-adversarial-general/-edge-case-hunter/-verification-gap
  into bmad-review as selectable lenses; hidden husk-forwarders remain at
  the old IDs (no catalog rows) so gds/loop/os-utils keep working
- Move bmad-brainstorming, bmad-party-mode, bmad-forge-idea out of core to
  src/standalone-skills/ as single-skill modules; add bmad-analysis bundle
  module (curated dependency list over the atoms)
- Move bmad-spec into bmm (2-plan-workflows)
- Modernize bmad-advanced-elicitation: uv run, customize.toml, methods
  pick offloaded to scripts/pick_methods.py (with tests)
- Delete bmad-index-docs, bmad-shard-doc (removes the tree's only external
  npm dependency), and the four deprecation shims (bmad-create-prd,
  bmad-edit-prd, bmad-validate-prd, bmad-create-architecture); all added
  to removals.txt
- Installer: activate the dependencies field (recursive union into
  selectedModules, cycle-guarded, warn on unknown), config-driven picker
  visibility; core stays force-installed
- bmm module.yaml declares deps on the three atoms
- Docs updated across all locales; new reference/standalone-skills.md;
  shard-doc how-tos removed

* Restore original critical wording lost in the review/editorial merges

The merges into bmad-review and bmad-editorial-review were meant to keep
the source skills' critical wording behind progressive disclosure, not
paraphrase it away. Restore what was lost:

- lens-adversarial: clueless-weasel framing, extreme-skepticism wording,
  the at-least-ten-issues quota, and zero-findings-is-suspicious (the
  merge had inverted this to zero-is-valid)
- bmad-review SKILL: zero-findings stance is now per-lens
- lens-edge-case: mandatory exact-order step enforcement
- lens-verification-gap: exact 'No verification gaps found.' clean line
- editorial-review: full Human/LLM reader principles restored to new
  references/reader-principles.md; structure-pass HIGH-VALUE DENSITY
  role, front-load-value, anti-patterns, pacing check, and length_target
  assessment; prose-pass role sentence, analyze-style-first step, and
  merge-overlapping-fixes rule; output summary block and min-3-words HALT

* feat(installer): promote bmad-analysis bundle to src/bmad-analysis-skills

Move the bmad-analysis bundle module out of src/standalone-skills/ into its
own src/bmad-analysis-skills root, teach the installer to resolve it there
(getModulePath, official-modules listing, isBuiltInModule helper), and
update the marketplace manifest and standalone-skills docs to match.

* refactor(bmad-review): rename edge-case lens to edge-case-hunter

Rename the lens code and reference file (lens-edge-case.md ->
lens-edge-case-hunter.md), add explicit when = "always" to the shipped
lenses, and tighten the lens-selection wording in SKILL.md.

* feat(bmad-editorial-review): configurable style guide + analysis-driven rework

Apply the workflow-builder analysis recommendations:

- Make the baseline style guide configurable: style_guide in customize.toml
  now IS the baseline (default "Microsoft Writing Style Guide") instead of
  an empty override slot; SKILL.md no longer hardcodes the guide.
- Inline reader-principles.md into SKILL.md and delete the reference (it
  loaded on every run and was half-duplicated inline).
- Complete the customization surface: activation_steps_prepend/append,
  persistent_facts (project-context glob), on_complete, and a
  review_output_path scalar split out of output_preferences; add a
  file:-load fallback convention.
- Ground word metrics: new scripts/word_metrics.py (stdlib, PEP 723, tests)
  emits total/per-section word counts so impact estimates and the reduction
  summary use exact numbers.
- Cross-pass dedup: prose pass skips CUT-tagged passages and re-attaches
  fixes in MERGE'd ones; output ranks by impact with a long-tail rollup.
- Polish: HALT threshold replaced with plain outcome, duplicate LLM-reader
  bullets merged, all-caps lowered, literal Overview heading added.

* fix(installer): stop cache-refresh git commands from escaping to the parent repo

Two compounding bugs let a pre-commit test run shallow-fetch and hard-reset
the developer's own repository:

1. Git spawns in custom-module-manager and external-manager inherited the
   hook environment. Git exports GIT_DIR (absolute, in worktree checkouts)
   into pre-commit hooks; a child git then targets the hook's repo regardless
   of cwd, and treats its cwd — the module cache dir — as the work tree. The
   cache refresh's 'git fetch --depth 1' + 'git reset --hard origin/main'
   therefore shallowed the shared .bare and moved the checked-out branch.
   New git-env.js strips repo-targeting GIT_* vars from every git spawn in
   both managers, including calls that previously inherited process.env
   implicitly.

2. Test suite 51 (quickUpdate dependency expansion) ran the real
   CustomModuleManager lookup, which scans ~/.bmad/cache/custom-modules and
   network-refreshes every cached clone — real user state. The suite now
   stubs findModuleSourceByCode.

Verified by rerunning the suite with GIT_DIR pointed at the repo and a PATH
shim blocking fetch/reset/clone: 432 passing, zero blocked calls.

* De-scope standalone-skills mechanism: atoms return to core, shims reinstated

Shrink the PR to its heart — the skill merges — and defer the module
mechanics to a follow-up where all skills become module-driven:

- bmad-brainstorming, bmad-party-mode, bmad-forge-idea move back to
  src/core-skills/ as ordinary core skills with their catalog rows
  restored; src/standalone-skills/ and the bmad-analysis bundle module
  are removed
- Installer reverted to main: standalone discovery, hidden-module
  filtering, dependency resolution, manifest changes (test suites 49-51
  removed with the code); the cache-refresh git fix is retained
- The four bmm deprecation shims (create/edit/validate-prd,
  create-architecture) are reinstated so enterprise installs that
  invoke the old IDs or carry _bmad/custom overrides keep working;
  descriptions trimmed to the short husk style; their removals.txt
  entries dropped (removal rides the v7 cut as their frontmatter
  promises)
- marketplace.json keeps the five plugin entries with atom paths
  pointing at src/core-skills/
- Docs (en/cs/fr/vi/zh) reframe the three skills as core thinking
  skills; standalone-skills.md reference page removed

* Fix all findings from the max-effort adversarial review

Correctness:
- Finish the edge-case -> edge-case-hunter lens rename at every caller:
  the forwarder husk, the code-review/dev-auto/quick-dev review layers,
  the renderer test assertion, and the stale example path in
  bmad-review/SKILL.md
- marketplace.json: ship the five core kernel skills with
  bmad-method-lifecycle so its skills' bmad-review/bmad-editorial-review/
  bmad-help/bmad-advanced-elicitation invocations resolve in a
  marketplace install
- pick_methods.py / word_metrics.py: force UTF-8 stdout (Windows locale
  code pages crashed on the catalog's arrows and CJK headings)
- word_metrics.py: pair fences CommonMark-style so 4-backtick fences can
  embed 3-backtick examples without corrupting sections; count CJK
  characters as words
- pick_methods.py: validate --extra entries are JSON objects (was an
  uncaught AttributeError); read catalogs with utf-8-sig (BOM'd CSVs
  silently blanked every num)
- bmad-spec: activation now resolves {output_folder} (which the
  Workspace uses) instead of the unused {planning_artifacts}; drop the
  stale core-only-installs comment
- Editorial husks: pin the legacy output contracts (three-column table /
  Document Summary report and exact empty-state lines) like the review
  husks do
- PRD shims: advertise the real bmad-prd customize keys
  (validation_checklist_template, prd_output_path, run_folder_pattern,
  finalize_reviewers) instead of three that don't exist
- bmad-prd: add the forwarded-activation clause its shims rely on
  (ported from bmad-architecture)
- Locale workflow-maps (fr/cs/vi/zh): add the bmad-spec Phase-2 row the
  English map gained, which every locale's core-tools note points at
- git-env.js: also strip GIT_CONFIG_PARAMETERS and the
  GIT_CONFIG_COUNT/KEY_n/VALUE_n family; pass gitEnv() to the three npm
  install spawns whose transitive git calls inherited hook vars

Consistency:
- brain.py --extra overlay now replaces-by-name like pick_methods.py
  (same customize.toml additional_* semantics across sibling skills),
  with a regression test

* Fix prettier formatting in marketplace.json

* Apply valid CodeRabbit findings

- brain.py: catch malformed --extra overlays (bad JSON, non-array root,
  non-object entries) into the clean error path instead of a raw
  traceback, with a regression test; read catalogs and overlays with
  utf-8-sig; normalize ALL CSV fields (required ones were unstripped and
  could arrive as None from short rows)
- brain-selector: clamp the random-technique count to what the pool can
  supply so the Total badge matches the actual draw (template +
  regenerated assets/brain-selector.html)
- bmad-editorial-review: word_metrics command now uses the explicit
  {skill-root}/ prefix
- resolve_party.py / resolve_personas.py: custom member overrides now
  start from the installed entry, so omitted fields (icon, title,
  description, module, team) survive; non-string member tokens land in
  unresolved instead of raising TypeError; party's member loop gains the
  isinstance guards its personas twin already had
- bmad-brainstorming: fix the SKILL.md claim that headless is the only
  context for self-generated ideas (autonomous mode is interactive);
  autonomous mode honors user-supplied techniques before self-selecting
- Docs: drop duplicate 'only' in the spec template; align zh-cn
  forge-idea's bmad-review description with the English wording

* Create only the output folder at install time

bmm no longer pre-creates planning_artifacts, implementation_artifacts,
and project_knowledge — the last of which put an empty docs/ at every
project root. Skills create those lazily on first write. core now
declares {output_folder} in its directories block, which was previously
created only as a side effect of the artifact folders nesting under it.
2026-07-18 23:49:22 -05:00
Alex Verkhovsky 717479bc3f fix(dev-auto): temporarily revert skill-entry renderer (#2598)
Back out the dev-auto render.py workflow entry change from #2587,
including the follow-up renderer-only fix on top of it, so the skill
returns to the pre-renderer SKILL.md flow while the longer fixes are
worked separately.
2026-07-15 13:19:03 -07:00
Alex Verkhovsky 64157d394c feat(dev-auto): render templates via stdlib Python at skill entry (#2587)
Propagate bmad-quick-dev's render.py pattern (#2281) to bmad-dev-auto.
SKILL.md becomes the two-line stdout-dispatch shim that runs render.py
via uv and follows the instruction it prints; the old SKILL.md body
moves to workflow.md, rendered to _bmad/render/bmad-dev-auto/ with all
compile-time values baked in.

- render.py is a copy of quick-dev's, differing only in skill-name
  references; a test guards against the two copies drifting apart.
- Compile-time config refs ({communication_language},
  {planning_artifacts}, {implementation_artifacts},
  {deferred_work_file}, {document_output_language}) become {{.var}}
  substitutions resolved from the central four-layer TOML config.
  Runtime refs ({spec_file}, {diff_output}, ...) pass through.
- [workflow] customization resolves at render time: on_complete inlines
  into the HALT On Complete section, implementation_handoff into
  step-03, and review_layers materialize as invocation blocks in
  step-04 — the runtime resolve_customization.py calls and the
  activation-time workflow-block resolution step are gone, along with
  the Load Config activation step (values are baked at point of use;
  the language rule moves into each step's RULES).
- Step files now reference workflow.md instead of SKILL.md; step-02
  resolves the spec template's date field; step-04 defines {date} for
  the triage-log header.
- tools/validate-file-refs.js whitelists render/bmad-dev-auto/;
  test:renderer now also runs the new test/test-dev-auto-renderer.js.
- docs: the dev-auto reference's Context Inputs now names the central
  _bmad/config.toml surface instead of _bmad/bmm/config.yaml.
2026-07-14 02:35:00 -07:00
Alex Verkhovsky 49069b8b52 feat(quick-dev): render templates via stdlib Python at skill entry (#2281)
* feat(quick-dev): render templates via stdlib Python at skill entry

Move compile-time variable substitution out of the LLM and into a
deterministic Python step. SKILL.md becomes a two-line stdout-dispatch
shim that runs render.py and follows the instruction it prints. The
renderer reads BMad configuration from the central four-layer TOML
surface introduced in #2285 (_bmad/config.toml plus config.user.toml
and the two _bmad/custom/ overrides), with a fallback to the legacy
per-module _bmad/bmm/config.yaml for pre-#2285 installs.

Compile-time refs ({{.var}}) get substituted at render time. LLM-runtime
refs ({var}) pass through untouched.

Renderer (render.py)
- Python 3 stdlib only (tomllib, already bundled since 3.11). UTF-8 I/O.
  Every invocation rebuilds from scratch — no hash, no cache.
- find_project_root walks up from cwd; HALT to stdout if no _bmad/
  is found anywhere on the path.
- load_central_config deep-merges the four TOML layers in priority
  order (base-team → base-user → custom-team → custom-user) so user
  overrides in _bmad/custom/config.user.toml win over installer-
  regenerated base values. flatten_central_config lifts scalar keys
  from [core] and [modules.bmm] into the renderer's flat namespace;
  module keys beat core on collision (matches the installer's own
  core-key-stripping behavior).
- When _bmad/config.toml is absent, falls through to the legacy
  flat-YAML parser for _bmad/bmm/config.yaml — the renderer keeps
  working across the #2285 transition.
- {{.var}} substitution; unresolved refs emit empty string (Go
  missingkey=zero semantics).
- Smart defaults for planning_artifacts / implementation_artifacts /
  communication_language applied after config load. Derives
  sprint_status / deferred_work_file from implementation_artifacts.
  {{.main_config}} points at whichever surface was actually read.
- Renders every .md in the skill dir except SKILL.md to
  {project-root}/_bmad/render/bmad-quick-dev/.
- On success, stderr summary plus a single stdout line:
  "read and follow {workflow_md}". On failure, stdout HALT directive —
  per the Anthropic skills spec, script stdout is the defined agent-
  communication channel.

Skill entry (SKILL.md)
- Two-line shim: run python render.py, follow stdout. No template
  tokens in SKILL.md itself.

Template conversions
- workflow.md, step-01..05, step-oneshot, sync-sprint-status: convert
  every compile-time {var} reference to {{.var}}. Runtime refs
  preserved.
- spec-template.md untouched (single-curly comment hint stays as
  documentation).

Skill-prose cleanups bundled in
- Remove dead step-file frontmatter: empty-string variable declarations
  (spec_file, story_key, diff_output, review_mode) in quick-dev step-01
  and code-review step-01; empty --- --- blocks in step-03 and step-05;
  the specLoopIteration counter init moved from step-04 frontmatter into
  the step body where first-entry vs loopback semantics are explicit.
- Unify the language rule across all six quick-dev step files plus
  workflow.md.

Tooling
- tools/validate-skills.js: add TPL-01 rule. Files whose name contains
  "template" must not contain compile-time {{.var}} substitutions.
  Template files seed durable, version-controlled artifacts that
  execute on other machines; baking a value at render time would
  freeze a machine-local path into every downstream artifact.
- tools/validate-file-refs.js: add render/ to INSTALL_ONLY_PATHS so
  the validator recognizes the runtime-generated buffer.
- tools/skill-validator.md: document TPL-01; deterministic rule count
  bumped from 14 to 15.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(quick-dev): drop render.py YAML fallback and smart defaults

Single happy path: central _bmad/config.toml with four-layer merge,
Python 3.11+ required (no ImportError guard), HALT if config missing.
Deletes load_flat_yaml, the YAML fallback branch, the setdefault block
for planning_artifacts/implementation_artifacts/communication_language,
and the tomllib ImportError fallback.

Part of plan-quick-dev-python-config-hardening.md (F0).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(quick-dev): normalize render.py paths to forward slashes

On Windows, os.path.join returns backslash-separated paths that can
misrender as escape sequences when later concatenated into POSIX
shell strings or regexes. Normalize the project root to forward
slashes after find_project_root, and use posixpath.join for every
path that gets baked into rendered .md files or joined into config
values. os.makedirs and os.listdir accept forward-slash paths on
Windows, so their call sites stay as-is.

Part of plan-quick-dev-python-config-hardening.md (F3).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(quick-dev): preserve source line endings in render.py

Python text-mode open() with the platform default performs universal-
newline translation: on Windows, LF source files get written as CRLF,
producing spurious diffs when rendered output is compared against
source. Pass newline="" on both the source read and the rendered
write so line endings pass through verbatim.

Part of plan-quick-dev-python-config-hardening.md (F4).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(quick-dev): delete stale .md renders before rebuilding

render.py rebuilds from scratch per the docstring, but
makedirs(exist_ok=True) only overwrites files that still exist in
the source — stale outputs from renamed/deleted source files linger
in _bmad/render/bmad-quick-dev/ forever. Remove every .md in the
render dir before the render loop; keep the dir itself and any
non-.md files.

Part of plan-quick-dev-python-config-hardening.md (F5).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(quick-dev): scope render/ whitelist to bmad-quick-dev

The previous INSTALL_ONLY_PATHS entry 'render/' was a blanket prefix
that let every {project-root}/_bmad/render/... reference in any skill
slip past validation. Narrow to 'render/bmad-quick-dev/' so only this
skill's render buffer is whitelisted. Future skills adopting the
stdout-dispatch renderer pattern add their own entries explicitly.

Part of plan-quick-dev-python-config-hardening.md (F6).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(quick-dev): add renderer smoke test with TOML override

New test/test-quick-dev-renderer.js spins up a temp project with
base _bmad/config.toml and a _bmad/custom/config.user.toml override,
runs render.py, and asserts the override wins in rendered workflow.md
and that sprint_status is rooted at an absolute path in the temp
project. Registered as test:renderer in package.json and chained
into the npm test script.

Part of plan-quick-dev-python-config-hardening.md (F7).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(quick-dev): HALT cleanly when base config.toml is unparseable

Load the four config layers through a load_toml helper that marks the
base _bmad/config.toml as required. A missing, unparseable, or unreadable
base now prints a HALT directive to stdout and exits, instead of being
silently skipped and then crashing downstream with a KeyError when a
derived value (e.g. implementation_artifacts) is absent. Optional layers
still warn on stderr and fall back to empty. Merge semantics are
unchanged (dict-aware deep merge, override wins for lists and scalars).

* fix(quick-dev): resolve render.py via {skill-root} in skill entry shim

The bare `python render.py` shim assumes the agent's working directory is
the skill directory, but agents run from the project root, so the script
is not found. Reference it as `{skill-root}/render.py` — BMAD's standard
token for a skill's installed directory, already used by every other
skill's resolve_customization.py invocation — and add the one-line
`{skill-root}` explainer so the model resolves it from an instruction
rather than guessing. Interpreter stays `python`; the python vs python3
choice is a separate cross-platform concern.

* refactor(quick-dev): resolve [workflow] customization in render.py

render.py now merges the three customize layers (customize.toml ->
custom/bmad-quick-dev.toml -> .user.toml) with the same structural rules as
resolve_customization.py and inlines the resolved [workflow] values, so no
{workflow.*} placeholder survives. workflow.md drops its Step 1 runtime
resolver + manual-merge fallback; step-05 and step-oneshot drop their runtime
workflow.on_complete calls. The shared resolve_customization.py and every
other skill are untouched. Smoke test extended with a [workflow] override
fixture covering inlining, array append, and no-leak assertions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(quick-dev): harden render.py invocation in the SKILL.md shim

The shim called bare `python`, which can resolve to Python 2 or be absent;
render.py needs 3.11+ for tomllib. Spell out python3 and the version
requirement. Also make the exit code authoritative: on a non-zero exit
(including an uncaught crash that writes only to stderr), do not proceed --
report what was printed and stop.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(quick-dev): drop the render.py success stderr line

The "rendered N files" progress line was pure diagnostic noise. The shim
already tells the LLM to ignore stderr and follow the stdout instruction, so
on success render.py now prints only the "read and follow ..." line.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(quick-dev): drop the activation gate sentence from the rendered workflow

The gate ported from #2398 defended against runtime customization
indirection: agents guessed resolver outputs instead of executing them,
silently skipping append steps. render.py inlines the prepend/append
entries into the rendered workflow.md, so there is nothing left to
short-circuit, and each inlined list already carries its own execute-
in-order imperative. In the default install both lists render as
_None._ and the gate is pure noise.

* feat(quick-dev): materialize review layers into invocation blocks

Reconcile #2550 with render-time [workflow] resolution. Main made review
layers configurable as [[workflow.review_layers]] arrays of tables and
had the LLM resolve them during activation; this branch resolves the
[workflow] block in render.py instead, so activation-time resolution no
longer exists and the layer refs must be materialized at render time.

Rather than inlining the layer tables as data plus interpretation rules,
render.py now knows this skill's customization schema outright and
renders review_layers/oneshot_review_layers as direct invocation blocks:
disabled layers (empty instruction) drop out, each active layer becomes
a #### section holding its instruction verbatim, zero active layers
renders the HALT instruction, and runtime placeholders like
{diff_output} pass through. The only judgment left to the LLM is the
optional `when` condition, which renders as a run-time guard line.
The step-04/step-oneshot review intros collapse to a single execute-in-
parallel imperative. Smoke test covers default rendering, replace-by-id,
disable-by-empty-instruction, when-guards, and the all-disabled HALT.

* fix(quick-dev): invoke render.py via uv run per house standard

The SKILL.md shim launched render.py with bare `python3`, which the rest
of BMAD is migrating away from: the customize-bmad docs and the
installer's uv-check standardize on `uv run` (uv provisions a suitable
3.11+ interpreter on demand). Bare `python3` is also fragile on Windows,
where python.org installs expose `python`/`py` rather than `python3`.

Make `uv run` the primary invocation and demote `python3` to the
documented fallback, spelling out `python`/`py -3` for Windows and the
3.11+ tomllib requirement. render.py itself is unchanged; the renderer
test drives it directly and is unaffected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(quick-dev): HALT cleanly on missing or malformed config

render.py derived sprint_status/deferred_work_file from an unconditional
vars_["implementation_artifacts"] subscript, so a config lacking that key
raised a raw KeyError instead of the stdout HALT the rest of the script
uses on bad input. flatten_central_config likewise called .get("bmm") on
merged["modules"] without checking it was a table, so a non-table
[modules] crashed with an AttributeError.

Guard both: HALT with a clear stdout directive when implementation_artifacts
is missing or blank, and coerce a non-dict modules to {} before indexing.
Add renderer regression tests asserting each path exits without a Python
traceback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(quick-dev): resolve config at compile time, drop the runtime re-read

The activation "Load Config" step told the LLM to open {{.main_config}}
and re-resolve project_name, communication_language, sprint_status, etc.
at run time -- but render.py already bakes those from the full four-layer
config merge. main_config pointed at only the base _bmad/config.toml, so
on installs with override layers (config.user.toml / custom/*) the runtime
re-read saw stale values that could contradict the baked {{.var}} in the
same rendered file. It also handed resolution back to the LLM: the drift
this skill's renderer exists to remove.

Delete the ceremony and wire each value where it is actually used:

- Every value the step resolved is already inlined at its point of use
  (planning/implementation_artifacts, sprint_status, communication_language)
  or loaded via persistent_facts (project-context.md), so the central
  block was pure redundancy.
- Fold document_output_language into the per-step language rule, adopting
  the house-canonical form ("Speak in X. Write any file output in Y.")
  already used by bmad-checkpoint-preview.
- Move the {date} = current-datetime definition to step-02, where the
  spec template's {date} field is filled.
- Drop the user greeting (user_name) and user_skill_level tailoring:
  quick-dev is not a conversational skill and neither was load-bearing.
- Remove main_config from render.py; it had no remaining consumer.

Renderer tests repointed at the files that now carry these values, plus
coverage for document_output_language baking and main_config removal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(quick-dev): reference variables by bare name, not placeholder curlies

Curlies mean "expand this to the value"; a bare backticked name means
"this is the variable/field I'm talking about". Several step files wrapped
a variable in curlies where they were only naming, assigning, passing, or
testing it -- so the notation implied an expansion that never happens:

- step-01: identify `epic_num`/`story_num`, set/leave `story_key` unset
- step-02: test `preserved_intent`; and resolve the template's `date` field
  (was `{date}`, which read as "expand date here" rather than naming it)
- step-03/step-05/step-oneshot: pass `target_status` to sync-sprint-status,
  set `title`
- sync-sprint-status: the `target_status` parameter, `story_key` precondition,
  and both `target_status` conditionals

Value tokens that are genuinely materialized in place -- `{spec_file}` paths,
`development_status[{story_key}]`, "set ... to `{target_status}`" -- stay
curly. Also reword step-02's frozen-block instruction from the ambiguous
"substitute it for the `<frozen-after-approval>` block" to "replace the
`<frozen-after-approval>` block in the spec you just filled out with
`preserved_intent`" so it's clear the replacement happens in the artifact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(quick-dev): require uv, drop the python3 interpreter fallback

The SKILL.md shim tried `uv run render.py` and, if uv was missing, retried
with a bare `python3`/`py -3` interpreter. Nothing else in the codebase
does that interpreter fallback: the uv-based skills (bmad-prd, bmad-ux,
bmad-architecture, bmad-product-brief) fall back to reading customize.toml
and using defaults -- graceful feature degradation, never a different
runner -- and the legacy skills just call python3 outright. uv is the
established house runner (memlog.py, resolve_customization.py, lint_spine.py
all invoke it).

That graceful-degrade path does not exist here: render.py is the entry
dispatch that produces the workflow.md the LLM then follows, so there is
nothing to fall back to. The only honest outcomes are "uv runs it" or
"HALT". Make uv the floor and drop the fallback.

Pin the interpreter the house way -- a PEP 723 `requires-python = ">=3.11"`
block, matching memlog.py/lint_spine.py -- so `uv run` provisions a 3.11+
interpreter and the tomllib requirement is guaranteed rather than hoped for.
This replaces the prose "needs 3.11+" hedge the shim used to carry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-07-07 19:31:55 -07:00
Dov Benyomin Sohacheski 5f3ebc91ed feat: add Antigravity CLI (AGY) as supported installer platform (#2551)
* feat: add Antigravity CLI (AGY) as supported installer platform

Distinct from the Antigravity IDE entry: the CLI reads workspace skills
from the shared .agents/skills standard and its own global dir. Closes #2440.

* test: assert Antigravity CLI global_target_dir differs from the IDE
2026-07-06 17:33:20 -05:00
Brian c0fa3231a2 v6.10.0: bmad-loop replaces bmad-automator, changelog draft (#2545)
* docs: draft v6.10.0 changelog; rebrand bmad-auto to bmad-loop; simplify uv check message

Drafts the v6.10.0 changelog entry, headlined by bmad-loop landing as
an installable module and bmad-automator's deprecation in its favor.
Renames the installer's bmad-auto module registry entry (code, name,
url, module-definition path, post-install message) to bmad-loop ahead
of the upstream repo rename. Also simplifies the uv-detected install
message to a plain pass/fail line with a checkmark, since the prior
"ready to run BMAD's Python-powered scripts via uv run" phrasing read
as more actionable than it was.

* feat(installer): support module-code aliases, migrate bauto to bmad-loop

Adds a bauto -> bmad-loop registry alias so existing installs migrate
forward on quick-update (and the interactive Modify flow) instead of
being orphaned as "no source available" the way the prior baut ->
automator rename was (CHANGELOG v6.7.1). ExternalModuleManager resolves
aliases in getModuleByCode/resolveCanonicalCode; quickUpdate translates
installed ids up front and removes the stale _bmad/<alias>/ directory
after a successful migration. removals.txt gains bmad-auto-setup, the
renamed skill id, so stale IDE-side skill dirs get pruned too.

Also corrects bmad-modules.yaml's bmad-loop entry to match the real
upstream repo content (src/bmad_loop/..., bmad-loop-setup skill) now
that the bmad-auto -> bmad-loop rename has actually landed there, and
moves bmad-loop to the top of the installer picker with a shorter,
less wrap-prone description.
2026-07-03 18:55:14 -05:00
Brian 4b6288d836 feat(installer): deprecate automator, add bmad-auto marketplace module (#2532)
* feat(installer): deprecate automator, add bmad-auto marketplace module

Add a `deprecated` registry property (with `deprecation-message`): deprecated
modules are hidden from the installer picker unless already installed, and the
message is surfaced in the picker hint so existing users see the replacement.
Mark bmad-automator deprecated, pointing to bmad-auto.

Add bmad-auto as a new official module. Since its installable skills live
outside a single module.yaml directory (it ships .claude-plugin/marketplace.json
with module.yaml inside the -setup skill's assets/), add a `marketplace-plugin`
flag that routes such registry modules through the PluginResolver — the same
machinery custom-URL installs use — to copy the resolved skill dirs and
module-help.csv. Manifest/version handling is unchanged (source: external).
The flag is opt-in, so existing modules (e.g. WDS) are unaffected.

* fix(installer): harden marketplace-plugin install (review #1/#5/#8)

- Fail loud when a marketplace-plugin module's skills cannot be resolved from
  marketplace.json, instead of silently copying the -setup skill's assets/ dir
  (module.yaml + module-help.csv) with no skills — a broken partial install.
- Extract _copyResolvedSkills() shared by install() and installFromResolution()
  so the official registry and custom-URL plugin paths cannot drift; this also
  picks up the synthesizedHelpCsv (strategy 5) handling in both paths.
- Detect duplicate skill leaf names in _copyResolvedSkills and throw instead of
  letting two skills silently overwrite each other.

* feat(installer): registry-driven post-install messages

Add a `post-install-message` property to the module registry. After the install
summary, any installed module that defines one shows an "action needed" notice;
interactive installs require the user to acknowledge it (press Enter), while
non-interactive (--yes) installs print it and continue so CI never blocks.

Use it on bmad-auto to tell the user to run the bmad-auto-setup skill from their
agent to finish setup (install the orchestrator + wire hooks/policy).

* fix(installer): acknowledge post-install messages before the summary

Show the "action needed" post-install messages (and gate on acknowledgment)
before rendering the install summary, so "BMAD is ready to use!" remains the
last thing the user sees.
2026-06-28 23:19:33 -05:00
Davor Racic 35b19db2e3 fix(installer): accept windows custom module paths (#2511)
* fix(installer): accept windows custom module paths

* fix(installer): reject versioned windows local paths

* style: format custom module manager

---------

Co-authored-by: Brian <bmadcode@gmail.com>
2026-06-26 20:06:07 -05:00
Zied Jlassi c9813c6862 fix(validate-skills): exempt deprecated skills from SKILL-06 trigger (#2486)
* fix(validate-skills): exempt deprecated skills from SKILL-06 trigger

SKILL-06 flagged deprecated compatibility shims for missing a "Use when"
trigger phrase. Deprecated skills omit it on purpose so users are steered
to their replacement, so exempt them from that specific check.

- detect deprecation via description starting with "DEPRECATED"
- keep the other SKILL-06 check (length) and all other rules applying
- add test/test-validate-skills.js + fixtures, wired into npm test

* test(validate-skills): document test helpers with JSDoc

Added JSDoc to the test/assert/hasTriggerFinding helpers so the new
test file documents its own helpers. No behaviour change — the suite
still passes 3/3.
2026-06-23 23:55:34 -07:00
Brian 02739932bc feat(installer): check for uv and standardize messaging on uv run (#2495)
Replace the standalone python3 environment check with a uv check, since
uv is becoming the de facto standard for running BMad's Python scripts
(`uv run <script>`) and uv provisions the interpreter itself.

Installer:
- Remove tools/installer/core/python-check.js and its wiring in ui.js
- Add tools/installer/core/uv-check.js: warn-don't-block, no ack prompt
  (the migration is in progress, so a missing uv never blocks install).
  Missing uv warns and points the user at setup, preferring "ask your
  agent to set up uv"
- Add a uv heads-up to the install intro (install-messages.yaml) and a
  uv tip line to the final "BMAD is ready" summary box
- Swap test Suite 46 from python-check to uv-check coverage

Docs and script comments (no functional skill invocations changed):
- resolve_config.py / resolve_customization.py docstrings: drop the
  "No uv ... plain python3 is sufficient" claims; frame uv run as the
  standard, python3 as the transition fallback; examples use uv run
- customize-bmad.md (en/fr/vi-vn): same reframing; example commands use
  uv run
- Update uv run hints in brain.py / list_customizable test comments
2026-06-22 00:03:03 -05:00
Larry Lewis e600181ab8 feat(installer): add hermes-agent tool target (#2489)
Co-authored-by: bigblackcoder <llewis@sovrlabs.com>
Co-authored-by: Brian <bmadcode@gmail.com>
2026-06-20 19:53:35 -05:00
Davor Racic 5bcc235cdb fix(installer): guard WSL installs from Windows Node (#2470) 2026-06-17 22:19:18 -05:00
Brian 560a2e3a6f feat: installer detects Python version and warns when 3.11+ (tomllib) is missing (#2466)
* feat: installer detects Python version and warns when 3.11+ (tomllib) is missing

Several BMAD features need Python at runtime: memlog (3.8+) and the TOML
config resolution scripts (3.11+ for stdlib tomllib). Users install into
varied environments (Linux, Windows, WSL, Docker) where Python may be
missing or too old, and previously only found out via runtime errors.

The installer now probes PATH at startup (py -3 / python3 / python) and
classifies the result: 3.11+ passes silently with a success line; 3.8-3.10
or missing/too-old Python gets a warning naming exactly which features
degrade, plus per-platform install hints. The warning requires an explicit
ack — continue (fix later, no reinstall needed) or quit and re-run after
installing Python. Warn-don't-block: most of BMAD works without Python, so
the install is never refused. In --yes mode the warning logs and continues
without prompting.

* fix: align Python check with runtime truth (python3) and harden edge cases

Review fixes for the installer Python check:

- Probe python3 first on all platforms: every runtime call site invokes a
  literal python3, so only that command vouches for BMAD features. Python
  found via py/python now gets an explicit mismatch warning instead of a
  false "all BMAD features supported".
- Treat closed/piped stdin as non-interactive (in addition to --yes) so
  scripted installs no longer silently exit 0 via clack's cancel path.
- Retry probes with shell:true on win32 EINVAL (CVE-2024-27980 hardening
  rejects .bat/.cmd shims like pyenv-win's without a shell).
- Add Suite 46 branch tests for checkPythonEnvironment with stubbed
  detection, prompts, and process.exit.
2026-06-11 21:27:52 -05:00
Dov Benyomin Sohacheski fbb48ed711 fix: remove empty skill-group dirs left in _bmad after install (#2461)
* fix: remove empty skill-group dirs left in _bmad after install

Skill cleanup removed each skill's own directory but never pruned the
now-empty grouping folders above it (e.g. _bmad/bmm/1-analysis), leaving
empty dirs behind after every install. Walk up from each removed skill
dir and drop empty parents, stopping at the bmad root.

* fix: harden empty-parent pruning boundary and cleanup

Use a path-boundary check instead of a string prefix so sibling dirs
(e.g. _bmad2) can't match the bmad root, and make the walk best-effort
so a dir that vanishes or fills in mid-walk never aborts the install.
Move the test fixture cleanup into finally so failures don't leak temp
dirs.

---------

Co-authored-by: Brian <bmadcode@gmail.com>
2026-06-11 08:29:02 -05:00
Brian b9431d6d99 Shared canonical memlog script (src/scripts/memlog.py) + bmad-spec as first consumer (#2462)
* bmad-spec: make the memlog canonical, SPEC.md a derived view

Replace the bespoke .decision-log.md with the shared memlog script
(_bmad/scripts/memlog.py, same location as resolve_customization.py).
The append-only memlog becomes the single source of truth; SPEC.md and
spec-authored companions are re-derived from it (plus cited sources for
raw content) on each run instead of hand-patched. This makes bmad-spec
the sole writer of the spec and lets the surrounding steps (PRD, UX,
architecture, epics) feed one spec in any order without merge drift.

- New "Memory and derivation" section: memlog canonical, SPEC.md a
  projection, single-writer rule, append/init via the shared script,
  no status field (terminal moments are event entries).
- Operation reads the prior memlog (not the rendered SPEC.md) as the
  authority on decisions and capability IDs on update.
- Conflict-surfacing: live sources/companions that disagree on a field
  are raised to the user, resolution logged as a new entry.
- Rename .decision-log.md -> .memlog.md across SKILL.md and assets.

* core: add shared canonical memlog.py in src/scripts

Single source-of-truth memlog: append-only, chronological working-memory
log for skills. Installs to _bmad/scripts/memlog.py via the existing
src/scripts sync (beside resolve_customization.py), so any skill can call
it at runtime — bmad-spec is the first consumer.

Merges the neutral API (--workspace, free-form --type/--by, generic set)
with crash-safe fsync atomic writes. No lifecycle status by design: a
memory log records completion as an event entry, never a frontmatter flag.
Also accepts --path for callers that hold the file path directly. 30 tests.

* bmad-spec: include event in memlog --type list

The documented append --type set omitted event while the next line
requires --type event for terminal moments. Align the list.

* Fix memlog Python floor and exclude tests from install

- memlog.py: add 'from __future__ import annotations' so PEP 585/604
  hints stay lazy; the script runs on Python 3.8+ instead of crashing
  below 3.10. Correct the requires-python header to >=3.8.
- installer.js: filter tests/, __pycache__/, .pytest_cache/, and *.pyc
  out of _installSharedScripts so dev-only files never ship to users.
2026-06-11 08:17:03 -05:00
Aristo Rinjuang 397b2a5c87 feat: add CodeWhale as supported installer platform (#2459)
CodeWhale uses .codewhale/skills/ (project) and
~/.codewhale/skills/ (global) for skill directories,
matching the existing config-driven installer pattern.

- platform-codes.yaml: codewhale entry after codex
- test: Test 12b validates install target and setup
2026-06-08 22:29:35 -05:00
Emmanuel Atsé 717a84f2e8 docs(fr): sync French docs with latest English source + fix non-ASCII anchor validation (#2408)
* docs(fr): translation of install-custom-modules

Reference commit 97d32405

* docs(fr): refinement of forensic-investigation

* docs(fr): translation of customize-bmad TOML customization rewrite

Reference commits 0dbfae67, 4405b817, ffdd9bc6, b63086f2"

* fix(docs): handle non-ASCII anchors in link validator

Anchor validation failed for links containing accented characters
(e.g. ./customize-bmad.md#dépannage) because the raw anchor didn't
match the slugified version produced by extractAnchors.

Normalize anchors through decodeURIComponent + headingToAnchor before
comparing, and guard against malformed URI components.

* docs(fr): translation of install-bmad channel and config rewrite

Reference commits 3d824d4c, 91a57499, 0f852a38

* docs(fr): translation of expand-bmad-for-your-org organizational customization patterns

Reference commits c52c9b5b, b63086f2, 4405b817, 0dbfae67

* docs(fr): update install-custom-modules

Reference commit 231a2036

* docs(fr): consolidate non-interactive installation into unified install-bmad guide

Replace standalone non-interactive-installation.md with a redirect stub
pointing to the Installations CI non interactives section in install-bmad.md.

* docs(fr): translation of named-agents

Reference commits 0dbfae67, 4405b817, b63086f2

* docs(fr): refinement of upgrade-to-v6

* docs(fr): refine agents.md

* docs(fr): refine commands.md

rename bmad-create-prd to bmad-prd and update skill descriptions

* docs(fr): refine workflow-map-diagram

Reference commit c52c9b5b

rename create-prd to prd, create-product-brief to product-brief
add prfaq workflow, update agent labels and output names
refine French wording throughout

* docs(fr): update and refine workflow-map

Reference commits: 380590a c52c9b5

* docs(fr): update and refine getting-started

Reference commits c52c9b5b, 0f852a38

rename bmad-create-prd to bmad-prd, add PRD intents section
update Quick Reference table, refine French wording throughout

* docs(fr): refine index.md

Reference commit 0dbfae67

refine French wording throughout, improve phrasing and table formatting

* docs(fr): apply French typographic conventions across all docs

regex-based pass followed by AI + manual review of all 34 source files

Rules applied:
- Apostrophe: ASCII ' → curly ’ (U+2019) in all French prose
- Guillemets: ASCII "..." → « … » with narrow no-break space (U+202F) on both sides
- Narrow no-break space (U+202F): before ; ? ! and after « / before »
- No-break space (U+00A0): before : in French prose
- Thousands separator: narrow no-break space (U+202F) in 4+ digit numbers

Additional review fixes: remaining ASCII quotes in _STYLE_GUIDE.md
checklist items, testing.md, and party-mode.md numbering.

Preserved exclusions: YAML frontmatter delimiters, code blocks,
backtick inline code, URLs, footnote syntax, and English UI text.

* docs(fr): align sidebar ordering with current English docs

Update sidebar order values across all French explanation and how-to
pages to match the live English documentation structure.

* docs(fr): fix omission in quick-dev from english

* docs(fr): style guide formatting

* docs(fr): use quick-dev wording in workflow-map-diagram-fr

* docs(fr): fix typos

* docs(fr): add bmad-investigate / IN trigger to agent tables

The forensic investigation feature added the IN menu trigger and
bmad-investigate skill, but the French docs that enumerate triggers
and agent capabilities were not updated.

- agents.md: add IN trigger and Enquête de code to Amelia's row
- named-agents.md: add Enquête de code to Amelia's capabilities

* docs(fr): fix agent skill identifiers to use bmad-agent-* prefix

The agent skill identifiers in agents.md and commands.md were missing
the -agent- segment of the namespace (e.g. bmad-pm instead of
bmad-agent-pm). All agent launchers use the bmad-agent-* naming
convention since the installer generates skill directories under that
prefix.

- agents.md: fix bmad-dev, bmad-analyst, bmad-pm, bmad-architect,
  bmad-ux-designer, bmad-tech-writer
- commands.md: fix bmad-pm, bmad-architect

* docs(fr): rename bmad-create-ux-design to bmad-ux (#2413)

Apply ee47e30c (refactor(bmad-ux): spine-based UX skill) to French docs.
Rename skill bmad-create-ux-design → bmad-ux and update outputs
from ux-spec.md to DESIGN.md + EXPERIENCE.md.

* docs(fr): translate bmad-spec section

French translation of the bmad-spec section introduced in aa6dece
(feat(bmad-spec): introduce Spec kernel distiller skill (#2417)).

* docs(fr): improve core-tools locution, phrasing and typography

Broader pass across all sections of core-tools.md for more idiomatic
French: consistent section headers (À utiliser quand, Fonctionnement),
natural verb choices, fluid sentence construction and corrected
punctuation.

* docs(fr): apply French typography and table formatting pass

Continuation of 27002100. Systematic pass across all French documentation
assisted by an automated French typography linter:
- Replace regular space with NBSP (U+00A0) before colons per French
  typographic convention
- Align table separator rows to match column widths
- Fix thousands separator in install-bmad.md (5000 → 5 000)
- Correct glossary example code block rendering in _STYLE_GUIDE.md

* docs(fr): fix missing french typography on roadmap.mdx

* docs(fr): translate web-bundles explanation and how-to

French translation of:
- docs/explanation/web-bundles.md
- docs/how-to/use-web-bundles.md
Reference commits: 7729ad46, d659a03d, 3bc2ad30

* docs(fr): refresh skill metadata references

Fixes #2437 for French.

- agents.md: update PM triggers CP/VP/EP → PRD, remove stale US trigger
  from Technical Writer, align PRD description to create/update/validate
- commands.md: fix Cursor/Windsurf skill paths to .agents/skills/,
  update core tools count to 12, align PRD description
- core-tools.md: add missing bmad-customize tool entry and section with
  link to customize-bmad how-to
- party-mode.md: replace stale "BMad Master orchestre" with "Le Party
  Mode orchestre la discussion"

---------

Co-authored-by: Brian <bmadcode@gmail.com>
2026-06-06 20:34:42 -05:00
hanhnt2-hblab db744d405f fix: support nested group paths in SSH Git URLs (#2379)
Co-authored-by: Brian <bmadcode@gmail.com>
2026-05-25 14:15:04 -05:00
Jérôme Revillard 9c291b7ca9 fix: resolve default branch explicitly when updating shallow-cloned custom modules (#2332)
With shallow clones (--depth 1), `origin/HEAD` becomes stale after the
initial clone. The update path used `git reset --hard origin/HEAD` which
never picked up new commits pushed to the default branch.

Resolve the default branch name via `git symbolic-ref refs/remotes/origin/HEAD`,
then fetch and reset against `origin/<branch>` explicitly. Falls back to
`main` if origin/HEAD is not set.

Co-authored-by: Brian <bmadcode@gmail.com>
2026-05-25 14:05:59 -05:00
robertocsko-seon fea431fd2e fix(installer): read config.toml on re-run so user_name (and other user-scoped answers) are preserved as defaults (#2411)
loadExistingConfig only read from legacy _bmad/<module>/config.yaml files, but
the installer writes user-scoped answers (user_name, communication_language, etc.)
to _bmad/config.user.toml. On every subsequent reinstall those values were not
loaded back, so the user got re-prompted instead of seeing their prior answers as
defaults.

Adds parseCentralToml — a lightweight line scanner matching the installer's own
TOML output format — and updates loadExistingConfig to read config.toml and
config.user.toml first (merging both into the same section buckets). Legacy
per-module config.yaml files are kept as a fallback for pre-v6 installations.

Co-authored-by: RobertOcsko <robert.ocsko@;seon.io>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Brian <bmadcode@gmail.com>
2026-05-25 13:56:05 -05:00
Farzad Rashidi 065003fc95 Fix stale custom-source redeploys on quick-update (#2399)
* fix(installer): refresh custom-source cache on quick-update and persist channel marker

* fix(installer): persist real next ref and atomically dedupe custom refresh

* fix(installer): preserve custom-source cache when remote unreachable

When git fetch fails against an existing custom-module cache, cloneRepo
previously wiped the cache and attempted a fresh clone, which then also
failed for the same reason (network down, repo deleted/moved, auth
revoked) — leaving the user with no usable cache. With the new
quick-update refresh path calling cloneRepo for every cached custom
module, this turned transient remote outages into cache loss on every
quick-update.

- cloneRepo: on fetch failure with an existing cache, keep the previous
  clone and surface a warning via prompts.log.warn instead of removing
  the cache. The downstream metadata write uses the existing HEAD.
- _refreshRepoCacheOnce: update the comment to reflect that the common
  "remote unreachable but cache exists" case is now handled inside
  cloneRepo; warn on the remaining unrecoverable failures so they
  aren't silent.

Tests: 349 passed, 0 failed.

---------

Co-authored-by: Brian Madison <bmadcode@gmail.com>
2026-05-25 13:39:04 -05:00
Brian 2b76d03316 feat(web-bundles): release packager + manifest for bmadcode.com/web-bundles/ (#2424)
* feat(web-bundles): add release packager + bundle manifest

Adds the infrastructure for shipping web bundles as downloadable ZIPs
attached to a GitHub Release, consumed by the upcoming
bmadcode.com/web-bundles/ page.

- web-bundles/bundles.json — manifest with persona, tagline, description,
  accent color, motif key, knowledge files, and feature flags
  (web-browsing, deep-research, stitch integration) for each of the 6
  bundles. Top-level releaseTag and downloadUrlPattern so the
  consuming page can construct download URLs without hardcoding.
- tools/bundle-web-bundles.js — packager that zips each bundle dir into
  dist/web-bundles/{slug}.zip and prints the gh release create command.
  Zero dependencies; uses system zip.
- .gitignore — exclude dist/web-bundles/ build artifacts.

The web-bundles-v1.0.0 release on GitHub is currently in draft state
with the 6 zips attached; it'll be published in coordination with the
Ghost site page going live.

* fix(web-bundles): single-source release tag, sharper bundle copy

- Remove downloadUrlPattern from bundles.json — the consuming page
  derives the URL from releaseTag, so version bumps now touch one
  field instead of two.
- product-brief-coach: drop "one-page" (briefs are whatever length
  the product earns).
- brainstorming-coach: real numbers — 60 techniques across 10
  categories — with concrete examples (SCAMPER, Drunk History
  Retelling, Nature's Solutions, Six Thinking Hats, etc.) so the
  card actually communicates the surprising breadth.

* fix(web-bundles): harden release script per PR review

- Verify the zip CLI is on PATH up front with a clear install
  hint, instead of crashing mid-zip with an opaque execSync error.
- Wrap JSON.parse in try/catch; validate the manifest shape (bundles
  array non-empty, releaseTag present, slug present per entry) before
  trying to package, so config errors fail with a targeted message.
- Catch zip failures per-bundle and surface the failing slug.
- Refuse to print the gh release command when zero bundles were
  packaged (would otherwise mislead the user into creating an empty
  release).
- Derive --title from manifest.releaseTag so the printed command can
  never drift from the actual tag (was previously hardcoded
  "Web Bundles v1" while the tag had moved to v1.0.0).
- Remove the stale `web-bundles-v1` example from the file header.

Addresses augmentcode bot review comments on PR #2424.

* docs(web-bundles): rewrite copy to actually sell what each bundle does

The JSON drives the bmadcode.com/web-bundles/ page; previous copy
was generic and undersold the actual capabilities. Rewrote each
tagline + description to lead with concrete, differentiating facts
pulled directly from each bundle's SKILL.md:

- Brainstorming Coach: 60 techniques across 10 categories with
  specific names (SCAMPER, Drunk History Retelling, Nature's
  Solutions, Shadow Work Mining, Superposition Collapse); calls
  out the 4 routes (browse, recommend, random, progressive) and
  the ~100-idea quantity-unlocks-quality target.
- Product Brief Coach: names the three intent modes (Create /
  Update / Validate) and the two working paths (Fast / Coaching);
  surfaces the [ASSUMPTION] tag system and the Addendum.
- PRFAQ Coach: details the 4 stages (Ignition / Press Release /
  Customer FAQ / Internal FAQ + Verdict), the 9 press release
  sections, the weasel-word list ("best-in-class", "seamless"),
  and that it adapts for commercial, internal, OSS, community.
- PRD Coach: spells out the two entry points (Vision+Features
  vs Journey-led), named-protagonist journeys, glossary
  discipline, stable ID system (FR-1..N, SM-C1..N), and the
  7-dimension validation rubric.
- UX Coach: leads with the two-spine contract (DESIGN.md +
  EXPERIENCE.md), Don Norman framing, named-protagonist
  journeys, surface closure as the test, and Stitch integration.
- Market & Industry Research: leads with Deep Research as the
  engine, names Porter and Christensen as anchors, lists the 6
  deliverable sections, and frames the deliverable as synthesis
  not a research dump.

* fix(web-bundles): security hardening + strict bundle validation

Two issues raised by coderabbit on the latest commit:

1. Shell injection surface: execSync was building the zip command
   with a template literal that interpolated bundle.slug from JSON.
   Even with our controlled inputs, a slug with shell metacharacters
   would break quoting. Switched to execFileSync with an argument
   array (no shell) and added a strict ^[a-z0-9][a-z0-9-]*$ slug
   regex enforced before any FS or zip call.

2. Missing bundle directories were [SKIP]-warned but the script
   still printed the release command, allowing an incomplete release
   to ship cleanly. Now treated as fatal: any missing or invalid slug
   blocks the printed gh command and exits non-zero with the offending
   slugs listed.
2026-05-25 11:43:55 -05:00
Emmanuel Atsé cede485217 feat(docs): Add sidebar order validator for doc frontmatter (#2409)
* feat(docs): add sidebar order validator

Adds tools/validate-sidebar-order.js to validate sidebar.order values
in YAML frontmatter across English and translated docs.

Checks for duplicate orders, gaps in sequence, and missing order fields.
For translations, also warns on order drift from English counterparts.
Wired into the quality script as docs:validate-sidebar.

* fix(validate-sidebar): tighten language detection and drift guard, add docstrings

* fix(validate-sidebar): replace subdirectory heuristic with locale pattern matching

detectLanguageDirs() previously classified any top-level docs/ directory
containing subdirectories as a translation language. This was too broad —
if an English section ever gained nested subfolders it would be silently
excluded from validation.

Replaced with a BCP 47 locale-code regex (/^[a-z]{2}(?:-[a-zA-Z]{2})?$/)
that matches known patterns (cs, fr, vi-vn, zh-cn) and won't falsely
classify content sections like explanation/ or reference/.

* fix(validate-sidebar): guard drift check against undefined order values

extractSidebarOrder() returns { hasSidebar: false } when no sidebar block
exists, leaving order as undefined rather than null. The drift check only
guarded against null, allowing undefined values to emit noisy warnings
like "Order drift: ... order undefined".

Changed the guard to typeof === 'number' which correctly excludes both
undefined and null without relying on a specific sentinel value.

* chore(validate-sidebar): add JSDoc docstrings to all functions

Adds @param and @returns annotations to extractSidebarOrder,
detectLanguageDirs, getEnglishSections, checkDirectory,
checkTranslationDrift, and relativePath.

* fix(validate-sidebar): add to pre-commit hook

* refactor(validate-sidebar): harden parsing and edge-case handling

Refactor to main() wrapper with pure return-based APIs, single directory
scan, and shared reporting. Harden frontmatter parsing (anchored delimiter,
direct-child-only order extraction, flow mapping support) and validation
(Infinity/zero guard, gap flood cap, multi-segment locales, graceful ENOENT).

* docs: fix sidebar.order duplicates and gaps across all locales

Resolves all validator errors flagged by the new
tools/validate-sidebar-order.js check.

English (docs/{explanation,how-to,reference}/):
- Renumbered to remove duplicates; established reading order
  for new explanation pages added since orders were last set.

Translations (cs, fr, vi-vn, zh-cn):
- Mirrored English structural ordering where files exist, then
  compacted to 1..N within each directory to eliminate gaps
  caused by missing translation files.

Non-blocking drift warnings remain where translation directories
have fewer files than English; these are expected per the
validator's design.

---------

Co-authored-by: Brian Madison <bmadcode@gmail.com>
2026-05-25 10:15:37 -05:00
Brian ee47e30cf6 refactor(bmad-ux): spine-based UX skill (DESIGN.md + EXPERIENCE.md) (#2413)
* 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.
2026-05-22 23:16:06 -05:00
Dicky Moore a08522631b fix(installer): preserve stale installed modules during update (#2391)
* 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
2026-05-18 08:39:11 -05:00
Brian 74cf467d57 v6.7.0: bundle module registry, retire marketplace, refresh display names (#2388)
* 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.
2026-05-17 17:47:25 -05:00
Davor Racic 0f852a38ac feat(prompts): add directory prompt with updated Clack runtime (#2387)
* 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
2026-05-16 18:30:25 -05:00
Brian 724867d48d fix(installer): descriptive error when module definition missing after clone (#2377)
* 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
2026-05-12 23:44:11 -05:00
bmad a3e0545847 feat(installer): register automator module 2026-05-08 18:10:22 -03:00
Alex Verkhovsky e36f219c81 refactor(catalog): rename after/before to preceded-by/followed-by (#2360)
* 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>
2026-05-01 12:28:50 -07:00
jheyworth 9debc165aa fix(installer): remove bmad-help from Copilot Custom Agents picker (#2359)
* 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>
2026-04-30 08:03:02 -05:00
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
Tankatronic fcf20f1c7b Fix/azure devops url parsing (#2269)
* 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>
2026-04-28 22:06:37 -05:00
Brian 91a57499e9 feat(installer): add --set and --list-options for non-interactive config (#2354)
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
2026-04-28 20:15:57 -05:00
Brian 48a7ec8bff fix: align bmad-help.csv with documented schema and clean up source rows (#2278) (#2349)
* 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).
2026-04-27 23:54:21 -05:00