Description
On a project running BMad Method 6.10.1-next.34, bmad-loop validate fails and bmad-loop run aborts before spawning any session. bmm renamed the dev primitive bmad-dev-auto → bmad-build-auto and left bmad-dev-auto behind as a deprecation shim (a lone SKILL.md that forwards). bmad-loop 0.9.0 still targets the old name and content-probes it for marker files that now live under the new name.
There is no way to configure around it, and every released tag predates the rename, so the loop is unrunnable on current bmm.
Steps to reproduce
- Install bmm 6.10.1-next.34 in a project (
npx bmad-method install), with the claude skill tree.
uv tool install "bmad-loop[tui] @ git+https://github.com/bmad-code-org/bmad-loop.git" (resolves to main @ 5c86f98, version 0.9.0).
bmad-loop init --project . --cli claude — succeeds; hooks, skills, policy all fine.
bmad-loop validate --project .
Expected behavior
Preflight recognises the project's dev primitive and passes, so run can start. bmm ships a complete dev primitive here — it is simply called bmad-build-auto, and both marker files bmad-loop demands are present in it.
Actual behavior
FAIL: .claude/skills/bmad-dev-auto is incomplete (missing step-04-review.md, customize.toml) — reinstall it from the bmm module
Every other check passes (config, policy, sprint-status, git, tmux, process host, claude found, hooks registered). The suggested remediation cannot fix it: reinstalling bmm re-renders the same shim, by design.
Critically, this is not validate-only. missing_base_skills returns severity problem; _require_base_skills (cli.py:494) maps that to False, which gates run at cli.py:912, plus cli.py:1144 and cli.py:1199. The run aborts before any session spawns.
Analysis
bmm 6.10.1 moved the primitive and shimmed the old name. From the project's _bmad/_config/skill-manifest.csv:
"bmad-build-auto","bmad-build-auto","One iteration of an unattended development loop. Use when invoked by name.","bmm","_bmad/bmm/4-implementation/bmad-build-auto/SKILL.md"
"bmad-dev-auto","bmad-dev-auto","Deprecated: forwards to bmad-build-auto. Do not use unless invoked by name.","bmm","_bmad/bmm/v6-shims/bmad-dev-auto/SKILL.md"
Note the source path on the second row: bmm/v6-shims/. On disk:
.claude/skills/bmad-dev-auto/ -> SKILL.md only (the forwarding shim)
.claude/skills/bmad-build-auto/ -> SKILL.md, customize.toml, workflow.md, spec-template.md,
compile-epic-context.md, step-01-clarify-and-route.md,
step-02-plan.md, step-03-implement.md, step-04-review.md,
references/, review-prompts/
The old name is hardcoded in five places:
| Location |
Code |
Effect |
install.py:107 |
DEV_PRIMITIVE_SKILL = "bmad-dev-auto" |
missing_base_skills probes the shim dir |
install.py:84 |
DEV_BASE_SKILLS = {"bmad-dev-auto": ("step-04-review.md", "customize.toml"), …} |
markers absent from the shim → problem finding |
install.py:350 |
STORIES_PROBE_SKILL = "bmad-dev-auto" |
stories mode's folder+id probe reads bmad-dev-auto/step-01-clarify-and-route.md — also only in bmad-build-auto now, so stories mode hits the same wall |
policy.py:41,861 |
DEV_SKILLS = {"bmad-dev-auto"}; raise PolicyError otherwise |
dev.skill cannot be repointed |
engine.py:1996, runsetup.py:83 |
policy.dev.skill == "bmad-dev-auto" |
selects GenericDevAdapter result synthesis |
Why there's no workaround
- Config can't repoint it.
dev.skill = "bmad-build-auto" raises PolicyError at policy.py:861. Even if the allowlist were widened by hand, engine.py:1996 / runsetup.py:83 compare against the literal "bmad-dev-auto" to decide whether the adapter synthesizes a result.json — so a bare allowlist change would silently disable result synthesis rather than fix anything.
- No escape hatch. No
--skip-preflight / --force on run; the only related env var is BMAD_LOOP_SKIP_REVIEW (engine.py:2765), which is unrelated.
- No older tag helps. Every tag from
v0.7.5 through v0.9.0 predates the bmm rename, so they all target bmad-dev-auto too.
Why relaxing the marker check alone is not sufficient
Dispatch is by skill name (/bmad-dev-auto <story key>, cli.py:997-998, cli.py:1043), so with the preflight merely satisfied the dev pass would land on the shim and reach the real primitive only through LLM-mediated forwarding. Two consequences:
- A deadlock seam in an unattended session. The shim's migration path instructs the session to "HALT and do not invoke any skill" if approval to rename a legacy
_bmad/custom/bmad-dev-auto.toml / .user.toml is "declined or unavailable". An automated bmad-loop session has no human to approve, so any project carrying a legacy customize file under the old name would hang instead of running. (Not my case — I have no such file — but it is a live hazard for anyone who customized bmad-dev-auto.)
- Customization keys off the directory name.
_bmad/custom/*.toml overrides are keyed by skill directory, so overrides for the primitive now belong to bmad-build-auto. A tool dispatching bmad-dev-auto and a project customizing bmad-build-auto disagree about which file is authoritative.
Targeting bmad-build-auto directly avoids both.
Suggested fix
Resolve the dev primitive by preference rather than by constant: use bmad-build-auto when its skill dir exists, else fall back to bmad-dev-auto — resolved per skill tree, since a project can have a post-rename .claude tree and a pre-rename .agents one side by side (the same reasoning missing_base_skills already applies to review-layer derivation). The resolved name then needs to flow through all five sites above: the marker probe, the stories probe, the dev.skill allowlist and its default, the GenericDevAdapter selection predicate, and the dispatch strings.
Secondary observation (possibly its own issue): bmm's bmad-build-auto/customize.toml now makes each [[workflow.review_layers]] self-contained — the layers read {skill-root}/review-prompts/{adversarial,edge-case-hunter,verification-gap}.md and explicitly instruct "Do not invoke any skill". So resolve_review_layers' derivation of required review skills from the primitive's config finds nothing to require, and missing_base_skills falls back to the static catalog (bmad-review-adversarial-general, bmad-review-edge-case-hunter, satisfied by a present bmad-review). It resolved cleanly for me, but the machinery is aimed at a skill shape upstream has moved past, and the fallback is doing the real work.
Which area is this for?
Orchestrator / control loop
bmad-loop Version
0.9.0, installed from main @ 5c86f98c7b13ce55947a2bd59d5c8d7861c57d9c (== git ls-remote HEAD at time of filing). Installed via uv tool install "bmad-loop[tui] @ git+…", Python 3.14.
BMad Method (bmm): 6.10.1-next.34 (_bmad/_config/manifest.yaml).
Which coding CLI are you using?
claude — all three roles (adapter dev=claude, review=claude, triage=claude), skill tree .claude/skills/. Sprint mode ([stories] source = "sprint-status").
Operating System
macOS (darwin 24.6.0), tmux 3.7b.
Relevant log output
$ bmad-loop validate --project .
FAIL: .claude/skills/bmad-dev-auto is incomplete (missing step-04-review.md, customize.toml) — reinstall it from the bmm module
ok: BMAD config OK: artifacts at <project>/_bmad-output/implementation-artifacts
ok: policy OK: gates=per-epic, adapter dev=claude, review=claude, triage=claude
ok: sprint-status OK: 63 stories, 32 actionable
ok: git worktree clean
ok: multiplexer TmuxMultiplexer available (tmux 3.7b)
ok: mux backends: tmux* (available, tmux 3.7b), psmux (unavailable)
ok: process host: PosixProcessHost
ok: claude found
ok: bmad-loop hooks registered for claude
Description
On a project running BMad Method 6.10.1-next.34,
bmad-loop validatefails andbmad-loop runaborts before spawning any session. bmm renamed the dev primitivebmad-dev-auto→bmad-build-autoand leftbmad-dev-autobehind as a deprecation shim (a loneSKILL.mdthat forwards). bmad-loop 0.9.0 still targets the old name and content-probes it for marker files that now live under the new name.There is no way to configure around it, and every released tag predates the rename, so the loop is unrunnable on current bmm.
Steps to reproduce
npx bmad-method install), with theclaudeskill tree.uv tool install "bmad-loop[tui] @ git+https://github.com/bmad-code-org/bmad-loop.git"(resolves tomain@5c86f98, version 0.9.0).bmad-loop init --project . --cli claude— succeeds; hooks, skills, policy all fine.bmad-loop validate --project .Expected behavior
Preflight recognises the project's dev primitive and passes, so
runcan start. bmm ships a complete dev primitive here — it is simply calledbmad-build-auto, and both marker files bmad-loop demands are present in it.Actual behavior
Every other check passes (config, policy, sprint-status, git, tmux, process host,
claudefound, hooks registered). The suggested remediation cannot fix it: reinstalling bmm re-renders the same shim, by design.Critically, this is not validate-only.
missing_base_skillsreturns severityproblem;_require_base_skills(cli.py:494) maps that toFalse, which gatesrunatcli.py:912, pluscli.py:1144andcli.py:1199. The run aborts before any session spawns.Analysis
bmm 6.10.1 moved the primitive and shimmed the old name. From the project's
_bmad/_config/skill-manifest.csv:Note the source path on the second row:
bmm/v6-shims/. On disk:The old name is hardcoded in five places:
install.py:107DEV_PRIMITIVE_SKILL = "bmad-dev-auto"missing_base_skillsprobes the shim dirinstall.py:84DEV_BASE_SKILLS = {"bmad-dev-auto": ("step-04-review.md", "customize.toml"), …}problemfindinginstall.py:350STORIES_PROBE_SKILL = "bmad-dev-auto"bmad-dev-auto/step-01-clarify-and-route.md— also only inbmad-build-autonow, so stories mode hits the same wallpolicy.py:41,861DEV_SKILLS = {"bmad-dev-auto"};raise PolicyErrorotherwisedev.skillcannot be repointedengine.py:1996,runsetup.py:83policy.dev.skill == "bmad-dev-auto"GenericDevAdapterresult synthesisWhy there's no workaround
dev.skill = "bmad-build-auto"raisesPolicyErroratpolicy.py:861. Even if the allowlist were widened by hand,engine.py:1996/runsetup.py:83compare against the literal"bmad-dev-auto"to decide whether the adapter synthesizes aresult.json— so a bare allowlist change would silently disable result synthesis rather than fix anything.--skip-preflight/--forceonrun; the only related env var isBMAD_LOOP_SKIP_REVIEW(engine.py:2765), which is unrelated.v0.7.5throughv0.9.0predates the bmm rename, so they all targetbmad-dev-autotoo.Why relaxing the marker check alone is not sufficient
Dispatch is by skill name (
/bmad-dev-auto <story key>,cli.py:997-998,cli.py:1043), so with the preflight merely satisfied the dev pass would land on the shim and reach the real primitive only through LLM-mediated forwarding. Two consequences:_bmad/custom/bmad-dev-auto.toml/.user.tomlis "declined or unavailable". An automated bmad-loop session has no human to approve, so any project carrying a legacy customize file under the old name would hang instead of running. (Not my case — I have no such file — but it is a live hazard for anyone who customizedbmad-dev-auto.)_bmad/custom/*.tomloverrides are keyed by skill directory, so overrides for the primitive now belong tobmad-build-auto. A tool dispatchingbmad-dev-autoand a project customizingbmad-build-autodisagree about which file is authoritative.Targeting
bmad-build-autodirectly avoids both.Suggested fix
Resolve the dev primitive by preference rather than by constant: use
bmad-build-autowhen its skill dir exists, else fall back tobmad-dev-auto— resolved per skill tree, since a project can have a post-rename.claudetree and a pre-rename.agentsone side by side (the same reasoningmissing_base_skillsalready applies to review-layer derivation). The resolved name then needs to flow through all five sites above: the marker probe, the stories probe, thedev.skillallowlist and its default, theGenericDevAdapterselection predicate, and the dispatch strings.Secondary observation (possibly its own issue): bmm's
bmad-build-auto/customize.tomlnow makes each[[workflow.review_layers]]self-contained — the layers read{skill-root}/review-prompts/{adversarial,edge-case-hunter,verification-gap}.mdand explicitly instruct "Do not invoke any skill". Soresolve_review_layers' derivation of required review skills from the primitive's config finds nothing to require, andmissing_base_skillsfalls back to the static catalog (bmad-review-adversarial-general,bmad-review-edge-case-hunter, satisfied by a presentbmad-review). It resolved cleanly for me, but the machinery is aimed at a skill shape upstream has moved past, and the fallback is doing the real work.Which area is this for?
Orchestrator / control loop
bmad-loop Version
0.9.0, installed frommain@5c86f98c7b13ce55947a2bd59d5c8d7861c57d9c(==git ls-remote HEADat time of filing). Installed viauv tool install "bmad-loop[tui] @ git+…", Python 3.14.BMad Method (bmm):
6.10.1-next.34(_bmad/_config/manifest.yaml).Which coding CLI are you using?
claude— all three roles (adapter dev=claude, review=claude, triage=claude), skill tree.claude/skills/. Sprint mode ([stories] source = "sprint-status").Operating System
macOS (darwin 24.6.0), tmux 3.7b.
Relevant log output