Component: bmad-sprint-planning — scripts/sprint_plan.py
Version observed: BMad Method v6.11.0
Severity: data loss (generate, fix); unusable (status, validate)
Summary
The skill assumes positional identifiers — Epic 1, Story 1.2, epic-1, 1-2-slug — in four
hardcoded regexes. A project that uses non-positional identifiers cannot use any subcommand, and
two of them rewrite the tracking file rather than failing.
Non-positional keys are a reasonable choice: they mean adding an epic never renumbers another. The
skill has no way to be told about them.
The four patterns
All in sprint_plan.py. None is read from config, environment, or the customization file:
EPIC_KEY_RE = re.compile(r"^epic-(\d+)$") # :55
RETRO_KEY_RE = re.compile(r"^epic-(\d+)-retrospective$") # :56
STORY_KEY_RE = re.compile(r"^(\d+)-(\d+)([a-z]?)-.+") # :57
EPIC_RE = re.compile(r"^#{1,3}\s*Epic\s+(\d+)\s*:?\s*(.*?)\s*#*\s*$", re.IGNORECASE) # :44
Impact, in severity order
generate is destructive on a non-matching epics file. It resolves zero epics and zero
stories and writes an empty development_status, replacing a populated file with nothing. It
does not detect that it parsed nothing from a non-empty input.
fix rebuilds into the positional scheme, discarding the project's identifiers — which are
also the keys shared with the epics file, the test-design handoff's story bindings, and every
story filename on disk.
status reads the same keys, so its counts are silently meaningless rather than absent.
validate is safe but always negative. It reports every key as unrecognized, so it cannot
distinguish "this project uses a different scheme" from "this file is corrupt".
Reproduction
A project whose epics file uses headings like ## CPM-EP-EVIDENCE: An evidence log that cannot lie
and ### CPM-EVIDENCE-S01: Five outcome states with one precedence order, and whose tracking file
uses matching lowercased keys.
$ python sprint_plan.py validate --status-file _bmad-output/implementation-artifacts/sprint-status.yaml
{"ok": true, "action": "validate", "valid": false, "problems": [
"unrecognized key 'epic-platform' (expected epic-N, N-M-slug, or epic-N-retrospective)",
"unrecognized key 'cpm-evidence-s01-five-outcome-states-precedence-order' (...)",
... 62 keys, all of them ...
]}
Running the script's own patterns against that epics file:
epic headings matched: 0
story headings matched: 0
total headings in file: 81
So generate would resolve nothing and emit an empty development_status.
Why it cannot be worked around
customize.toml exposes exactly four keys — activation_steps_prepend, activation_steps_append,
persistent_facts, on_complete. None reaches parsing or validation.
Editing the script works until the next update overwrites it: the customize.toml beside it carries
DO NOT EDIT -- overwritten on every update.
Suggested fixes, cheapest first
- Make
generate refuse when it parses zero epics from a non-empty epics file. One guard, and
it closes the data-loss case regardless of everything else. Parsing nothing out of 81 headings is
a parse failure, not an empty backlog.
- Have
validate distinguish "no key matches any known pattern" — likely a different
identifier scheme — from "some keys are malformed" — likely corruption. The current message reads
as the latter for what is usually the former.
- Expose the patterns in
customize.toml, e.g. a [workflow.identifiers] block carrying the
four regexes, so a project declares its scheme once and every subcommand honours it.
Secondary: the inline dependency assumes uv
sprint_plan.py declares its dependency as PEP 723 inline metadata:
# /// script
# requires-python = ">=3.10"
# dependencies = ["ruamel.yaml>=0.18"]
# ///
Only uv run provisions that automatically. A project standardized on another package manager gets
ModuleNotFoundError: No module named 'ruamel' from the documented invocation, with nothing
indicating the dependency is the problem rather than the script. A line in the skill's instructions
about non-uv environments — install ruamel.yaml into the interpreter you invoke it with — would
save the rediscovery.
Component:
bmad-sprint-planning—scripts/sprint_plan.pyVersion observed: BMad Method v6.11.0
Severity: data loss (
generate,fix); unusable (status,validate)Summary
The skill assumes positional identifiers —
Epic 1,Story 1.2,epic-1,1-2-slug— in fourhardcoded regexes. A project that uses non-positional identifiers cannot use any subcommand, and
two of them rewrite the tracking file rather than failing.
Non-positional keys are a reasonable choice: they mean adding an epic never renumbers another. The
skill has no way to be told about them.
The four patterns
All in
sprint_plan.py. None is read from config, environment, or the customization file:Impact, in severity order
generateis destructive on a non-matching epics file. It resolves zero epics and zerostories and writes an empty
development_status, replacing a populated file with nothing. Itdoes not detect that it parsed nothing from a non-empty input.
fixrebuilds into the positional scheme, discarding the project's identifiers — which arealso the keys shared with the epics file, the test-design handoff's story bindings, and every
story filename on disk.
statusreads the same keys, so its counts are silently meaningless rather than absent.validateis safe but always negative. It reports every key as unrecognized, so it cannotdistinguish "this project uses a different scheme" from "this file is corrupt".
Reproduction
A project whose epics file uses headings like
## CPM-EP-EVIDENCE: An evidence log that cannot lieand
### CPM-EVIDENCE-S01: Five outcome states with one precedence order, and whose tracking fileuses matching lowercased keys.
Running the script's own patterns against that epics file:
So
generatewould resolve nothing and emit an emptydevelopment_status.Why it cannot be worked around
customize.tomlexposes exactly four keys —activation_steps_prepend,activation_steps_append,persistent_facts,on_complete. None reaches parsing or validation.Editing the script works until the next update overwrites it: the
customize.tomlbeside it carriesDO NOT EDIT -- overwritten on every update.Suggested fixes, cheapest first
generaterefuse when it parses zero epics from a non-empty epics file. One guard, andit closes the data-loss case regardless of everything else. Parsing nothing out of 81 headings is
a parse failure, not an empty backlog.
validatedistinguish "no key matches any known pattern" — likely a differentidentifier scheme — from "some keys are malformed" — likely corruption. The current message reads
as the latter for what is usually the former.
customize.toml, e.g. a[workflow.identifiers]block carrying thefour regexes, so a project declares its scheme once and every subcommand honours it.
Secondary: the inline dependency assumes
uvsprint_plan.pydeclares its dependency as PEP 723 inline metadata:Only
uv runprovisions that automatically. A project standardized on another package manager getsModuleNotFoundError: No module named 'ruamel'from the documented invocation, with nothingindicating the dependency is the problem rather than the script. A line in the skill's instructions
about non-
uvenvironments — installruamel.yamlinto the interpreter you invoke it with — wouldsave the rediscovery.