Refresh interviews shrink to one recall question — what changed since the
last run. Cross-file contradictions are flagged only when they change
behavior; rewording and overlap are not contradictions.
Compose now asks, per accepted candidate, whether a hook, lint rule, or
CI check enforces it better than a guide line; the line is the fallback
and a landed check deletes it.
Five adoptions from the generator prior-art survey: prohibitions name
their permitted alternative; an emphasis-marker budget; a
git-log --diff-filter=DR drift check on refresh; TODO placeholders over
guessed greenfield commands; commit and branch conventions mined from
history.
The skill never commits — its output stays as working-tree changes for
the user. Headless runs never rewrite a guide the memlog doesn't record
writing; they leave an AGENTS.md.proposed for an interactive merge.
The run record is now a standard memlog kept with the shared
memlog.py script — append-only typed entries, latest entry wins —
replacing the bespoke ledger format; stale-disposition notes become
structurally impossible. Two appeal-to-measurement assertions cut:
the operative admission and exclusion rules carry that load.
The AGENTS-dev.md hop is the most common progressive-discovery trigger,
so it is now gated on the first hands-on action rather than session
self-classification, names its payoff, and names the exemption. The
contract's worked example shows the two-file form with the pointer in
situ. Scoped-guide discovery no longer assumes harness nearest-file
loading: the root-guide pointer is the mechanism.
A maintainer-named frequent session kind (UX, manual testing, data
work) may earn its own AGENTS-<kind>.md behind a pointer; module-level
differences stay with scoped guides.
Where-things-are pointers serve planning sessions as much as coding
ones, so they belong in the always-loaded file. Shape rules now require
every line to state an action (bare facts only as justification clauses)
and stable contract headings across runs.
Round-3 trial findings: an unsourced pitfall entered the guide at
composition time because coverage only checked ledger-to-guide; and
repeat-fix git history, the strongest pitfall evidence observed, was
not an explicitly admitted source.
Revisions from two end-to-end trials plus review:
- Replace the global non-derivable test with per-section admission rules:
brevity (orientation), authority (policy), universal need verified by
execution (commands, verification), wrong-default-assumption (conventions),
localization value (pointers), observed failure only (pitfalls)
- Two-tier output: AGENTS.md (orientation + policy + pointer) for every
session, AGENTS-dev.md for coding sessions; single file when tiny
- Pitfalls can never be nominated by scans: sources are recorded lessons,
maintainer recall, session evidence, and the writing session's own caught
mistakes; retirement only when the guarded thing is gone or the human says
so, since a working rule erases its own evidence
- Interview ergonomics: recall questions, never review lists; testimony the
repo contradicts is surfaced with evidence, never written or dropped
- Trial-driven fixes: guide-to-filesystem link check, mutating-command
go-ahead as the interview's first question, plain-English rewrite
throughout
Replace the kernel+bundle context system with a single product: a short
verified agent guide (AGENTS.md). A field trial of the first version showed
repo scanning produces polished-but-useless factoids; the rewrite fills a
fixed section plan from ranked evidence channels (executable config and CI,
targeted git history, session logs, human interview) and uses the repository
only to verify claims, never as the source of knowledge.
- Intents: bootstrap, refresh, record (capture an observed agent mistake),
audit; query is gone with the bundle
- Per-fact entry files, trust frontmatter, index, placement machinery, and
the skill's context.py mechanics script are removed; accountability moves
to one plain ledger file recording every candidate claim and its
disposition
- Skill directory only; docs, forwarding husks, and shared scripts untouched
* fix(installer): submit the path shown and retire WDS from the picker
Directory prompt
The installation-directory prompt was a clack AutocompletePrompt whose
render() drew only the text line. The candidate list existed but was never
shown, and Enter returns the focused option rather than the typed text.
Focus was sticky: it only reset when the previously focused value left the
list, so a subdirectory selected while narrowing survived deleting back to
the parent. Typing /path/to/workspace could install to
/path/to/workspace/some-child with no sign of it on screen.
Rebuilt on TextPrompt so the input line is the value:
- the candidate list is visible, windowed, with an active-row marker
- arrow keys and Tab write the highlighted candidate onto the input line
- the list is frozen against the last typed text while browsing, so arrows
walk siblings instead of descending (this also unsticks Tab cycling)
- index -1 is the typed text, so backing out of the list restores it
- Tab completes to real directories only, skipping "Create/use:" entries
- directory() takes optional input/output streams so it is testable
Module registry
- WDS is marked deprecated: hidden from the picker unless already
installed, shown with a notice when it is, never removed and still
resolvable from its source so existing installs keep updating
- deprecation notices now reach the CLI paths (--modules, --yes) and
quick-update, which never render the picker's option hints
- picker order is now bmm, bmb, cis, tea, bmad-loop, gds
- the core row is hidden; it was a locked always-on checkbox. core is
still added to the result, and the picker no longer requires a
selection so a core-only install stays possible
* fix(installer): replace the whole line when browsing directories
_clearUserInput() sends readline ctrl+u, which deletes only what is left
of the cursor, and _setUserInput() inserts at the cursor. Browsing after
an arrow-key edit therefore left the surviving tail appended to the
selected candidate: typing a path, pressing left three times, then down
twice submitted ".../workspaceace" instead of ".../workspace/alpha".
validateDirectorySync accepts that path when its parent exists, so the
install went somewhere the user never typed - the same silent-divergence
class this prompt was rebuilt to prevent.
replaceLine() now moves to end of line (ctrl+e) before clearing. This
also fixes the pre-existing instance of the bug on Tab.
Alongside it:
- shift+tab steps back through completions instead of acting as tab
- the "... N more" counter counts only entries below the window, not
every off-window entry, which overstated it once scrolled
- an empty line resolves the default through expandHome/path.resolve,
and seeds the candidate list from the same place, so the list always
describes what Enter would submit
- selectAllModules JSDoc no longer claims core is excluded
- test escape sequences are written as escapes rather than raw bytes,
and the keystroke driver has wider timing margins for CI
* refactor(installer): make the directory prompt a plain text entry
The candidate list, key hints and completion cycling were noise for the
common case: people run the installer from the directory they want to
install into, or one under it. Enter on an empty line already accepts
that, so the list mostly served to push the actual question off screen.
Removed the list rendering, the hint line, arrow/Tab browsing and the
helpers that fed them (listDirectoryOptions, directoryWindow and the
directory-probing utilities). What remains is a clack TextPrompt with a
placeholder showing the default.
The original defect stays fixed by construction rather than by
bookkeeping: TextPrompt's value is the text on the input line, so there
is no hidden selection that Enter could submit instead. Net effect on
prompts.js versus main is -66 lines.
* docs(installer): shorten module descriptions in the picker
The hint beside a highlighted module ran long enough to wrap, which made
the list harder to scan than the module names alone. Each description is
now a single short phrase:
- bmm Agile AI driven development
- bmb Skill, workflow, and agent builder
- cis Brainstorming, ideation, and creative problem solving
- tea Enterprise testing BMM add-on
- loop Builds, verifies, and retros a whole epic unattended
- gds Ideate, design, and build games in any framework
TEA is the only module that depends on BMM, and its description now says
so. The others no longer imply it. "Loop" means nothing to a new user, so
that description leads with what the module does rather than its name,
and gds no longer enumerates engines.
* feat(installer): pre-fill the directory prompt with the current directory
The default was shown as dim placeholder text, so choosing anything near
it meant typing the whole path by hand. It is now the real starting value
on the input line: press Enter to take it, append to install one level
down, or backspace to move up. Clearing the line and pressing Enter still
accepts the default, and the placeholder remains for that case.
* docs: reposition on Agile Ai Driven Development
The tagline was absent from the installer and the README, and the slot
under the wordmark where a tagline belongs was carrying the company line
instead. AiDD is the category BMad Method operates in; the agile part is
what BMad adds to it.
Installer:
- the banner reads tagline, then positioning, then company credit, in
descending weight
- bmm and cis picker descriptions match, with cis short enough that its
row no longer wraps and shifts the list as you arrow onto it
README:
- the opening states the phrase, defines AiDD on first use, and drops the
rhetorical "heard BMad means heavyweight process?" framing while
keeping what it was defending
- greenfield lean corrected: the opening now states the range, "add BMad
to an existing codebase" is a CTA above the fold rather than a link at
line 57, and a bullet names working from verified context on inherited
code. Everything above the fold previously scaled by change size and
nothing by codebase maturity, so a brownfield reader had no answer.
- the module table matches the installer descriptions, uses full module
names instead of letter codes, and adds BMad Loop, which was missing
* docs: carry the module descriptions into the translated READMEs
Game Dev Studio was the last picker row wide enough to wrap an 80-column
terminal, which shifts the list as you arrow onto it. The engine list
stays in the README tables, where there is room for it.
The Chinese and Vietnamese READMEs have their own structure rather than
being a translation of the current English one, so this only touches the
two parts that had gone stale against the installer: the opening
positioning line and the module table. Both tables now match the English
one - installer descriptions, full module names instead of letter codes,
and BMad Loop, which none of the three had.
The translated prose needs a native reviewer before release.
The page is no longer needed. Drop it and its localized copies (cs,
fr, vi-vn, zh-cn), and de-link the remaining references in
forge-idea.md and the zh-cn advanced-elicitation/build pages. Drop a
stale line from lens-adversarial.md left over from the prompt slim.
Also drop a renderer test assertion that could never fail: it checked
that a deleted file wasn't in the snapshot, but the file no longer
exists anywhere in src/, so nothing could put it there.
* Add bmad-project-context skill; husk document-project and generate-project-context
- New bmad-project-context: one engine, three intents (ingest/query/audit)
building a verified kernel + bundle context system; interactive default,
auto/headless mode; works with a BMad install or standalone via bootstrap
- context.py core runtime script (validate/index/map/sweep/resolve/compass/
sync/bootstrap/config) with 52 tests; config resolution delegates to the
installed BMad resolver so script and session never disagree
- bmad-document-project and bmad-generate-project-context reduced to
10-line deprecation shims forwarding to the new skill
- Docs updated: project-context explanation/how-to rewritten, established
projects guide + FAQ, agents references, workflow map; deprecation notes
kept for old-name searches
- module-help.csv single PC row; analyst menu DP -> PC
- validate-file-refs: context.yaml is runtime-generated
* refactor: remove map command from context.py — discovery is the model's job
Real-repo testing showed map's descriptor pass grinding through large
asset trees. Discovery is judgment work the model does better with its
own tools; the script keeps only measurement, mutation, and resolution
(validate/index/sweep/resolve/compass/sync/bootstrap/config). SKILL.md
brownfield flow de-prescribed to outcome-driven wording; added a
bounding-question rule for huge external sources.
* feat: closing message when the harness may not load AGENTS.md
43+ harnesses make per-harness load verification impractical. Whenever
AGENTS.md carries the kernel, the run now closes by telling the user:
if your harness doesn't auto-load AGENTS.md, make the context file it
does load pull this one in (e.g. a CLAUDE.md containing @AGENTS.md).
Found in real-repo testing: the kernel sat unloaded under Claude Code
until a CLAUDE.md pointer was hand-made.
* docs: add The Theory of Project Context explanation
Why the skill captures so little: the evidence against generated docs,
the pruning test and what earns a place, the deliberate exclusions with
their reasons, context-as-liability, and an honest comparison with the
two replaced skills.
* fix: address PR review findings
- Force-add eval fixture files the repo gitignore silently dropped
(pnpm-lock.yaml, _bmad/context.yaml, context/.memlog.md)
- docs/reference/agents.md Analyst row: DP/Document Project -> PC/Project Context
- context.py: cmd_index no longer crashes on an empty index.md (and
allows overwriting one); inline # comments in frontmatter values are
only stripped when preceded by whitespace (C#-style values survive);
cache_lookup tolerates corrupt pointer files; pointer writes are atomic
- triggers.json: positive trigger for the query intent
* refactor(review): slim adversarial hunter prompt across build and review skills
Drop cynical-persona framing. Inline a short review prompt (≥10 findings,
look for missing, empty/zero guards) into blind-hunter layer instructions for
bmad-build, bmad-build-auto, and bmad-code-review. Delete the old
review-prompts/adversarial.md files. Align offline no-subagent dump with the
same child prompt. Update bmad-review's adversarial lens to the same method
while keeping its canonical finding fields.
* test(renderer): stop requiring deleted adversarial.md prompt file
Blind hunter is inlined; assert the inlined prompt text and remaining
file-backed review prompts instead.
* docs: align adversarial review explanation with slim hunter prompt
Document the finding floor and missing-not-only-wrong method instead of
the old cynical persona. Update core-tools lens table and localized pages.
`--set core.<key>` was applied only as a post-install TOML patch, but core
values are dependency-bearing: module artifact paths are built from
output_folder during config collection, the output directory is created
from those paths, and each module's config.yaml snapshots the core values
at generate time. A patch that lands after all of that leaves the sources
disagreeing.
`--set core.output_folder=generated` produced output_folder: generated in
core config, BMM paths under _bmad-output, and a _bmad-output/ directory
on disk. `--set core.project_name=Foo` left BMM's copy on the default.
The docs present --set core.<key> and the legacy shortcuts as equivalent
and label --set the preferred form, so both were reachable by following
the documented advice.
Seed core config from setOverrides.core alongside the legacy shortcut
flags, so every core key takes effect during collection rather than only
the four that have a dedicated flag. Non-core overrides keep the existing
post-install patch path.
The field recorded a commit id inside a file that had to be committed,
so Finalize took a second commit carrying nothing but one frontmatter
line. Nothing read the field.
Finalize now sets status: done before the run's commit and includes the
spec in it, then verifies the working copy is clean. A story's range end
is the next story's baseline in stories.yaml list order.
* refactor(bmm): move sprint-planning and sprint-status to plan/
They sit at the plan/ship boundary and their outputs are planning
artifacts of the dev cycle; next commit makes sprint-planning the
readiness gate, which is plan-side work.
* refactor(bmm): fold readiness gate into sprint-planning, retire check-implementation-readiness
The old skill was 1,154 lines of legacy numbered-step ceremony whose
document discovery hardcoded filename globs (*prd*, *ux*, *epic*) that
miss what current skills produce (SPEC.md, DESIGN.md) and still treated
retired sharded docs as first-class. Sprint-planning now opens with a
lean readiness gate: generic artifact discovery by content, forward/back
traceability, PASS/CONCERNS/FAIL, stop on FAIL with findings. The IR
trigger on John's and Winston's menus dispatches sprint-planning, so
'check implementation readiness' still works everywhere it used to.
* refactor(bmm): modernize sprint-planning with deterministic script core
SKILL.md drops the legacy XML step dialect for the product-brief style
(~100 lines, uv run, headless contract). New scripts/sprint_plan.py owns
the mechanical work — epic parsing, key derivation, ordering, preserve-
never-downgrade merge, story-file detection, action_items carry-over,
atomic writes, drift checks — with 11 tests wired in as
test:sprint-planning. Judgment stays with the LLM: epic discovery, the
readiness gate, and reconciling script-reported orphans and unparsed
headings. checklist.md retired (the script performs that checklist);
sprint-status-template.yaml is the single source for the status
vocabulary. Output stays byte-compatible with build's sprint sync and
retrospective's tooling.
* refactor(bmm): fold sprint-status into sprint-planning's status view
sprint_plan.py gains a status subcommand: counts (legacy values mapped),
risk flags, open action items, and a priority-ordered next-action
recommendation — the old skill's inference-driven summary, computed
deterministically and covered by 9 new tests. bmad-sprint-status becomes
a v6-shims husk that forwards with status-view intent and a deprecation
notice; its dead data/validate modes had zero callers and are gone. If
a hand-edited status file defeats the script, the skill falls back to
reading it directly and summarizing by best judgment. New explanation
page docs/explanation/sprint-planning.md covers the consolidated skill;
workflow maps and references updated across all languages.
* docs: changelog entries for skill reorg and sprint consolidation
* fix(bmm): harden sprint_plan.py per review; add validate/fix intents with full progressive disclosure
Review fixes (PR #2659 findings, bot + internal review):
- Normalize legacy v6 statuses (drafted/contexted) on every read — merged by
meaning and reported, never treated as illegal or reset
- dropped_orphans carry their old status; transplant renames via --set
- project_key/tracking_system/story_location preserved from the existing file
unless overridden; refresh round-trips custom keys and user comments
- Hardened write path: dump-to-bytes, fsync, permission-preserving atomic
write inside the guarded block, explicit checks (no asserts), atomic restore
- JSON-only argparse (errors and -h emit JSON); unicode-aware slugs with hash
fallback; fenced code blocks ignored when parsing epics
- Odd retro keys, date-typed stamps, and non-mapping YAML report cleanly
instead of crashing; unparseable timestamps warn instead of silently
disabling the staleness check; malformed action items flagged, not dropped
- Dead check subcommand removed; generate --dry-run reports drift/in_sync
- test:sprint-planning wired into quality and CI (was test-only)
- Retro tests use a vendored template fixture (PATH-05); repo-level
test-template-sync.js keeps it byte-identical to the source; template
example timestamps and story_location fixed; header block pinned to the
template by test
New capability:
- validate subcommand + reference: structural validation, never writes
- fix flow: evidence-gathering subagents -> user-confirmed state table ->
generate --fresh --set writes a pristine file (the one path allowed to
downgrade); universal script-failure fallback to inference for every intent
- SKILL.md is now a lean router: gate, tracking, status, fix, and validate
each load as progressive-disclosure references
Docs: explanation page gains Repair section; workflow-map and getting-started
across all five languages mention the status view; headless payload nests
under 'report' to avoid the status key collision; changelog updated.
Test suite grows 20 -> 37; retro suite 91/91; docs build and validators green.
* docs: mention repair in sprint-planning explanation description
Step 1 opened with a whole-change stop ("If the change is non-behavioral,
stop here and output the clean result") and then, three paragraphs later,
told the reviewer to screen each part separately. The two framings
contradicted each other, and the clean-result instruction sat before the
second skip rule was even introduced.
Reorder so the step reads in the order it is executed: screen per part,
skip non-behavioral parts, skip parts with no deterministic outcome, then
output the clean result if every part was skipped. The wording of the
individual rules is unchanged, as are the non-behavioral examples.
This is a clarity change, not a behavior fix. A 12-run A/B against the
previous version — four diff shapes, including one built specifically to
trigger early termination (a non-behavioral rename leading the diff,
followed by a behavioral change with a real gap) — found no difference in
either direction. Reviewers already screened per part regardless of what
the opening sentence said, and the genuine gaps were reported in every
arm. Cost was within noise at +2.3% tokens.
Applied identically to all three copies of the prompt.
The verification-gap prompt reliably pushed implementers to write tests
that grep source files for strings. Those tests pin wording, break on
rewording, and verify nothing.
The reviewer was right to treat a prompt as the executable artifact —
editing it does change behavior. The mistake was what followed: having
classified it as code, the reviewer reached the "a test counts only if
an assertion observes the changed output" rule and demanded an
assertion, and the only assertion reachable against prose is a match on
the file's own wording. The "Removed verification" finding category then
flagged deleting such a test as a regression, making it self-reinforcing.
Documentation was never affected; the failure was specific to prompts.
Three changes: list source-text assertions among the checks that do not
count, exempt their removal from "Removed verification", and have Step 1
screen each part of the change on its own so parts with no deterministic
outcome are skipped while the rest is reviewed normally. The screen is
per-part rather than whole-change, so a diff touching both a prompt and
a script still reports gaps for the script.
Applied identically to all three copies of the prompt.
* refactor(bmm): move agent skills into agents/
* refactor(bmm): collapse phase folders into planning/ and shipping/
Skills reorganize from numbered pipeline folders (1-analysis,
2-plan-workflows, 3-solutioning, 4-implementation) into two sets:
planning/ and shipping/. Path and phase-label references updated
across marketplace.json, module-help.csv, tests, and bmad-help;
also trues up two marketplace paths that were stale on main
(create-story/dev-story already lived in v6-shims).
* refactor(bmm): shorten skill folders to plan/ and ship/
* refactor(bmm): retire tech-writer agent (Paige on hiatus)
Paige's capabilities were generic LLM defaults with no domain substance;
her one real menu item (DP) dispatches bmad-document-project, which stays
directly invocable and remains on the Analyst menu. Added to removals.txt
so installs clean up, and docs (all languages) carry a hiatus notice —
she returns in the future far more capable.
* feat(bmm): rework bmad-retrospective as an evidence-based epic review
Replace the persona-meeting simulation with an evidence engine that mines
what a completed epic actually left behind — spec, full diff, per-story
commits, sprint status, and session logs — instead of simulating a team
that "remembers." Every finding carries a source reference.
- Five-phase flow: Gather -> Analyze -> Decide -> Close. Analyze derives
aggregate views (architecture delta, duplication, god-class growth,
pattern divergence, spec reconciliation) and reuses bmad-review for the
diff-scope code lenses rather than reimplementing them.
- Acceptance verdict (accepted / accepted-with-open-items / rejected); a
failing epic can never close as silently accepted.
- Team discussion is now opt-in and off by default, delegating to
bmad-party-mode seeded with the real findings.
- Add deterministic scripts: sprint_status.py (epic detection plus a
comment-preserving, force-quoting, validate-and-restore sprint-status.yaml
update) and git_evidence.py (range / commit / size-trajectory
measurement), with a pytest suite.
- The retrospective document is the working artifact: built early, filled
per phase, and resumable. Adds a headless mode (-H) with assumption
capture.
- SKILL.md drops from ~1527 lines to a lean spine plus five references.
* fix(bmm): harden retrospective scripts for orchestrator use
Address review feedback on the evidence-based retrospective (PR #2612) from
CodeRabbit and the bmad-loop maintainer. All changes are additive — no existing
JSON field or CLI argument that a consumer reads is renamed or removed.
- detect-epic: STORY_RE now matches split-story keys (2-6a-...), aligning with
bmad-loop's sprint-status detection; previously such an epic was invisible and
a headless run could retro the wrong epic.
- sprint_status/git_evidence: argparse failures now emit JSON on the documented
stdout contract instead of plain usage text.
- sprint_status: guard non-list action_items (clean JSON error, no traceback);
_restore reports success/failure so a failed rollback is surfaced, not hidden.
- action_items entries carry a stable id and a ref to the retro document, so an
orchestrator can dedupe across re-runs and dispatch each sourced finding.
- update echoes the acceptance verdict in its JSON; the retro key value stays
"done" for existing lifecycle consumers. Retro doc gains machine-readable
frontmatter, and -H <epic> is documented as the stable automation interface.
- evidence-gathering: derived range now includes the first story commit
(<first>^..<last>); aggregate-views drops the size/acceleration overclaim.
- Tests: split-story detection, non-list guard, restore reporting, argparse
JSON, and id/ref/verdict coverage (13 pass).
* docs(bmm): refine retrospective party-mode phrasing
* docs(bmm): document the reworked retrospective
- Add docs/explanation/retrospective.md — a short feature page: what the
skill does, why to run it after an epic, and what to do with its output
(retro document, action items, acceptance verdict).
- Update the workflow-map retrospective row to reflect the evidence-based
review and its actual outputs instead of "Lessons learned."
* fix(bmm): validate git_evidence --range as a strict revision range
An unvalidated --range reached the git argv unchanged: a value starting
with "-" was consumed by git as an option, a single rev logged all
history up to it, an existing path was consumed as a pathspec, and a
file named like a range (a..b) was silently logged as one — each
returning a confident, wrong evidence set with exit 0. Reject anything
that is not an explicit REV..REV form — including empty endpoints
("..", "a..", "..b"), which git silently defaults to HEAD, and
unstripped values — and terminate the git argv with "--" so a
range-shaped name is always parsed as revisions, never as a pathspec.
Drop the root-commit special case from evidence-gathering.md: its
wording steered into a bare-rev invocation now rejected, the scenario
(an epic starting at the repository's first commit) is vanishingly
rare, and an agent that ever meets it can still construct a shape-valid
range itself. Document the exit-code split (2 invalid args, 1 git
failure). Every rejected mode is covered by regression tests; git
error-string assertions are pinned to LC_ALL=C.
* fix(bmm): harden sprint_status.py input validation and atomic writes
Nine findings from the PR #2612 review of the reworked retrospective, all
reproduced against the previous behavior:
- Pin the emitter indentation so a round-trip stops de-indenting
pre-existing, untouched action_items; the sprint-status template now
survives an update byte-identical apart from last_updated.
- Keep malformed input on the documented JSON-to-stdout contract instead
of a traceback: shape-check the root document and development_status on
both subcommands, widen the file open from FileNotFoundError to
OSError, and report invalid UTF-8 as a JSON error. A non-mapping
development_status previously reported ok:true while doing nothing.
- Validate comment preservation against the whole file's comment lines
rather than only the leading block matched by substring, so a lost
mid-file comment fails the write and restores.
- Write atomically through a temp file, fsync and os.replace, resolving
symlinks and carrying the target's mode across. The rollback goes
through the same path: a truncating rewrite that died halfway used to
destroy the bytes it was restoring.
- Stop inserting an empty development_status mapping, and report
retro_key_found: null when --set-retro-done was not passed, reserving
true/false for "flag passed, key present/absent".
- Include restored:true on every update failure that precedes the write.
- Make _slugify Unicode-aware with a content-hash fallback, so non-Latin
action text no longer collapses to the literal "item".
- Reject an --add-action item whose action is empty or not a string.
- Validate --date against MM-DD-YYYY HH:MM and normalize it, since
strptime otherwise admits unpadded spellings.
Each fix is pinned by a subprocess-level regression test; the suite goes
from 18 to 49 tests.
* feat(bmm): add action-item status updates to sprint_status.py
The update subcommand could only append, and retro-document.md forbids
hand-editing sprint-status.yaml, so nothing anywhere could move an action
item off open. bmad-sprint-status renders every open and in-progress item
on every call, so retrospectives accumulated permanently-open noise.
Add --set-action-status, taking a JSON array of transitions for items
already in the file. Each entry selects one item by id, or by epic plus
exact action text for legacy entries written before ids existed, and gives
it one of open, in-progress, done. Selectors resolve against action_items
as loaded and strictly before the --add-action append, so an item added in
the same run is not addressable in that run. Validation is all-or-nothing
and entirely pre-write: a selector matching nothing, matching more than
one item, colliding with another entry, or carrying a status outside the
vocabulary aborts the whole invocation with restored: true and the file
byte-identical. After the write the file is re-parsed and every targeted
item is confirmed to carry its new status. Success reports the new
action_items_updated count.
Rewrite the contradicting paragraph in retro-document.md so the flag is
the one sanctioned path to change a status: offer the transitions when
the Phase 4 follow-through has evidence an item landed, apply only what
the user confirmed, and never touch prior statuses in a headless run.
* fix(bmm): measure renames, merges, and binary churn in git_evidence
Five ways the measurement was quietly wrong:
- Renames emitted an unopenable "src/{a => b}" pseudo-path and split one
file's churn across up to three keys; non-ASCII paths arrived octal
escaped. Both passes now run with core.quotePath=false and
--no-renames, so a rename is an honest delete + add and a path is a
real string that opens.
- Merge commits emit no numstat rows, so cross-story conflict-resolution
churn vanished with nothing saying it had been skipped. The listing
pass keeps full topology (per-story attribution is unchanged); a
second pass measures merges alone under -m --first-parent
--min-parents=2 and reports merge_files, merge_count and
merges_measured. Merge churn is never folded into files: a merge's
first-parent diff restates the churn of the commits it merged in.
- A commit naming two stories attributed to whichever id was passed
first. Every matching id is now collected, so a seam commit counts for
both stories. commits[].story becomes commits[].stories.
- A git failure with empty stderr reported "error": "". It now falls
back to the exit code.
- One binary revision of a path nulled its added/deleted/net, dropping
real measured text churn from the ranking. The text sums survive and
binary_revisions reports the exposure beside them.
log.diffMerges is pinned to separate on the command line, because a user
config of off makes the merge pass emit no rows at all. Git output is
decoded with surrogateescape rather than replace, so two distinct
non-UTF-8 paths cannot collapse into one key.
evidence-gathering.md documents the changed output. 19 subprocess-level
tests over real git fixture repos cover every case above; the suite goes
81 -> 100.
* feat(bmm): add a pending-stories gate and align the retrospective docs
`detect-epic` now also reports `pending_stories` — the selected epic's
story keys that are not `done`, scoped to that epic alone — and SKILL.md
branches on it before Phase 1: interactively the user is shown the list
and may decline, headless the run proceeds and records the list as an
assumption. An epic supplied on the invocation skips detection, so the
instructions say plainly that the check did not run rather than implying
it did.
Both scripts are built with `add_help=False`. `-h`/`--help` previously
printed argparse's usage text on stdout and exited 0, breaking the
JSON-only stdout contract the scripts sell to their machine consumer;
help is now an ordinary unrecognized argument routed through the
existing JSON error path. SKILL.md also gained the branch for a
`detect-epic` that exits non-zero, which is the normal path for a
stories-mode project with no sprint-status.yaml.
The references are brought back into agreement with what the scripts do
after the last three batches: the close-out invocation quotes its values
and pins the `--date` format that now hard-fails a non-conforming value;
the result JSON documents `retro_key_found: null` and which failures
carry `restored`; the retro key is stated to read `done` even for a
rejected epic, so a verdict-aware gate must read the document
frontmatter; Phase 3 gains an inline fallback when bmad-party-mode is
absent; Phase 4 specifies the previous-retro follow-through record the
close-out consumes; and the god-class view is rewritten for the current
git_evidence keys.
Suite goes from 100 to 111 tests.
* chore(bmm): align retrospective script conventions and test harness
Adopt the invocation convention the quick-dev and dev-auto skills settled
on, and make the git_evidence test fixtures independent of the machine
they run on.
All five documented invocations become `uv run --no-cache`: the shared
cache may be unwritable in a sandbox and may serve a stale build. Both
scripts drop their shebangs entirely — they are only ever launched via
`uv run`, so a shebang and executable bit are a false affordance; the
PEP 723 blocks stay, since that is what uv reads. The encoding audit
that change implies found one implicit site left: `_load_yaml` now pins
the ruamel emitter's encoding, which is what encodes the bytes
`_dump_bytes` writes to the user's file.
`_git` and `_git_unchecked` passed an env of only the four GIT_* identity
vars, so PATH and HOME were wiped and git resolved through os.defpath —
the fixtures ran a different binary than the script under test, and
failed outright wherever git lives only in /opt/homebrew, /usr/local or
a nix store. Both now share a `_git_env` that inherits the environment,
strips ambient GIT_* vars that would redirect or reconfigure the fixture,
and pins identity, both gitconfig sources, gitattributes and the locale.
`_run` parsed stdout bare, so a crash surfaced as JSONDecodeError with
the real traceback hidden in the discarded stderr; it now routes through
the `_json` guard the rest of the file already used. Both test files gain
the repo's established runner footer and the PEP 723 header that makes it
self-bootstrap under `uv run <file>`.
No test's assertions change; the suite holds at 111 passing, and passes
under a gitconfig setting commit.gpgsign, core.autocrlf, core.hooksPath
and init.defaultBranch against it.
* feat(bmm): aim detect-epic at a supplied epic and reject unfinished ones
Unattended retros need the unfinished-story gate on the orchestrator path
and a hard machine verdict when delivery is incomplete.
detect-epic gains optional --epic N so -H <epic> can request the same
pending_stories list auto-detect already returns for its picked epic.
Non-positive values fail as JSON (exit 1). The skill now always runs
detect-epic for a supplied epic with that flag, and the acceptance
rubric forces rejected when pending_stories is non-empty — headless
included; interactive humans may still override.
Suite 111 → 115.
* fix(bmm): harden retrospective script contracts after re-review
- reject three-dot --range values in git_evidence.py: A...B passed the
guard and silently measured a symmetric difference
- move the directory fsync in _atomic_write past the failure path so a
post-rename fsync error can no longer report "restored": true about a
write that landed
- validate --verdict against the frontmatter vocabulary and spell
accepted-with-open-items one way across every machine-read surface
- emit story_count from detect-epic so a typo'd epic number is
distinguishable from a finished epic, and teach the SKILL gate to
treat 0 as suspect
- align the dev agent's ER menu description with the reworked skill
* fix(bmm): reject typed retrospective statuses
* docs: fix retrospective sidebar order
* ci(bmm): run retrospective Python tests
* fix(bmm): harden retrospective script execution
Reject non-positive epic numbers before update processing.
Keep explicit repositories authoritative when invoked from Git hooks.
* docs(bmm): rewrite retrospective skill prose in plain language
Remove invented metaphor and jargon from the skill's prompt surface
(SKILL.md and references): witnesses/interrogates, testimony, seams,
close-out, mining, and similar phrasing are replaced with plain
equivalents. Rename Phase 5 "Close" to "Finalize" and the "Honest
degradation" section to "Missing evidence", syncing cross-references.
Industry-standard terms (god-class, churn) and BMAD vocabulary
(declared/profiled, party mode) are kept. No operational rule,
script contract, or verdict vocabulary changes.
* docs(bmm): refine retrospective prose
---------
Co-authored-by: Alex Verkhovsky <alexey.verkhovsky@gmail.com>
* fix(code-review): make no-spec mode an explicit supported path
Replace ambiguous "If yes / If no" language in step-01 spec-context
selection. Honor explicit no-spec declarations without asking, keep
known specs on full mode, and otherwise offer path vs continue-without.
* fix(code-review): clear spec_file when entering no-spec mode
Keep frontmatter consistent when an explicit no-spec declaration
overrides a Tier 1/2 path so later steps do not treat a stale path
as intentional.
* fix(review): dispatch reviewers by prompt file
* fix(review): load review content from parent message only
Align phase-four reviewer prompt files with file-dispatch: drop the
{review_content} fill-in slot and take the review target exclusively
from the calling prompt.
* fix(review): keep no-subagent fallback prompts self-contained
When subagents are unavailable, write full instruction body plus
REVIEW TARGET under implementation_artifacts, not a path-only pointer.
* fix(review): keep layer recipes plain multi-line prompts
Drop blockquote wrapping so diffs stay intact, leave parent policy in
the review step, and keep customize instructions as the layer recipe
(default subagent prompt or a custom bash/LLM override).
Rewrite published documentation and maintained translations around variable
planning depth with one Phase 4 implementation loop. Update diagrams and AI
indexes, and reject obsolete workflow terminology in deployable output.
* feat(bmm): promote quick-dev to the official Phase 4 loop
- module-help.csv: bmad-quick-dev becomes the required Phase 4 item
(sprint-planning -> quick-dev -> code-review); the deprecated
create-story/dev-story rows leave the catalog; code-review and
qa-generate-e2e-tests chain after quick-dev.
- Dev agent menu drops its DS/CS entries.
- Docs and skill recommendations point at bmad-quick-dev instead of the
legacy split (architecture, ux, sprint-status, sprint-planning,
retrospective, named-agents, project-context,
expand-bmad-for-your-org, commands, workflow-map, getting-started).
The legacy skills themselves are untouched; deprecating them in place
is a follow-up PR.
- Quick-dev's user-facing descriptions (commands, workflow-map,
getting-started, help catalog, dev menu) drop the interactive-session
phrasing ("canonical implementation loop") for plain documentation
wording.
- bmad-retrospective: story-record scan also matches
spec-{epic}-{story}-*.md and quick-dev's section names, so retros see
quick-dev output.
- bmad-quick-dev: preserve an existing baseline_commit on resumed runs
instead of overwriting it with current HEAD.
* fix(bmm): address quick-dev review findings
Record deferred review findings only in spec frontmatter and remove the
deferred-work output. Make updates safe for legacy specs and YAML-special
content, strengthen contract coverage, and synchronize the reference docs.
Render complete dev-auto workflows into root-scoped immutable snapshots
using shared declarative rendering and strict TOML configuration layers.
Keep generated render state out of installer module discovery and custom
file preservation, preserve quick-dev behavior, and provide deterministic
Python version failures for standalone resolver use.
Walk back two bits of overprompting from #2629:
- The `implementation_handoff` guardrail block was premature mitigation to
speculative failure modes (don't commit, don't revert unrelated changes,
don't edit the spec). Collapse the default to what it should have always
been: read the spec fully, load its `context:`, implement, report back.
The key stays customizable — that seam exists to run implementation on a
different model or an external tool via bash — only the default shrinks.
- Revert the Code Map spec-template enrichment. Granular entries were always
permitted; step-02 already instructs planning to populate the Code Map, so
the template comment/example nudge was redundant and half-relegitimized a
root cause (#2629) that the natural experiment had already disproved.
Both skills' handoffs are now identical again.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
quick-dev's step-03 handed the spec to a coding subagent with loose prose,
so the main session improvised a fat dispatch prompt each run — re-narrating
the spec and re-expanding investigation detail at instruction weight. The
review layers were already nailed down in customize.toml; the coding subagent
was not. Give it the same treatment dev-auto got in #2561:
- Add a customize.toml `implementation_handoff` whose prompt is just "read the
spec fully and implement it" plus guardrails and a report-back format.
- Rewrite step-03 to inject that handoff verbatim and forbid parent-authored
goal restatements, file lists, investigation detail, or house-style rules.
- Route investigation into the spec Code Map at planning time (step-02) and
enrich the Code Map template guidance, so the thin handoff points at a rich
spec instead of the dispatch prompt backfilling it.
Apply the same step-02 and Code Map template changes to dev-auto for parity.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(bmm): consolidate research trio into bmad-deep-recon
Replace bmad-market-research, bmad-domain-research, and bmad-technical-research
(5,136 lines of near-duplicate legacy step files) with one modern skill,
bmad-deep-recon (~650 lines):
- Research-master-orchestrator persona; conclusions never rest on training
data alone; lead-following rounds with coverage/novelty-exhaustion stops
- Six type packs as ~25-line policy+craft cards (market, domain, technical,
competitive, user-voice, academic-lit) + select decision shape layering a
weighted-matrix method over any type
- Three acquisition modes: Generate (subagent fan-out), Delegate (engine
registry: CLI/MCP, engine-first strategy), Import (provenance-tracked)
- Claims-ledger verification (normal/high/max) with independence rules and
optional red-team pass; cited synthesis with staleness map
- Effort presets (quick/standard/deep) over four knobs (subagents,
sources/round, depth, validation); precedence request > knob > preset
- Plan gate with surface discovery (MCPs/CLIs/engines), routing table, and
time estimate; use_workflows and subagent_models config
- Create/Refresh/Deepen intents, memlog run-folder workspace, headless JSON
- v6 shims forward the three old IDs with type pre-set; analyst menu,
catalog, marketplace, docs and translation mirrors updated
* feat(bmm): runtime output_format for bmad-deep-recon (v7 artifact protocol)
Replace the output_formats array with output_format = auto|html|md|both
(default auto): interactive runs render the HTML briefing, headless or
skill-invoked runs present the canonical markdown only. research.md always
exists in the workspace as the machine-readable report; the briefing is its
regenerable face. First instance of the v7 artifact protocol (memlog = truth,
md = distillation under contract, html = face).
* feat(core): move bmad-deep-recon to core-skills; address review findings
Move: research is not code-project-specific — home it in core-skills
(brainstorming precedent) so CIS and core-only installs get it. Skill ID
unchanged; standalone marketplace plugin added; catalogs moved to Core;
{planning_artifacts} falls back to {output_folder} on core-only installs.
v6 shims stay in bmm-skills (the legacy trio were bmm skills).
Review fixes (CodeRabbit):
- Engine briefs are now file-based: invoke templates substitute
{brief_file} (a skill-generated path), never inline brief text — quotes
and shell metacharacters in researched content can't shape a command.
- Refresh/Deepen preserve verification statuses for out-of-scope claims.
- HTML briefing: http(s)-only source links, escape source-derived text.
- user-voice pack: redact usernames/handles/emails from verbatim quotes;
communities complement surveys (triangulate) rather than beat them.
- engine.md: explicit single-writer rule — digests return to the lead,
which alone writes research.md in plan order.
* feat(core): deep-recon v2 — draft/process/run, faster defaults, research firewall
Rework after first real-run feedback (slow, token-heavy, locally biased
report, end-pass verification degraded quality, digests stranded in
subagent contexts):
- Three modes replace the acquisition-mode machinery: Draft (build a
deep-research prompt the user runs in their own subscribed tool),
Process (file a finished report into imports/, extract to digests/,
distill research.md summary + metadata so downstream never reprocesses),
Run (native fan-out, first-class). Bare research asks get the choice up
front with the trade stated honestly.
- Engine/Delegate registry cut: the Draft->Process round-trip is the
integration with dedicated deep-research tools; engine.md -> run.md.
- Files-first: digests hit {doc_workspace}/digests/ on landing, sections
commit per dimension, synthesis reads files never conversation memory,
dead runs resume from disk.
- Research firewall: persistent_facts default now empty, assistants get
only their brief, project context frames questions but is inadmissible
as evidence.
- Verification at landing, not end-of-run: normal = spot-check
load-bearing claims only; red_team default off; heavy passes behind
high/max. Presets rescaled faster (standard 3 subagents/8 sources/
depth 2).
- Multi-agent research lessons folded into run.md and the plan gate:
decomposition topology (breadth/depth/straightforward), per-assistant
tool-call budgets, query craft with OODA pause, shared source-quality
card, stop-and-write valve, mechanical citation check at finalize.
- Ripple: v6 shims, catalogs, marketplace, docs one-liners (all five
languages), template gains source: provenance field.
* feat(core): deep-recon quality pass — carve SKILL.md, recon_kit scripts, single-source verification
- SKILL.md 3989→2091 tokens: Draft/Process/Refresh+Deepen/Finalize carved to
references/{draft,process,lifecycle,finalize}.md; Run effort knobs + plan
gate moved into run.md; Overview and pack prose trimmed
- verification.md: red-team pass is the single adversarial mechanism (max
runs it at full breadth — no double-spawn); level semantics single-sourced
- scripts/recon_kit.py + tests: citations cross-check, memlog claim tally
(ref=/status= convention, last wins), staleness date math from per-class
windows, deterministic run-folder slugs, escaped source-appendix HTML
- Draft wired with preferred/banned source policies and an open-floor opening
- external_sources examples (Tavily/Sonar/xAI X-Search MCPs); source-quality
card: answer engines are aggregators — chase their citations
* docs: Deep Recon explanation page + integration
- new docs/explanation/deep-recon.md: three modes, mode-choice guidance,
research types, native-run internals diagram, firewall/verification, refresh
- analysis-phase.md research section rewritten for bmad-deep-recon
- core-tools.md: deep-recon in thinking-skills table, full catalog entry,
migration note for the merged market/domain/technical trio
- workflow-map.md + getting-started.md link the new page
- vi-vn developer guide: last stale old-skill flow mention updated