760 Commits

Author SHA1 Message Date
Alex Verkhovsky 2c10d5ba45 feat(build): add the route lever and route reporting (#2860)
Add a `workflow.route` customization (oneshot, full, auto; default auto)
to bmad-build and bmad-build-auto. A route named in the invocation
becomes `--set workflow.route=<value>` on the render command. Templates
render only the pinned route's continuation; auto renders both plus the
selection rule, byte-identical to before apart from reporting. Story
frontmatter gains `route_source` (pinned or auto), and a pinned run
halts when a resumed spec's recorded route differs.

A pinned oneshot run does what it was told, how it was told: the
mid-build stop conditions narrow to an intent gap. Work turning out
larger than expected is the routing call the pin already made, and no
longer stops the run. A hole in the intent still does, because the only
alternative is to guess: bmad-build asks the human, bmad-build-auto
halts blocked with `intent gap`.

Give templates a `halt(message)` function so they can reject values they
cannot act on; each build skill's workflow.md uses it to halt the render
on a route outside oneshot, full, auto instead of silently rendering the
auto path.
2026-09-12 04:06:26 -06:00
Alex Verkhovsky 94b6727b00 refactor(renderer): render skill sources as Jinja2 templates (#2857)
Replace the regex token substitution and the line-parsed bmad-if
directives in render_skill.py with Jinja2. Templates see config,
workflow, and snapshot(); undefined names, empty entry files, and
links to omitted sources halt; every value a render reaches and the
Jinja2 version key the generation. Migrate the five rendered skills'
sources to the new forms, keep their shipped output byte-identical,
and update the validator rule and the authoring docs.
2026-09-11 16:45:10 -06:00
Alex Verkhovsky d7d4cfffbb feat(renderer): add invocation overrides and conditional sections (#2844)
Add repeatable --set key=value arguments and an --overrides <file.toml>
file to render_skill.py. Shipped defaults, project TOML, user TOML, the
invocation file, and command-line assignments resolve into one effective
customization using the existing structural merge; persistent files are
never written.

Two --set paths that are equal or nested halt as a caller error. The
renderer keeps no separate schema of customization keys: a --set path
must exist in customize.toml, and any invocation override that reaches
no token or condition halts. Values are validated where consumed.

Standalone [[bmad-if:path == literal]] / [[bmad-else]] / [[bmad-endif]]
lines select sections before token and link resolution. A secondary
file that filters to nothing is omitted from the snapshot; workflow.md
filtering to nothing is an error. Condition inputs join the generation
identity so identical output from different inputs still yields
distinct snapshots.

Document both interfaces, ignore the per-machine skills-lock.json, and
cover precedence, equivalent forms, isolation, conflicts, unused
overrides, malformed input, nested conditions, and snapshot reuse.
2026-09-07 19:33:19 -06:00
Alex Verkhovsky cf947f8937 refactor(retrospective): run through the skill renderer (#2845)
* refactor(retrospective): run through the skill renderer

Make bmad-retrospective a rendered skill like bmad-build and
bmad-walkthrough. SKILL.md becomes the render_skill.py launcher, and a
new workflow.md carries the goal, conventions, modes, activation,
inputs, and phase flow. Reference files are reached through
[[bmad-snapshot:...]] tokens, artifact paths use
{{.implementation_artifacts}}, {{.planning_artifacts}} and
{{.output_folder}}, and the finish section reads {workflow.on_complete}
at render time instead of calling resolve_customization.py. The bundled
scripts keep running from {skill-root}/scripts. The greeting step is
gone; its going-in-concerns prompt moves to the point where the epic is
fixed.

* feat(render): bind {skill-root} to the installed skill directory

Rendered skills can bundle scripts and other non-Markdown files that
the snapshot does not carry. Resolve {skill-root} in skill sources to
the absolute installed skill directory at render time, so no runtime
placeholder survives into the snapshot, and add the skill path to the
generation identity so the same sources installed at two locations
publish distinct generations. Customization values keep binding
{skill-root} to the snapshot. The renderer tests now cover all four
rendered skills and the retrospective's script paths.

* docs(skills): tidy activation prose after the greeting removal

Move the retrospective's going-in-concerns prompt above the sprint-mode
split so it applies in stories mode too, and drop the greet-step
mentions from the walkthrough customize.toml comments.
2026-09-07 17:56:02 -06:00
Alex Verkhovsky fa1637ee40 build: move the Node toolchain into docs-site (#2834)
The root package.json, lockfile, .nvmrc, prettier ignore file and
.npmignore are gone. docs-site has its own package.json and lockfile
with the Astro, ESLint and Prettier dependencies, and its scripts run
relative to that directory. tools/quality.py, both workflows and the
docs all call npm inside docs-site.

stamp_release.py stamps only the 29 skill manifests now; the version
lives nowhere else on this branch. The tests for package stamping go
with it.
2026-09-05 18:11:37 -06:00
Alex Verkhovsky ad86519c6b build: replace the npm lint stack with pre-commit (#2832)
* build: replace the npm lint stack with pre-commit

markdownlint-cli2, prettier and eslint for YAML/JSON, husky and
lint-staged are gone. pre-commit runs ruff, rumdl (the same five
markdown rules), yamllint, yamlfix, the JSON checks, both validators
and pytest, at commit time and over the whole tree from
tools/quality.py, which is now what `npm run quality` calls. ESLint and
prettier stay only for the docs-site scripts and tests. quality.yaml
collapses to a Python job and a docs-site job.

yamlfix keeps one blank line and no document-start marker: its defaults
strip blank lines inside block scalars and add `---`, which the sprint
status scripts do not write back. The JSON hook keeps key order and
non-ASCII text.

* style: apply yamlfix and JSON formatting to the tree

Mechanical output of the new hooks; every file parses to the same data.

* docs: state what the commit hook covers
2026-09-05 13:25:19 -06:00
Alex Verkhovsky 2f6e46edbe refactor(docs-site): move the doc tooling out of tools/ (#2831)
* refactor(docs-site): move the doc tooling out of tools/

The five doc scripts and their test exist because of Starlight: sidebar
order frontmatter, the rehype link convention, the built site, and the
Astro build itself. They now live under docs-site/scripts and
docs-site/test, next to the rehype plugins and the site tests, which
leaves tools/ Python-only. ESLint stops ignoring those two directories
and its script rules now target them; the Astro sources stay excluded.

* ci(docs): deploy the site from dev

main moves only by release fast-forward, so a docs deploy tied to it
would lag every doc change until the next release. Deploy on push to
dev instead; main receives the same tree later and needs no deploy.
2026-09-05 12:41:20 -06:00
Alex Verkhovsky 40c4572a31 build: declare the Python toolchain in pyproject.toml (#2830)
* build: declare the Python toolchain in pyproject.toml

Pin the dev environment (pytest, pytest-xdist, pyyaml, ruamel.yaml, ruff)
with uv instead of a one-line --with list in package.json. The project is
marked non-packaged: the tree itself is what gets installed, and shipped
scripts keep their inline metadata. The validate CI job now runs on uv
alone, without Node, and gains a ruff check.

* style: apply ruff to tools and skill scripts

Mechanical output of ruff check --fix and ruff format under the new
config, plus four hand edits: explicit zip strictness in setup.py and
test_sprint_status.py, an f-string for the hex colour in brain.py, and a
noqa on the sys.path-dependent import in render_skill.py. No behaviour
change; 500 tests pass.

* build: declare Python 3.11 as the floor of every shipped script

Eighteen scripts declared 3.8 or 3.10 inline while ruff targeted 3.11,
so an autofix could introduce syntax those scripts did not advertise.
The lower floors were never reachable: every skill that carried one
also runs a 3.11 hub script, and uv fetches whatever interpreter a
script asks for. All inline metadata now says 3.11, and a test keeps
the inline floors equal to requires-python and the ruff target.
2026-09-05 12:28:22 -06:00
Alex Verkhovsky 8612d316ea fix(release): promote dev to main with fast-forward pushes 2026-09-05 04:32:20 -06:00
Alex Verkhovsky bdec5aafe0 feat(release): stamp dev releases and package metadata 2026-09-05 03:00:11 -06:00
Alex Verkhovsky b762e7e29b fix(update): pin GitHub manifest checks to main 2026-09-05 02:37:01 -06:00
Alex Verkhovsky 7807036e29 fix(dist): point skill update sources at BMAD-METHOD 2026-09-05 02:35:34 -06:00
Alex Verkhovsky 04055f1236 chore: bump placeholder version to 6.12.0-next
Main has released 6.12.0, so the module manifests and the package
version now carry the next placeholder above it.
2026-09-05 01:45:00 -06:00
Alex Verkhovsky 0258223cb7 fix(tools): carry the Windows path-leak fix into the Python checker
The Python rewrite of the file-ref checker ported the JS pattern verbatim,
including the `\\\\` that only matched the escaped `C:\\Users` form. Main
fixed the JS copy in #2794 before this branch deleted it; apply the same
pattern here so the rebase does not revert the fix.
2026-09-05 01:43:24 -06:00
Alex Verkhovsky 8f09e6a610 refactor(skills): stop writing module config.yaml files nobody reads
Setup resolved config through the script already, but still wrote
core/config.yaml and bmm/config.yaml on every run. Nothing reads them.

Drop the writes and the code that existed only to build them: the
legacy_config projection threaded through materialize_bmad/stage_bmad,
without_manifest_answers, delete_path, stringify, and the whole YAML
parse/render/fill path. ensure_file now merges TOML only.

Existing files are left in place, like the other classic-installer
traces, and both paths join LEGACY_LEFTOVERS so doctor reports them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sn1de7Zc9yWcJnJkE6QNis
2026-09-05 01:43:24 -06:00
Alex Verkhovsky 42189fe117 fix(release): reject build metadata in the version stamper
setup.py drops build metadata when ordering versions, so 6.12.0+hotfix
compares equal to 6.12.0 and a release stamped that way is invisible to
every installed copy. The runbook warned against it; the stamper accepted
it. Reject it before anything is written.

The version rule is now "orderable and distinguishable", one notch
stricter than setup.py's orderability - the contract test pins that gap
and pins the premise it rests on.
2026-09-05 01:43:24 -06:00
Alex Verkhovsky 3baa7c64fe fix(dist): point knowledge at references/help.md, the file that exists
The knowledge value named `reference/help.md`, but the bmad skill has no
reference/ directory — the file is references/help.md. Nothing ever resolved
the value, so the dangling pointer reached 30 manifests and the release
stamper's constant unnoticed.
2026-09-05 01:43:24 -06:00
Alex Verkhovsky 94ef73af22 fix(setup): refuse to replace a symlinked _bmad with a clear message
setup and doctor rewrite _bmad wholesale via replace_dir, so running
them through a symlinked _bmad crashed mid-flight with a raw
IsADirectoryError from the backup rename. Reads through the symlink
are the point of symlinking and stay untouched; only the write paths
now fail fast, naming the link target and the --project-root to use
against the real installation. The doctor flow rejects in its
missing-_bmad pre-flight so --list-config-questions --doctor fails
before interrogating the user.
2026-09-05 01:43:24 -06:00
Alex Verkhovsky eaeebebd76 feat(setup): report plugin-shipped copies as plugin-managed in the update check 2026-09-05 01:43:24 -06:00
Alex Verkhovsky baf0fe9aea feat(dist): add a knowledge key pointing every manifest at the bmad help doc 2026-09-05 01:43:24 -06:00
Alex Verkhovsky 1db98c5b14 docs(release): point step 7 at the release script itself, not the removed README section 2026-09-05 01:43:24 -06:00
Alex Verkhovsky 9535e0968c docs(release): tag each release so force-pushed main keeps history 2026-09-05 01:43:24 -06:00
Alex Verkhovsky f7ec2f77a0 feat(dist): ship plugins from bmad-plugins; split skills into method and toolbox modules
The seven standalone support skills that help.md lists as belonging to
no path and no stage — brainstorming, forge-idea, deep-recon,
advanced-elicitation, review, party-mode, customize — now carry
module = "toolbox"; the other 22 skills carry module = "method". The
module key names only the distribution grouping; the _bmad/bmm runtime
config path skills read is staged by setup.py independently of it.

The Claude marketplace and the Codex plugin lid leave this repo: both
plugin ecosystems are built by bmad-code-org/bmad-plugins from the
stamped manifests bmad-skills main serves, sharing one skills tree per
plugin. The stamper therefore stamps and validates only the manifests
(exact key set, known module, the one known update source, per-module
byte identity), and the runbook gains a rebuild-the-plugins step.
2026-09-05 01:43:24 -06:00
Alex Verkhovsky d68545414a feat(plugins): split the Claude marketplace into bmad-bmm and bmad-tools
Two marketplace entries share source "./" and list their skills
explicitly, replacing the single plugin whose skills tree was a symlink
to skills/ — with per-plugin subsets the symlink bought nothing. The
plugins/bmad-method lid is deleted. bmad-tools has no skills yet, and an
empty skills list makes Claude Code fall back to scanning skills/, so
its source points at the empty plugins/tools directory instead.

The stamper now validates the whole distribution shape before writing:
every manifest carries exactly module, version, and update_source, with
a known module and the one known source; the marketplace has exactly
one entry per module; and each entry's skills list equals, as a set,
the skills whose manifest carries that module — no orphans, no
double-shipping, no dangling paths (a dangling path is load-bearing:
Claude Code silently falls back to shipping every skill for one). The
manifest byte-identity check is now per module, since manifests
legitimately differ in the module line.

Verified live: bmad-bmm installs with 29 skills, bmad-tools with 0,
and a scratch stamp of the real tree passes.
2026-09-05 01:43:24 -06:00
Alex Verkhovsky 38156784da docs(release): note the raw.githubusercontent CDN delay after a release 2026-09-05 01:43:24 -06:00
Alex Verkhovsky 26695850a4 fix(release): fail the stamp when a skill directory lacks its manifest
The stamper globbed for manifests, so a skill directory without
module-manifest.toml was silently skipped and would ship unstamped
with no version or update_source. Enumerate skill directories and
fail naming the offender before anything is written.
2026-09-05 01:43:23 -06:00
Alex Verkhovsky edb144f31f feat(release): stamp every Claude marketplace plugin entry
The tools/bmm split will put a second plugin into the Claude marketplace,
so the stamper no longer hardcodes plugins[0] and the bmad-method path.
It now stamps the version of every entry in the marketplace plugins
array, discovers plugins/*/.claude-plugin/plugin.json by glob, and
requires the marketplace entry count to match the plugin manifest count.
Each textual rewrite is proven against the parsed JSON: the result must
equal the original tree with only the intended version nodes changed,
and a "version" key anywhere else in a stamped file fails the run
before anything is written.
2026-09-05 01:43:23 -06:00
Alex Verkhovsky c61a3d2554 refactor(release): stamp only the skill manifests
The version's single source of truth is skills/*/module-manifest.toml.
Plugin metadata (Claude marketplace and plugin.json, Codex plugin.json)
is no longer stamped — whatever builds those artifacts reads the version
from skills/bmad/module-manifest.toml. The textual single-"version"-key
rewrite would have broken the moment the Claude marketplace gained a
second plugin, and those lids are likely to leave this repo anyway.

Tests updated: JSON-stamping cases replaced with a regression test that
plugin metadata is left byte-identical; runbook expectation adjusted.
2026-09-05 01:43:23 -06:00
Alex Verkhovsky 120823d140 feat(release): add version stamper and release runbook for the skills mirror
Make the bmad-skills mirror's main branch release-only: dev now mirrors
this branch unstamped, and main is always current dev plus one stamp
commit cut by following tools/release.md.

- tools/stamp_release.py: stdlib-only stamper that validates an
  orderable SemVer argument (rejects -dev, which setup.py cannot
  order), rewrites the version line in every skills/*/module-manifest.toml
  textually to keep the manifests byte-identical, and sets the version in
  .claude-plugin/marketplace.json, plugins/bmad-method/.claude-plugin/
  plugin.json, and .codex-plugin/plugin.json without reformatting them.
  Nothing is written unless every file validates; after writing it
  re-reads everything and fails naming the offending path if the
  manifests diverge or any file carries a different version.
- tools/release.md: self-contained runbook — clean detached checkout of
  origin/dev, human-chosen version that differs from what main serves,
  stamp, review, commit, force-with-lease push of HEAD:main.
- tools/tests/test_stamp_release.py: unit tests covering the happy path,
  invalid and -dev versions, missing version line/key, divergent
  manifests, idempotent re-stamp, and formatting preservation.
- TEMP-RELEASE-PROCESS.md: the mirror is the testbed for both the npx
  install/update flow and the release process that feeds it. Records the
  dev/main branch model, the 0.0.0-next.N throwaway versions to stamp
  there, and a note to replace the file with the real release
  instructions before this branch merges to main.
- AGENTS.md: replace the test-mirror section with a pointer to that file.
- .npmignore: exclude the new tool files and the temporary runbook from
  the npm tarball.
2026-09-05 01:43:23 -06:00
Alex Verkhovsky 6a098b6e6e chore: drop unused Augment review config and stale docs prompts
Augment is no longer in use, and the tools/docs working prompts have
not been run in months.
2026-09-05 01:43:02 -06:00
Alex Verkhovsky 121889775e refactor: rename website/ to docs-site
The directory is the Astro docs site, not a generic website, and the old name collided with the docs/ content tree.
2026-09-05 01:43:02 -06:00
Alex Verkhovsky 41faf4f1da chore: remove unused SVG visual-diff helper
The script's default diagram has been gone since January, and nothing in the build or quality pipeline invoked it.
2026-09-05 01:43:02 -06:00
Alex Verkhovsky 09f4b119d4 chore: rewrite the deterministic skill validator in Python
Replace tools/validate-skills.js with a stdlib Python 3.11 port and rewire
validate:skills and test:skills onto it. Observable behavior is preserved,
including the JS frontmatter quirks; in-skill file walks are sorted.
2026-09-05 01:43:01 -06:00
Alex Verkhovsky b33544ae55 feat(tools): check backticked skill-relative refs, flag stray files, prune dead grammar
The checker's V4/V5 grammar (exec attrs, invoke-task, step metadata,
Load directives, quoted dot-paths, {_bmad} shorthand) matches nothing
in the flat tree; it verified only four script filenames. It now
resolves backticked slash-paths against the containing file's directory
and the skill root, flagging a missing file only when the path's first
directory exists — paths without one are prose, so the current tree
stays at zero false positives (276 refs verified, up from 135). Files
sitting directly under skills/ are reported as stray.
2026-09-05 01:43:01 -06:00
Alex Verkhovsky da9034dbc2 fix(tools): repoint the file-refs checker at the flat skills tree
The checker still scanned src/, which the flattening removed, so it
crashed on any fresh checkout and failed the quality gate. It now scans
skills/; the obsolete core-skills/bmm-skills module mapping is replaced
by _bmad/scripts/ -> skills/bmad/scripts/, with the install-only and
install-generated skip lists unchanged.
2026-09-05 01:43:01 -06:00
Alex Verkhovsky aed23a3a0b refactor(skills): extract hub help.md and ship TOML manifests
Move the duplicated BMM routing guide into the bmad hub skill and replace
every module-manifest.md with a two-key TOML file parsed by stdlib tomllib.
Drop PyYAML from setup.py and from test:npx-skills.
2026-09-05 01:43:01 -06:00
Alex Verkhovsky 9cace71719 chore: port the web-bundles release packager to Python
Stdlib zipfile replaces the zip-CLI dependency; behavior and output
are otherwise unchanged. Verified live on both the success path (all
6 bundles packaged) and the missing-directory refusal path.
2026-09-05 01:43:01 -06:00
Alex Verkhovsky 0cfe6865e0 chore: delete orphaned format-workflow-md and workflow-path-regex tools 2026-09-05 01:43:01 -06:00
Alex Verkhovsky 84def5a7d3 refactor(skills): flatten sources into a root skills/ tree
Move core and BMM skills to skills/<id>/ so npx skills can install
the repo as-is. Copy the BMM module manifest into every skill, move
the shared Python runtime into skills/bmad/scripts/, drop src/, and
retarget repo tests at the new locations.
2026-09-05 01:43:01 -06:00
Alex Verkhovsky e450ebc70d chore: rewrite the file reference checker in Python
Port tools/validate-file-refs.js to tools/validate_file_refs.py (PEP 723,
pyyaml) preserving detection, resolution, CLI, and CI-annotation behavior.
CSV extraction is dropped: .csv leaves the scan set, and the CSV test and
fixtures are deleted rather than ported. The npm dependencies block (yaml,
csv-parse) goes away with its sole consumer; validate:refs and test:refs
now run via uv, and test:refs joins the quality chain. A new stdlib
unittest suite covers extraction, mapping, skip lists, UNRESOLVED vs
BROKEN, leak detection, exit codes, and the GitHub Actions output path.

The port also hardens what the JS left fragile: multi-document YAML is
scanned in full, non-UTF-8 bytes are replaced instead of crashing the
run, and directory symlinks are not traversed.
2026-09-05 01:43:01 -06:00
Alex Verkhovsky 636f8e277d refactor!: remove the publish script and the v6 shim skills 2026-09-05 01:43:01 -06:00
Alex Verkhovsky 05175bd569 refactor!: rip out the classic installer, the packager, and bmad-help 2026-09-05 01:43:00 -06:00
Alex Verkhovsky 5349ac0823 fix(publish): preserve SECURITY.md in the artifact repo 2026-09-05 01:43:00 -06:00
Alex Verkhovsky 430501edb9 feat(setup): leave classic-installer files alone and report them in doctor 2026-09-05 01:43:00 -06:00
Alex Verkhovsky e5d115646e feat(installer): refuse to run in npx-managed projects 2026-09-05 01:43:00 -06:00
Alex Verkhovsky 4d562582c7 test(setup): cover doctor repair of a symlinked legacy scripts dir 2026-09-05 01:43:00 -06:00
Alex Verkhovsky 6cc7317588 fix(installer): never ship the bmad skill or module manifests 2026-09-05 01:43:00 -06:00
Alex Verkhovsky b284c68665 fix(core): stop treating the module as a catalog to complete
Core skills are independent tools, not a set to finish. Help no longer
reports uninstalled skills as missing, and the packager no longer
requires every skill id in the manifest body.
2026-09-05 01:43:00 -06:00
Alex Verkhovsky fe71ce0edb fix(setup): create module scripts dirs so first doctor reports current 2026-09-05 01:43:00 -06:00
Alex Verkhovsky 2553fb6e09 refactor(skills): drop user name, language, and skill-level config
The model already knows who it is talking to and what language fits the
conversation; answers frozen at install time only mislead. Setup asks no
questions of its own now — the only questions come from installed module
manifests. user_name, communication_language, user_skill_level, and
document_output_language leave the config templates, setup.py, the setup
reference, and every live skill's prose. Classic-installer surface
(module.yaml, tools/installer, v6-shims, bmad-help) is unchanged; the
test suite keeps negative assertions that the keys stay out of team
config.
2026-09-05 01:43:00 -06:00