19 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 9347a524e6 feat(skills): move npx setup payload to bmad
Add the canonical bmad entrypoint, exclude bmad-help from flattened
output, and retain transitional CSV packaging. Move the setup tests,
allow the canonical root ID in validation, and normalize the existing
install-only custom path for strict reference checks.
2026-09-05 01:43:00 -06:00
Alex Verkhovsky e13bbde315 docs(skill-validator): align rule catalog with current repo state (#2815)
The catalog had drifted from the code it describes. Corrections, each
verified against src/ and src/scripts/:

- REF-01 cited a `config.yaml` config source. The central config is
  `_bmad/config.toml` plus its user/custom overlays (config_utils.py).
- REF-01's double-curly exception was stated for all `{{...}}`, which
  contradicted TPL-01. The two forms differ: plain `{{name}}` is an
  artifact placeholder that survives rendering, while dotted `{{.key}}`
  and `{{config.key}}` are compile-time substitutions consumed by
  render_skill.py. Split the exception by form.
- PATH-05 told authors to replace cross-skill file paths with
  `skill:skill-name`, while REF-03 forbade that prefix. Prose uses
  invoke language; `skill:` is the customize.toml value form. Recorded
  the split as a REF-03 exception.
- WF-03 governed workflow.md frontmatter variables. Neither of the two
  workflow.md files carries frontmatter, and no WF-01/WF-02 exist.
  Removed.
- SKILL-04's stated regex rejected the bare name `bmad`, which
  validate_skills.py accepts. Matched it to the implementation.
- Replaced dead example paths (`core/data`, `bmm/data`,
  `core/workflows`) and `{installed_path}` examples already covered by
  PATH-02.

Drop STEP-02 and STEP-03: step goal sections and next-step references
are structure, and the validator no longer takes a position on it.
STEP-04 and STEP-05 stay, being execution safety rather than shape.

Add a Token Forms table and a Skill Layouts section so the token
grammar and the three coexisting step layouts are stated once, and
extend REF-01 to cover `{workflow.key}`, `{agent.key}`, and
`[[bmad-snapshot:]]`. Compile-time tokens are predicated on the skill
actually invoking render_skill.py, which only bmad-build and
bmad-build-auto do.

Details the catalog now states precisely: render_skill.py substitutes
`{workflow.key}` but not `{agent.key}`, whose only source is
resolve_customization.py output; a `[[bmad-snapshot:]]` target must be
a Markdown file other than SKILL.md, which _load_sources excludes;
workflow.md is the renderer's entry point, not a property of any
layout; config keys are declared in module.yaml, which exists in a
checkout, rather than the installed config.toml, which does not; and
`{project-root}` and `{skill-root}` are named as sources so REF-01
does not flag the two most common tokens in the corpus. SKILL-04
claims no character limit, since NAME_REGEX does not bound length and
a passing deterministic rule is skipped by the inference pass.

Drop the Skill Spec Cheatsheet. Its path-resolution notes duplicated
PATH-01 and the rest (loading levels, 500-line tip, discovery
keywords) was read on every run and used by no rule; the intro now
links the specification instead. The How to Use steps no longer
restate the first-pass skip rule, and backslash-escaped backticks
inside code spans are replaced with double-backtick spans so they
render.

Verified across all 50 skills: every `{workflow.*}` and `{agent.*}`
resolves in its own customize.toml, every snapshot target exists, and
no unrendered skill uses a compile-time token.
2026-09-01 21:03:27 -06:00
Alex Verkhovsky 68ea5b8e17 refactor(tools): port the deterministic skill validator to Python (#2810)
Replaces tools/validate-skills.js with tools/validate_skills.py, taken from the
flat-tree work on feat/npx-skills-distribution rather than written afresh, so
the two do not diverge again. Discovery is repointed from that branch's flat
skills/ tree to src/. Behaviour is otherwise unchanged: same rule IDs, same
JSON shape, same --strict and --json flags, and the tests come across as
unittest cases run through uv, matching how the other Python tests are wired.

The three step-structure rules go away with it. STEP-01 (filename format),
STEP-06 (step frontmatter) and STEP-07 (step count) all key off a literal
steps/ directory that only two of fifty skills have — everywhere else step
files sit at the skill root — so they validated almost nothing. The catalog's
first-pass list drops from 13 rules to 10 to match, and their rule sections
are removed.

CI is unaffected: quality.yaml already provisions uv and invokes the npm
script rather than the file.
2026-09-01 07:58:02 -06: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
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
Alex Verkhovsky 4f1894908c refactor: tighten SKILL-04 regex, broaden WF-01/WF-02, remove forbidden names
- SKILL-04: require bmad- prefix, enforce single dashes via regex
  ^bmad-[a-z0-9]+(-[a-z0-9]+)*$, drop FORBIDDEN_NAME_SUBSTRINGS
- WF-01/WF-02: check all .md files (not just workflow.md) for stray
  name/description frontmatter, with tech-writer exception
- Update skill-validator.md prompt to match all rule changes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 08:02:01 -06:00
Alex Verkhovsky 5a1f356e2c feat(tools): add deterministic skill validator for CI
Add tools/validate-skills.js — a Node CLI that checks 13 deterministic
rules (SKILL-01–06, WF-01–02, PATH-02, STEP-01/06/07, SEQ-02) across
all skill directories. Runs in under a second, exits non-zero on HIGH+
findings in strict mode, and outputs JSON for the inference validator.

- Add validate:skills npm script to quality chain
- Update skill-validator.md with first-pass integration instructions
- Update AGENTS.md push gate documentation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:49:01 -06:00
Alex Verkhovsky 6dc9ce0090 chore(tools): remove Claude Code-specific sections from skill cheatsheet
Keep cheatsheet focused on the Agent Skills open standard only.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 18:30:39 -06:00
Alex Verkhovsky 07f1a44c5c chore(tools): align Augment config with skill-validator as single source of truth
Replace duplicated workflow-era rules in .augment/code_review_guidelines.yaml
with a single reference to tools/skill-validator.md. Append the skill spec
cheatsheet to the validator with a link to the Agent Skills specification.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 17:41:54 -06:00
Alex Verkhovsky cb16a4fac2 fix(skills): strip redundant [workflow.md](workflow.md) links repo-wide
Replace `[workflow.md](workflow.md)` with bare `workflow.md` in all 34
SKILL.md files. Redundant markdown link syntax adds noise for LLM
consumers. Also update the validator example to match.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 11:24:57 -06:00
Alex Verkhovsky 098c96740c fix(skills): validation pass 2 — fix path, variable, and sequence issues across 32 files
Run skill-validator against all 36 skills on HEAD (42b1d0f6). Fixes:

- PATH-01: relative path corrections in product-brief-preview, brainstorming,
  distillator, generate-project-context, edit-prd, quick-dev-new-preview
- PATH-04: remove 5 intra-skill path variables from edit-prd
- REF-01: single-curly template vars → double-curly in create-architecture,
  create-epics-and-stories, create-story
- REF-02: fix dangling file refs in advanced-elicitation, validate-prd, edit-prd
- REF-03: update rule to prefer natural language `Invoke the skill` form;
  fix stale persona ref in qa-generate-e2e-tests
- SEQ-01: "skip to" → "proceed to" in quick-dev-new-preview
- SEQ-02: remove time estimates from document-project, quick-spec
- SKILL-06: add "Use when" trigger to review-edge-case-hunter
- STEP numbering: renumber step n="0.5" to integer sequence in retrospective

Also updates REF-03 rule in tools/skill-validator.md to clarify that
natural language invocation is canonical — no skill: prefix required.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 10:38:43 -06:00
Alex Verkhovsky e794a81ee2 feat(tools): add REF-03 skill invocation language rule to validator
Skills must be invoked with "invoke" language, not file-oriented verbs
like "read fully and follow", "execute", "run", or "load". These imply
document-level operations and are incorrect for skill references.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 06:40:10 -06:00
Alex Verkhovsky 02cfaf64a4 feat(tools): add PATH-05 skill encapsulation rule to validator
Add PATH-05: no file path references into another skill directory.
Skills are encapsulated — external consumers must use skill:name syntax,
not reach into internal files. Also tighten WF-03 to cross-reference
PATH-05 so vague "legitimate external path" no longer permits
cross-skill file paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 02:26:01 -06:00
Alex Verkhovsky f4084ea199 feat(tools): add SKILL-05 name-matches-dir and REF-01 variable-defined rules
SKILL-05 checks that SKILL.md name matches the directory name.
REF-01 checks that every {variable} traces to frontmatter, config,
or runtime — exempts {{double-curly}} template placeholders.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 15:49:10 -06:00
Alex Verkhovsky 6ff29d4707 feat(tools): add inference-based skill validator
LLM-readable validation prompt covering 19 rules across 6 categories:
SKILL.md frontmatter, workflow.md hygiene, path resolution, step file
structure, sequential execution, and file reference integrity. Designed
to catch anti-patterns from mechanical workflow-to-skill conversions
(installed_path abuse, intra-skill path variables, metadata in wrong
frontmatter).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 15:18:55 -06:00