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.
* fix(dev-auto): score follow-up review from patched-finding severity
The old rule asked for a significance judgment of the pass's own
review-driven changes, which recommended another pass nearly every
time and never converged. Replace it with arithmetic over the triage
log, counting only findings triaged patch: recommend a follow-up for
a patched high finding, or when 3 x medium + 1 x low reaches 5.
Deferred and rejected findings never count. The flag stays a plain
boolean suggestion; the orchestrator owns the re-review decision.
Fixes#2576
* feat(dev-auto,quick-dev): route review patches to implementer, re-verify
When the step-03 implementation subagent can be re-engaged with its
context intact, step-04 sends it the patch findings instead of fixing
them in the main session; falls back to fixing directly where the
platform cannot keep a subagent around. Either way, the spec's
verification re-runs after patches land — previously patches applied
after step-03's verification shipped unchecked.
* fix(dev-auto,quick-dev): restate synchronous invocation at spawn sites
The SKILL-level ban on backgrounding subagents loses to harness bias
in long sessions once the preamble ages out of attention. Restate it
where reviewer subagents are launched in step-04, and mark the other
spawn sites (epic-context compile, planning exploration) synchronous.
Fixes#2570
* docs(zh-cn): add missing translations for forge-idea, web-bundles, and dev-auto
Complete the remaining five zh-cn documentation pages on origin/main.
Also fix Starlight sidebar autogenerate config so docs:build passes.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(docs): revert sidebar autogenerate to Starlight 0.40 items format
Starlight 0.40 (Astro 6) requires autogenerate inside items[], not at
group level. The previous fix passed locally with stale deps but failed CI.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: leon <leon.liang@hairobotics.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
* 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>
* 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
The review step said only to "execute all remaining layers in parallel
wherever their execution methods allow", which permits an orchestrator to
spawn one reviewer, react to its output, then spawn the next. Observed in a
run where four reviewers launched ~2m14s apart end to end — pure wall-clock
waste with no quality benefit.
Require every reviewer spawn to be issued contiguously before reading,
waiting on, or reacting to any reviewer output; collection and triage only
begin once all reviewers are launched. No change to reasoning structure or
review discipline.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bmad-spec gains an optional, interactive-only Story Breakdown step that
derives stories.yaml from the memlog: a fixed-name sibling of SPEC.md
listing stories as a simple sequence (list order = execution order),
each with id, title, description, and orchestration fields
spec_checkpoint, done_checkpoint, and invoke_dev_with. Field definitions and validity rules live in
assets/stories-schema.md. Ids are pinned only once a story's spec file
exists; un-started stories may be renumbered on re-derive. stories.yaml
never carries status.
bmad-dev-auto becomes dispatchable per stories.yaml entry: invoked with a
spec folder and story id, it reads only that entry's title and
description, derives the slug, and creates or resumes the story spec at
stories/<id>-<slug>.md just in time. All HALT write-back lands at that
id-keyed path (skeletal spec for pre-planning halts). An
invocation-prompt directive halts ready-for-dev after planning;
re-dispatching the same folder+id resumes via existing status routing.
Planning accumulates context from all prior story records in the
folder. Reference docs updated to cover both halves.
The intent_gap branch reverted code changes before halting, destroying
information: the attempted diff shows the human exactly which reading
the agent implemented, which is concrete evidence for repairing the
intent — and occasionally the guessed reading is simply right.
Save the attempt as a patch file in {implementation_artifacts} before
reverting, reference it from the triage log, and include its path in
the halt output. Restart stays default-clean (blocked keeps discard
semantics; the tree is reverted as before); if the human decides the
attempted reading was correct, git apply + status in-review resumes
review on it instead of paying for a full re-run.
Also unify the blocking-condition vocabulary: 'intent gaps' (step-02)
and 'intent gap in intent contract' (step-04) both become 'intent gap'
— one condition, one meaning; the artifact shows which phase raised it.
Document the artifact, the recovery affordance, and the unified
condition in the integration reference (docs/reference/dev-auto.md).
- step-04 finalize: commit every file in the reviewed diff, tracked and
untracked; verify and amend if any reviewed file is missing. Leftover
porcelain entries are by definition not part of the change: left in
place, never committed/deleted/gitignored, declared as residual
artifacts (the next run's step-01 clean-tree check is the enforcement
point)
- handoff report: the implementation subagent declares any files
changed beyond the spec's tasks and why each was needed; triage and
the human judge the reasons under the intent-authority rule
Observed in a live run: a new test file was left untracked, so the
commit omitted a file the review had approved; the same run expanded
scope beyond the spec (correctly, per the repo's architecture) with no
declaration anywhere.
- customize.toml: add workflow.implementation_handoff — a literal
subagent prompt with {spec_file} substituted at run time; the spec
is the sole source of truth, its change-log entries are binding, and
the report shape (files, verification, blockers, residual risks) is
fixed
- step-03: resolve and follow the handoff verbatim; no parent-authored
goal restatements, file lists, ownership boundaries, or acceptance
criteria; HALT on handoff/spec conflict; the subagent loads the
spec's context: files itself instead of the parent pasting them
- Ready standard: ACs must observe the outermost surface the intent
references, never an internal proxy
- step-02: divergent defensible readings of the intent are an intent
gap; never resolved by picking a reading
- step-03: retire the post-implementation AC/checkbox ritual; run the
spec's Verification commands instead, and leave acceptance judgment
to the independent review panel
- customize.toml: add Intent Alignment Auditor as a fourth default
review layer, fed the verbatim invocation intent plus the diff,
descriptive only; step-04 defines the {verbatim_intent} placeholder
- step-04: out-of-scope dispositions require the intent as authority;
spec scope language, plan, and diff shape are inadmissible
Quick-dev, dev-auto, and code-review hardcoded the same review layers
(Blind Hunter, Edge Case Hunter, Verification Gap Reviewer, plus the
Acceptance Auditor in code-review) in their review steps. Move them into
each skill's customize.toml as [[workflow.review_layers]] defaults —
quick-dev's one-shot route gets its own [[workflow.oneshot_review_layers]].
Each layer is a keyed table (id, name, instruction, optional when) whose
instruction is the complete execution recipe, so the standard keyed merge
lets team/user overrides add layers (e.g. a security auditor), replace a
default's instruction wholesale — including running an external review
tool in a separate process via bash instead of a subagent — or disable
one by overriding its id with an empty instruction. The review steps
resolve the layers through resolve_customization.py (with the usual
manual-merge fallback), skip empty and when-failing layers, and execute
the rest; triage tags findings by layer id instead of the fixed
blind/edge/vgap/auditor labels.
Also cut the code-review SKILL.md description and preamble to their
load-bearing text.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Step-03's Tasks & Acceptance Verification in bmad-dev-auto and
bmad-quick-dev gains a Matrix Test Audit: when the spec's frozen contract
contains an I/O & Edge-Case Matrix, verify every matrix row is covered by
at least one test that verifies its expected behavior, and that each
covering test ran and passed in the verification output. A covering test
that exists but did not run (unregistered, filtered out, skipped,
disabled) counts as missing. Test-vs-matrix disagreements are fixed in
code, never by editing the expectation toward observed behavior.
dev-auto (unattended) HALTs blocked on matrix ambiguity or an
unsatisfiable audit; quick-dev (interactive) halts and asks the human.
The fork from quick-dev rewrote 'Isolate deep exploration in
sub-agents' to 'Use subagents for deep exploration' (682a2005), which
reads as a compliance step: the agent spawns an explorer, then explores
and plans itself without waiting for it. Restore the isolate framing,
scope inline reading to narrow localized tasks, and require planning
from the subagent summaries.
* feat(review): add verification-gap reviewer as a third review layer
Add bmad-review-verification-gap, a code-review layer orthogonal to the adversarial bug-hunter and edge-case hunter. It asks whether a regression in the changed behavior would be caught by a test where that behavior is actually exercised — never whether the code is wrong — and reports verification gaps with no severity (the triage step owns that).
Wire it into the review steps of code-review, quick-dev, and dev-auto, and register it in the plugin marketplace. The code-review triage folds its findings into the unified normalization (source vgap); the triage step's per-layer format enumeration is dropped, since the triage agent sees the actual layer outputs and a description of them adds nothing.
Per external review feedback: absence claims are gated on a repo-wide symbol and import-reference search, and the report's evidence field must show the searches run when it claims no test exists.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs(review): tighten verification-gap reviewer prompt
* docs(review): apply decisions-log refinements to verification-gap reviewer
Fold two decisions from docs/test-gap-hunter/decisions-log.md and follow-up
review into the reviewer prompt:
- Missing-adoption now qualifies on a supersession signal plus a shared
observable contract, not the adoption failure alone; missing coverage of the
non-adoption is the gap itself, not a disqualifier. Step 4 routes it as its
own outcome so it is not collapsed into the regression-style gaps.
- Findings report what was actually checked ("none of the tests I read cover
this") and how far, and claim a test exists nowhere only when the
symbol/import search establishes it. The gap definitions and Consequence stay
conceptual; the how-far-verified qualification lives in the report fields.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* 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.
The prior commit described agent-team mode as "one shared room" where
relaying user turns keeps everyone in sync. Claude Code's Agent Teams
documentation contradicts this: communication is a point-to-point Mailbox
(`SendMessage` to a named recipient, "send one message per recipient" to
reach everyone) with no broadcast. An idle member does not observe exchanges
it isn't addressed in.
So keeping the room in sync is the lead's job, not the channel's. Replace the
"shared room" line in mode-agent-team.md with the point-to-point reality:
relay each user turn to the members who need it, and catch an idle member up
on what it missed before it speaks again.
mode-subagent.md's "One shared room" stays — there the orchestrator is the
sole channel and already routes the whole exchange, matching plain Subagents'
report-back-to-main model.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The dev-auto workflow runs unattended with no event loop to resume a
yielded turn. If a subagent is launched detached/backgrounded (e.g.
run_in_background: true) or the turn ends to await a completion
notification, control is never handed back and the run stalls.
Make the contract explicit: invoke every subagent synchronously and
await it within the same turn. Clarify that 'in parallel' means several
blocking calls awaited together, not detached execution. The only
sanctioned way to end a turn remains the HALT protocol with a terminal
status.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Finalize block explicitly writes `followup_review_recommended` and
(since #2522) `final_revision` to the spec frontmatter, but the terminal
`status` advance lives only in the conflated `SKILL.md` HALT macro
("update status in frontmatter AND append result details"). An agent that
completes the detailed `## Auto Run Result` prose can treat that sentence
as satisfied and skip the terse `status` write, leaving frontmatter at the
template default `draft` on an otherwise-successful run — which breaks
downstream automation that reads frontmatter `status` as the
machine-consumable completion signal. Add the explicit `status: done` write
at Finalize, consistent with how #2522 handles `final_revision`.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A runtime read the opening prompt as a task and, once it was satisfied,
concluded the party was over and closed the spawned agents. Party mode is
principally interactive: the opening intent is a topic, not a stopping point.
- SKILL.md: state the party is interactive and open-ended; it ends only when
the user signals done. Add an explicit `--non-interactive` flag as the one
opt-in path that serves a single intent and then wraps up.
- mode-subagent.md / mode-agent-team.md: add a lifecycle contract — one
standing agent per persona, kept alive for the whole session, visible
roster, resume/respawn if dropped, close only at wrap-up. A member that
finished its task is idle, not done.
- mode-subagent.md: add "One shared room" — every standing member hears the
whole exchange each round, speaking or not, so personas stay in sync and a
history can form. mode-agent-team relays every user turn to all members.
- docs: document the interactivity default and `--non-interactive`.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* 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.
Replace the standalone bmad-review-deletion-contract-auditor layer with a
self-gated deletion check inside the Edge Case Hunter.
- After its edge-case pass, the hunter runs a secondary deletion check on
the same diff it already holds (Step 4) and folds any deletion findings
into a single JSON array, tagged kind: deletion with a confidence.
- Add kind and confidence fields to the hunter output; the existing four
fields are unchanged. Edge cases stay primary; deletion findings are
rare and usually empty.
- step-04-review invokes the hunter once — no deterministic deletion scan,
no agent resume, no fallback divergence. Classify routes deletion
findings through the same triage categories.
- Remove the standalone skill, its module-help.csv row, and its core-tools
entry; tool count back to 12.
Rationale: the hunter already sees the full diff, so a separate detection
pass plus a context-rebilling continuation turn bought nothing; self-gating
in the existing turn is cheaper and simpler. Deletions are rare and rarely
load-bearing, so the check stays secondary to the edge-case pass.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add one bullet to Step 2 (Exhaustive Path Analysis) of
bmad-review-edge-case-hunter for implicit branches: when a diff
special-cases or changes the handling of one or more members of a
fixed set of values (enum, status code, sentinel, type tag,
flag, value range), the rest of the set are implicit branches —
silent branches absent from the diff.
The bullet sits as a peer to the existing "Walk all branching paths"
(explicit branches) and feeds the same shared loop ("For each path:
determine whether the content handles it" -> "Collect only the
unhandled paths"), so it needs no restated action and the output
contract is unchanged. "scan", not "enumerate", lets the model scale
effort to set size instead of flooding on large sets. Count
boundaries (0/1/many, off-by-one) are left to the existing first
bullet.
Catches implicit branches the syntactic walk misses. Measured on a
real regression (!ALL fixed, sibling !BLANK left case-sensitive):
catch rate 50% -> 100% over 10 runs at +19% tokens/run.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Severity now lives in triage, but in the standalone code-review skill the
adjudicator sees only the diff plus subagents' text, so it rates reachability
blind to call sites and guards outside the hunk, and over-rates.
- Add a "read the code before rating" step: open the source at each finding's
location and judge reachability from real call sites, not the diff hunk alone.
- Drop the "prefer the more conservative classification" tie-breaker so genuine
toss-ups force a pick instead of biasing severity upward.
- Remove the now-vacuous "Be precise." rule.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Capture the post-commit HEAD as `final_revision` alongside the existing
`baseline_revision`, so the orchestrator running immediately after a
dev-auto session can derive the session's commit range
(`baseline_revision..final_revision`) without inferring it from git state.
The artifacts directory is gitignored, so the spec frontmatter is the only
link from the out-of-tree spec to the in-tree commits. A single endpoint
suffices: `git log baseline..final` regenerates the commit list on demand,
and equal values mean no commits were made. Degrades to `NO_VCS` when
version control is unavailable.
Also documents both revision fields in docs/reference/dev-auto.md.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Delete the explicit CLAUDE.md / memory file loading instruction from
the implementation skills that still asked the model to fetch host
session context itself.
* 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>
* chore(bmm): retire bmad-investigate skill and its documentation
Removes the bmad-investigate skill, its case-file template, the EN/FR
forensic-investigation explainer docs, and every integration point:
Amelia's `IN` menu entry, the plugin marketplace manifest, module-help,
the workflow-map tables and HTML diagrams, and the agent-trigger tables.
EN/FR explanation sidebar orders are renumbered to close the gap left by
the removed doc.
Rationale: the skill's only non-redundant value was a durable, hand-off
case-file artifact — a workflow that is unproven in practice. Everything
else (evidence grading, hypothesis discipline, causal tracing) is
behavior a capable model already performs without a dedicated skill. The
skill also carried method-internal metaphor ("stronghold", "evidence
perimeter") that leaked into user-facing chat. Upstream signals agreed:
issue #2452 flagged the vocabulary leak and a maintainer noted the skill
should not auto-fire. Added in #2364.
Supersedes the in-flight cleanup in #2478 and resolves#2452 by removal.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(bmm): add bmad-investigate to removals.txt and note retirement
The retirement commit removed the skill source and docs but did not add
the removals.txt entry that triggers cleanup of the skill directory on
existing installs during update. Add it, plus an Unreleased CHANGELOG note.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Invoking the skill on a spec with status `done` now resets
`review_loop_iteration` and routes to step-04 for a fresh review pass,
instead of ingesting the spec as context. This lets an orchestrator
layer follow-up reviews on a completed spec without another skill.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Blind Hunter review subagent was denied project access in dev-auto,
quick-dev, and code-review — limited to the diff, unable to inspect the
surrounding code that determines whether the change is correct. It is blind
to intent (no spec/context), not to the codebase.
Replace the prose reviewer descriptions with bare verbatim prompts that
invoke the named review skill on {diff_output}. Subagents already have
project read access by default, so the explicit prompt is the only control
needed; this also removes the vague "invoke via the skill" phrasing that
invited emulating the review instead of actually invoking it.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(dev-auto): commit completed work at end of successful run
Add a commit line to step-04-review.md's Finalize section: if version
control is available, commit (no push). This completes the VCS bookend with
the existing start-of-run clean-tree check (step-01), making each unattended
iteration atomic so the next one starts clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* chore(dev-auto): trim over-prompting in step-04 Finalize
Tighten the two closing lines: drop the redundant "Before HALT with status
done" ordering (the line already sits right before HALT) and the "do not set
on blocked exits" caveat (blocked exits never reach this line).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* 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.
* fix(quick-dev): tighten ready standard
Add sufficiency and coherence criteria so approval does not mask unresolved gaps, ambiguities, or contradictions in generated specs.
* fix(quick-dev): verify acceptance before review
Make the active session verify both tasks and acceptance criteria before review, and remove the redundant acceptance auditor review layer.
* fix(quick-dev): persist review loop counter
Store the review loop counter in spec frontmatter so loopbacks cannot reset it by re-reading the review step file.
* style(quick-dev): normalize subagent spelling
Use subagent and subagents consistently across Quick Dev step files.
* docs(quick-dev): clarify customization comments
Replace internal merge jargon and stale workflow comments with plain descriptions of the Quick Dev customization file behavior.
* fix(quick-dev): structure deferred work entries
Make Quick Dev append deferred work as source_spec, summary, and evidence entries without modifying existing entries or deduplicating during the run.
* feat: add bmad dev auto skill
* fix: replace dev auto approval gate
* fix: remove dev auto one-shot route
* fix: tighten dev auto review step
* fix: inline dev auto finalization
* fix: clarify dev auto sprint sync
* fix: clarify dev auto epic context output
* fix: structure dev auto deferred work entries
* fix: remove dev auto sprint status coupling
* fix: run dev auto completion hook on blocked exits
* fix: persist dev auto review loop counter
* fix: remove dev auto approval-era intent marker
* fix: simplify dev auto final result handoff
* fix: tighten dev auto workflow contract
* fix: clarify dev auto verification owner
* fix: strengthen dev auto verification gates
Require the auto workflow to re-read its READY standard before judging the spec, and make implementation verification cover both tasks and acceptance criteria with a blocked HALT when missing work cannot be completed.
* fix: tighten dev auto prompt wording
Remove remaining human-interaction atavisms, make subagent wording consistent, and clarify blocked verification handling in the unattended development workflow.
* docs: clarify dev auto customization comments
Replace internal merge jargon and stale workflow comments with plain descriptions of the customization file behavior.
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
* feat(core): add bmad-forge-idea skill
Domain-agnostic idea-forging skill for BMad core. Takes a half-formed idea
and pressure-tests it in conversation until it hardens, proves out, or dies
cheaply — the quality of thinking is the product, not an artifact. One
question at a time with an always-on anti-sycophancy stance; two opt-in gears
(adversarial attack; a persona room resolved from the installed roster,
voiced by default and spawned when a branch needs independent minds); a
memlog as durable, resumable residue. Honest exits (hardened / killed /
clearer); optional brief distilled from the memlog that can feed bmad-spec or
bmad-quick-dev. Interactive and socratic; no headless mode.
Registered in core-skills/module-help.csv (menu code FI).
* Add forge-idea documentation and finalize skill scripts/conventions
Docs (Diátaxis):
- New explanation/forge-idea.md and how-to/pressure-test-an-idea.md
- core-tools.md: catalog entry + item section for bmad-forge-idea
- workflow-map.md and getting-started.md: Phase 1 (Analysis) listing
- De-collide the "forge" verb from bmad-prfaq positioning across docs
Skill:
- forge-idea SKILL.md: add term-sharpening axis, operationalize the
existing-project ground-truth rule, and add graceful degradation
- bmad-prfaq: description de-collision; Stage 1 now redirects upstream
to bmad-forge-idea for an unsound idea
- Unbundle the core memlog.py copy (skill references the core script at
{project-root}/_bmad/scripts); keep skill-local resolve_personas.py + tests
- customize.toml: comment refresh; on_complete as array
* Fix review findings: resolve_personas crash + doc accuracy
- resolve_parties: resolve token once + coerce non-strings (fixes KeyError
on mixed-case members and TypeError on unhashable members)
- Guard malformed party-mode config shapes so discovery stays best-effort
- _brief: pass through model/capabilities; register: no name-lookup hijack
- 5 new regression tests (case-insensitivity, malformed input, rename collision)
- Docs: correct bmad-review-adversarial-general name, bmad-prfaq handoff,
recursive resume glob, broken table row, and Produces filenames across
forge-idea/brainstorming/product-brief/architecture rows
Clears all 11 open Dependabot alerts on main:
- astro 5.18.1 -> 6.4.6, @astrojs/starlight 0.37.5 -> 0.40.0,
@astrojs/sitemap 3.6.0 -> 3.7.3 (8 XSS/SSRF advisories)
- esbuild pinned to 0.28.1 via override (astro/vite cap at ^0.27;
fixes dev-server arbitrary file read on Windows)
- markdown-it -> 14.2.0 via override (smartquotes ReDoS)
- brace-expansion (under glob) -> 5.0.6 (range DoS)
Astro 6 migration for the docs site:
- content config moved to src/content.config.ts with loaders
- sidebar autogenerate groups wrapped in items[] (Starlight v0.39)
- 404 page uses render(entry) instead of entry.render()
Verified: docs:build produces an identical page set vs the
pre-upgrade baseline; sidebar validation and format checks pass.