* feat(method): add bmad-preview-ticketing skill and tickets.py runtime
Ticketing at every altitude: an initiative sliced into epics, an epic
incepted into a Breakdown of stories, spikes, and bugs, and tickets
written, refined, published, and moved on a git-backed store or a tracker
(GitHub, Jira, Linear, Notion, Trello).
- Container tickets are the spec at their altitude: Requirements with
stable ids, Outcome, Done when, Boundaries, Breakdown.
- Thin tickets carry contribution and verification; full criteria are
written when pulled (`refined: false` until approved).
- scripts/tickets.py derives ready, blocked, and to-create views from the
files; scripts/read_toml.py reads the store config; tests beside them.
- Store configs per tracker under config/, templates per type under
assets/, customization surface in customize.toml.
- Listed in the bmad help catalog as a preview alternative to
bmad-create-epics-and-stories plus bmad-sprint-planning.
* fix(method): address review findings in bmad-preview-ticketing
- tickets.py: a dropped blocker still blocks its dependents; mark clears
blocked_at and blocked_reason on a status change and takes the assignee
literally; --project-root finds the store config when tickets live
outside the project; a numeric blocker falls back to the ticket id;
duplicate Breakdown numbers and blockers naming no entry are errors.
- read_toml.py: read local files only.
- board.md: mark is the leaf-level write, a container's status is a file
edit, and a dropped ticket is removed or repointed in its dependents.
- SKILL.md: tickets are drafted under tickets.root; persistent facts load
file: entries.
- gh config: read children with `gh issue view --json subIssues`.
- help catalog: the breakdown includes bugs.
* docs: add a guide to testing v7 previews
A new page under Plan Larger Work for trying proposed v7 planning
changes: setting up an initiative store, configuring where tickets are
tracked, and using bmad-preview-ticketing. It states early that preview
stories are not wired into sprint planning, sprint-status.yaml, or
status updates from bmad-build, and that a story must be refined before
it is built.
- Sidebar entry and a pointer from the stories-and-tracking page.
- Locale coverage baseline records the new English-only page.
The skill is still /bmad-walkthrough. It writes a review narrative and log
under implementation artifacts, then walks the narrative one block at a time.
Hooks are optional; empty ones are omitted. A writer subagent is used only
when the host has subagents.
BREAKING CHANGE: customize.toml no longer uses prepend and append. The
hooks are on_activation, on_block_activation, on_block_complete,
on_complete, and persistent_facts.
Add `workflow.review` (none, quick, thorough, auto; shipped auto) with the
same `quick_lenses` and `thorough_lenses` sets `bmad-build-auto` ships,
replacing `review_layers` and `oneshot_review_layers`. Step-04 renders the
thorough set and step-oneshot the quick set under auto, each renders only
the pinned set otherwise, and `none` drops the lens dispatch and triage.
The oneshot route captures `baseline_commit` and stages a diff so the shared
lens recipes serve both routes. Step-03 now stages the diff and acts on the
implementer's report instead of re-checking tasks and acceptance criteria.
Story frontmatter gains `review`, `review_source`, and `lenses_ran`.
Both skills gain a `workflow.review` selector. bmad-build-auto accepts
`none`, `quick`, `thorough`, and `auto`, where `auto` follows the
resolved route (oneshot selects quick, full selects thorough) and is the
default. bmad-code-review accepts `quick` and `thorough`, defaulting to
`thorough`; a review skill with review turned off has nothing to do, so
it offers no `none`. An invocation naming a selection passes it as
`--set workflow.review=<value>`, and any other value halts the render.
`review_layers` retires in both skills in favour of two configured, ordered
lens sets. `quick_lenses` holds the new Quick lens, an informed review of
acceptance criteria, applicable rules, and bugs that reads the spec, its
context files, and the repository's agent instructions. `thorough_lenses`
holds Blind Hunter, Edge Case Hunter, Verification Gap Reviewer, and Intent
Alignment Auditor, identical in both skills; bmad-code-review's Acceptance
Auditor is removed.
Templates render only the selected set. Under `auto` route with `auto`
review, bmad-build-auto renders both sets and the session launches the one
the fixed mapping selects. Under `none`, bmad-build-auto's step-04 drops
its staging, review, and classify sections. The bmad-build-auto story
frontmatter gains `review`, `review_source`, and `lenses_ran`.
The review docs describe the two review depths and point to
bmad-customize for the rest; the customize doc's example sets the default
depth.
* fix(renderer): halt on persistent override keys the skill does not declare
The renderer validates a customization value only where a template reads
it, so a key in `_bmad/custom/<skill>.toml` or `<skill>.user.toml` that
the shipped customize.toml does not declare was merged and then dropped
without a word. A misspelled key, or one a skill has since retired, left
the user believing their override was in force.
Before merging the layers, walk each persistent file's leaf paths against
the shipped defaults and halt naming the file and the undeclared keys.
The check asks whether a key is declared, not whether this render read
it, so an override of a key that only some rendered variants consume
still passes; the existing invocation-override check keeps its stricter
"used by this render" rule.
* docs(customize): drop the note about undeclared keys halting
The halt names the file and the keys, so the reader learns it the moment
it applies; a sentence about it in the precedence section is detail no
reader needs up front.
Add a `workflow.route` customization (oneshot, full, auto; default auto)
to bmad-build and bmad-build-auto. A route named in the invocation
becomes `--set workflow.route=<value>` on the render command. Templates
render only the pinned route's continuation; auto renders both plus the
selection rule, byte-identical to before apart from reporting. Story
frontmatter gains `route_source` (pinned or auto), and a pinned run
halts when a resumed spec's recorded route differs.
A pinned oneshot run does what it was told, how it was told: the
mid-build stop conditions narrow to an intent gap. Work turning out
larger than expected is the routing call the pin already made, and no
longer stops the run. A hole in the intent still does, because the only
alternative is to guess: bmad-build asks the human, bmad-build-auto
halts blocked with `intent gap`.
Give templates a `halt(message)` function so they can reject values they
cannot act on; each build skill's workflow.md uses it to halt the render
on a route outside oneshot, full, auto instead of silently rendering the
auto path.
* docs(diagrams): let the delivery loop's two slogans carry the accent
Alexey, on the merged version: "I would make both slogans stick out more -
splash of color, bigger font". He is right, and the original backs him up: it
set START ANYWHERE in gold and RIGHT-SIZED in pale blue, both larger than
what replaced them.
Dropping every colour from the diagrams - so one drawing could serve light
and dark - took that with it, and the two lines went grey and small enough to
skip. They are the only sentences in the drawing, and a reader who skips them
gets four boxes and no argument.
Both now take the accent at 22, up from 17.5 and 18, as a matched pair rather
than the mismatched ink-700 / muted-600 they had drifted into. Two colours
are not available to a theme with one accent, so the pairing the original
drew - gold for the entry promise, blue for the summary - collapses into one
hue used twice. The canvas grows 460 to 466 to hold the larger type at the
same 40 units of clearance.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(diagrams): make the slogans banners, and give the pair two hues
The theme already had an answer for what a banner is here. custom.css says
the masthead is "display type, a lead, then a hairline closing the band, the
way every section on the marketing site closes" - so each slogan now closes on
a rule, run across the drawing's own measure, 60 to 1060, so the banners sit
on the boxes' grid rather than floating over it.
Both ends in the same accent read as one statement made twice. They are not:
the top is the invitation, the bottom the summary, and the original said so by
setting them in different colours. `--dg-accent-2` is the site's copper, the
nearest thing this palette holds to that gold, so the pairing survives without
inventing a hue. It needs a dark value of its own - `--bmad-copper` is #8a5a00
and disappears on a dark ground - and #e0b25f is that copper lifted, the value
`--dg-warn` already uses on dark.
The two rules cost height: 466 to 477.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(diagrams): set the banners in the site's label register, and drop copper
Copper is not a palette colour on bmadcode.com. Every use of #8a5a00 there is
a status: `.tag-warn`, the gate's CONCERNS heading, `.road .st`, a flagged row
in the module pane. Putting it on the closing line said "this is a problem"
about the diagram's own conclusion. `--dg-accent-2` is gone.
Reading the live site rather than counting hexes in its stylesheet also
settles what these should be. Its uppercase labels are one register - IBM Plex
Mono, 11px, weight 400, tracking ~0.08em - in exactly two colours: #7c8797
when a label orients, #0f35e0 when it carries weight. No section head on the
site is coloured at all.
So the banners are that register, not the Archivo 700 headings they had
become, and the pair is told apart the way the site tells labels apart: accent
for the opening, which is also what the entry drops below it are drawn in, and
muted for the closing summary. They are set at 16 units rather than the site's
11px because they span the width of a drawing rather than sitting over a
paragraph - 13.3px apparent in a README, against the 9.2px Alexey objected to.
Canvas back to 465 now that the type is smaller.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(diagrams): light the bulbs, and rule the field the original had
Two colour families ran through the original: gold for the inputs - both
bulbs, the three entry drops, the opening line - and cyan for the loop. When
the drops took the accent back, the bulbs were left outside a family they
belong to, so the drawing had a blue arrow leaving an ink bulb.
Both bulbs are lit in the accent now. The cloud stays muted, as it was there
too: it was drawn in the cool colour, not the gold, and a vague notion should
not glow like an idea.
The ruled field returns at the original's pitch, 70 one way and 140 the other,
but held between the two hairlines so it reads as what the banners enclose
rather than running out under them. Drawn in the line token, not the fixed
blue it was, so it survives both ramps - at two opacities, because the dark
line sits further from its ground than the light one and the same value that
is texture on paper becomes structure on black.
No gradient. The docs page gives this drawing no ground of its own, so a
gradient can only live in the README export, and the two would drift apart for
it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Replace the regex token substitution and the line-parsed bmad-if
directives in render_skill.py with Jinja2. Templates see config,
workflow, and snapshot(); undefined names, empty entry files, and
links to omitted sources halt; every value a render reaches and the
Jinja2 version key the generation. Migrate the five rendered skills'
sources to the new forms, keep their shipped output byte-identical,
and update the validator rule and the authoring docs.
* docs: refresh the README banner, restore its diagram, and fix the favicon
Three things the READMEs and the site were carrying wrong.
The banner is the current one from bmadcode.com: the BMad tile and wordmark
over the line art, at 2x for retina. It replaces a 1408x224 crop, and is
smaller on disk than what it replaces.
The delivery-loop diagram in the README has been broken since the diagrams
moved to `docs-site/src/diagrams`. It cannot simply be pointed at the new
path: an authored diagram carries geometry and classes only, so it needs the
site's stylesheet to have any colour at all, and a README loads an SVG as an
`<img>` where no stylesheet can reach it. So `docs/images/` now holds exports
of the source, generated by `npm run export-readme-diagrams` with the dark
ramp substituted in as literal colours. Literals rather than custom
properties because an export has to survive renderers thinner than a browser
- resvg drops `var()` and paints the fallback black. The Korean README's
copy is exported from the same geometry through the existing labels file, so
the two can no longer drift apart.
The favicon was a teal `B` that matched neither the header tile nor
blog.bmadcode.com. It is now the BMad mark, drawn from the same path data
the header already carries, on the same navy the blog uses. The .ico is
generated from the SVG and stays listed for browsers that ignore
`image/svg+xml`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(diagrams): draw the bulbs as bulbs, not as coloured circles
The earlier version leaned on gold to say "idea". Once the diagrams lost
their own colours, a circle over a rounded tab in the body ink read as
neither a bulb nor anything else.
So the glyph now carries its meaning in the drawing: a filament arch inside
the globe, a tapered neck, and a ribbed screw base, plus a third ray
overhead. The small bulb takes the same construction one size down, with a
single rib rather than two, which is all that reads at that scale. Both hold
up on the light and dark ramps.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs: give the delivery loop an English page, at the house type scale
The diagram the README leads with appeared on exactly one page of the site:
the Korean `how-to/choose-a-development-path`, a leftover from before the
English tree was restructured into start/plan/build. An English reader never
saw it.
It now opens "Find Your Starting Point" on the docs index, where it says in a
picture what the list underneath says in prose.
Putting it in a docs column for the first time showed its type was tuned for
a README: drawn at a 1120 viewBox, its labels came out at 11.0px and 8.3px
against the 12.8px and 10.9px the other diagrams hold at the same 736px
content width. The sizes are scaled to match; the geometry is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs-site: guard locale coverage, and give the footer band an edge
Two unrelated things a reader can see, and one they cannot.
The invisible one first. When a locale has no page at a route, Starlight
serves the English one and says nothing, so a missing translation and a
working one look identical from the outside — which is how all five locales
ended up stranded on the pre-restructure tree unnoticed (#2855). Starlight
does mark the substitution: a fallback page carries `lang="en"` on `<main>`
inside a document that declares the locale. The build now checks the built
site for that mismatch, which measures the symptom rather than inferring it
from the sidebar.
The existing backlog is far too large to fix here, so it is recorded in
`locale-coverage-baseline.json` and tolerated. The build fails only when the
picture changes: a route starts falling back, or a baseline entry stops. Both
are one `--update` away. The second failing is deliberate — it is what keeps
the baseline from outliving the problem it records.
The visible one: the footer band sets its own dark ground, which on the dark
ramp is the page's ground, so there was no band — only 297px of unexplained
space where one should have started. It now lifts a step and takes a hairline
in dark mode, and sits flush against the article instead of adding a margin
on top of its own padding. The last-updated line gives up some of its air too;
between them the gap is 234px, and every part of it is now doing something.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs-site: stack the footer columns on mobile, and add the touch icon
The footer's three link groups were laid out in two columns below 32rem, so
one group always dropped onto a row of its own with the space beside it left
empty, and "Plan inside an organization" wrapped inside a 155px column. Three
groups do not fit two columns; on a phone they get one each.
The favicon already matches bmadcode.com exactly - same viewBox, same navy
tile, same three paths, since the mark is the one the header carries. What was
missing is the apple-touch-icon the site also ships, so an icon saved to an iOS
home screen fell back to a screenshot. It is generated from the same SVG,
flattened onto the tile navy because iOS applies its own mask and does not want
the transparency our rounded corners would leave.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(diagrams): raise the delivery loop's type, and give it back a colour
Alex is right about what he saw, and wrong about it being new. His screenshot
is the version before the type was scaled for a docs column, where the title
rendered at 9.2px against GitHub's 16px body. That is already fixed. But the
original diagram this replaced ran 14/16/21 and the fix brought it to
14.5/16.5/19.5 - a hair under where it always was, and his objection would
have applied to the original too. So rather than argue the point, take it
past the original: 17.5/18/21, which puts the node labels at body size and
the title at 14.5px in a README.
The colour is the other half of his complaint's cause. The original said
"here is where each kind of work joins" in gold; when the diagrams lost their
own colours that meaning went with it and nothing replaced it. The three
entry drops now carry the accent, which is the vocabulary's existing job for
an edge the drawing has to single out, so it works on both ramps. The marker
was still called `arrow-gold`; it is `arrow-entry` now.
The README export also gets a ground rather than a flat fill: a near-black
lifting across the diagonal with one soft accent wash behind the row the work
enters from, which is the register bmadcode.com uses - almost all ground and
one blue. The wash sits high on purpose, because centred it pooled behind the
boxes and their flat fill then read as darker than the ground around them.
The docs site keeps a ground that follows the reader's theme, so this belongs
to the export alone.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(diagrams): drop the gradient ground from the README export
It read as an effect rather than a surface. The drawing's colour is the
accent on the three entry drops, and it says more with a flat ground behind
it and nothing competing.
The larger type and the accent stay.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(diagrams): space the delivery loop's two band labels evenly
They were not spaced at all, only placed. The title's baseline fell three
units BELOW the big bulb's top ray - the two only looked separate because
they are far apart horizontally - while the lower band had 35 units of air.
That mismatch is what read as wrong.
Both now sit 40 units clear of the nearest mark. The drawing keeps its size
and shifts down inside a taller canvas, 420 to 460, with the labels lifted
out of its group so the shift leaves them where they are; the remaining
padding above and below the pair is 15 and 16.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
bmad-build-auto gains a oneshot route that plans lightly and implements
in the main session without an implementing subagent. Both build skills
replace their embedded route gate with one customizable instruction,
workflow.route_selection, that users override as a whole; route values
are oneshot and full. Intent gaps and irreversible steps always take the
full route regardless of the rule, and a oneshot run replans to full
when the remaining work is substantially larger than anticipated.
The two spec templates are aligned below the frontmatter, and bmad-build
adds Open Questions only when there are intent gaps.
* fix(docs-site): act on the review findings from #2850
Five findings, all valid, verified against the code rather than taken on
trust.
The label register failed WCAG AA. --sl-color-gray-3 resolved to #7c8797,
which is 3.64:1 on white, and it sets the sidebar group labels, the table
of contents heading, the search shortcut and the footer meta — 11px
uppercase mono, the hardest case in the file. It is #687383 now: 4.81:1,
and still a step lighter than the body's muted ink so the ramp keeps its
shape. Dark was already 6.16:1 and is untouched.
The footer's column headings were <h2> inside <main>, so they joined the
page's heading outline: a reader skimming by heading met "Method" and
"Community" among the article's own sections. Each column is now a nav
labelled by its own visible text.
Diagram.astro substituted labels with a regex that had no g flag and did
not escape the key, so a key used twice in one drawing replaced only its
first occurrence and a key containing regex metacharacters could match
the wrong element. The rehype plugin walks the tree and has neither
problem; this path now escapes and replaces globally.
The diagram cache guard returned early when no diagrams were found, so
deleting the last one left the pages that embedded it rendering from
cache. The empty list now reaches the digest.
The accessible-name guard checked ariaLabelledBy but not ariaLabel, so a
diagram naming itself that way still had its name replaced by the
markdown alt text.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(docs-site): bring the section list back above the fold
The themed sidebar spaced its groups at 1.8rem, which pushed the last
section 132px below the fold at 1440x800 — so a reader could no longer
see what the docs contain without scrolling, which is the sidebar's main
job on first visit.
Group spacing goes to 0.9rem and item rows lose a little padding. The
mono label register keeps enough air to read as a label.
Measured against the sidebar as it was before the theme landed:
1440x800 before 791px, themed 932px, now 788px (fold at 800)
1280x720 before 791px, themed 932px, now 788px (fold at 720)
At 720 the original overflowed by 71px and this now overflows by 68, so
it is no worse than the baseline; at 800 both fit. In every case the
full list of sections sits above the fold with the first two sections
showing their contents.
Reported by Alex Verkhovsky.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(docs-site): stop printing the sidebar script on narrow screens
`.page > .main-frame > *` set `display: flex` on every child of the main
frame. One of those children is Starlight's inline sidebar-persistence
module, and `display: flex` overrides the browser's `display: none` for
a script element — so its source rendered as text on the page.
Only below 72rem, because that is where the rule lives, and only in a
production build, where the module is inlined rather than loaded from a
file. That is why it showed on mobile and never in dev.
The selector names the wrapper div instead. Confirmed at 375px: the
script computes `display: none` again, and the footer still sits at the
bottom of the page, which is what the rule was there for.
Also brings two imported diagrams onto the shared type scale. Apparent
size is nominal size over viewBox width; build-run and walkthrough-run
sit at 0.0149, development-paths was 0.0237 and bmad-delivery-loop
0.0187, so their labels rendered up to 1.6x larger than everything else
on the site. Both are scaled to match; planning-skills was within 12%
and is left alone. Median rendered text is now 10.5px on build-run,
10.5px on planning-skills and 12px on development-paths, with no
overflow or collisions.
Reported by Ruben.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* feat(website): restyle the docs in the bmadcode design system
The docs carried a Ghost-blog theme: Inter and Space Grotesk, a #3b82f6
accent, 12px radii, tinted panels and hover lifts. bmadcode.com is built
from the foundry ramp on paper, Archivo and IBM Plex Mono, one
accent held under ~2% of the page, 2px corners and hairlines. This aligns
the two so the method and its documentation read as one thing.
Four type registers, and almost nothing else: Instrument Serif for the
page masthead, Archivo 600 for headings, Archivo 400 at 17px for prose,
and IBM Plex Mono at 11px for labels — spent once per section, never on
prose or a table header. The measure comes down to 46rem so a page reads
as an article.
Also fixes the site title, which was the only place in the repo spelling
the brand "BMAD Method"; it now matches the prose, and every page title
and share card with it.
The four component overrides are the parts CSS could not reach: the mark
in its ink tile, the accent eyebrow naming each section, and the dark
footer band. The footer renders from TwoColumnContent rather than the
Footer slot because Starlight right-aligns the content column
(--sl-content-margin-inline: auto 0), so a band in that column never
reached the sidebar edge.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* feat(website): inline hand-authored SVG diagrams
Diagrams shipped as rasters: build-diagram.png at 488 KB, plus a -fr and
a -ko export of the same picture. Every translation meant re-exporting an
image, three of the five locales fell back to the English one, and none
of them could follow the site's light and dark themes.
Diagrams are now hand-authored SVGs carrying geometry and classes only.
A rehype plugin inlines them where a page links to one, so a single
stylesheet themes every diagram — an <img> is opaque to page CSS, which
is the whole reason for inlining. A second diagram written against the
same class vocabulary matches the first without any styling work.
Labels are translated rather than redrawn: each <text> carries a data-i18n
key and the strings live in <name>.labels.json, so one drawing serves
every language and a translation cannot drift out of shape.
The integration exists because the inlined SVG lands inside Astro's
content layer cache, which is keyed on the markdown file. Editing a
diagram left the previous drawing on the page, through a build that
reported success. It watches the diagram directory in dev and drops the
content store when the drawing changes.
Diagram.astro is the same behaviour for anywhere that can take a
component. The docs are 193 .md files and no .mdx, where components
cannot be imported, so the plugin is the path pages actually use.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(build): draw the bmad-build run as a themed SVG
Replaces build-diagram.png and its -fr and -ko exports with one drawing
shared by all five locales: the actors in a left lane, the spine down the
middle, a return channel for BAD_SPEC and INTENT_GAP, and the review
lenses in a panel — the layout the original had.
Gzipped, the diagram goes from 440 KB to 1 KB, and it now follows the
theme. The French labels are in place; the other locales fall back to the
English text in the SVG, which is what their pages showed before.
The raster files stay for now: walk-through-a-change still uses
walkthrough-diagram, and that conversion is a separate change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(website): let the diagram cache stamp survive a fresh checkout
The stamp is written into Astro's cache directory, which does not exist
until Astro creates it partway through the build. On a clean clone — CI,
every time — the integration threw in astro:config:done and took the
build with it.
It now creates the directory, and treats any failure as a warning: a
cache that cannot be stamped is a slower build, not a broken one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(walkthrough): draw the walkthrough run as a themed SVG
Replaces walkthrough-diagram.png and its -fr and -ko exports with one
drawing shared by all five locales, keeping the original's layout: the
two inputs in a left lane, the five stages down the spine, the notes
beside them, the early exit skipping the middle, and the three outcomes
along the bottom.
The outcome chips introduce a `chip` class in the shared stylesheet,
taking the green and amber the asides already use, so a green in a
diagram is the same green as a tip. Nothing else about this diagram
needed styling: it inherits the vocabulary build-run established.
With both diagrams converted, website/public/diagrams is empty and the
six raster files are gone.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(plan): fold the remaining diagrams into the themed pipeline
planning-skills, development-paths and bmad-delivery-loop were already
SVG, but outside the pipeline in three ways: they carried their own
palettes, they were served as <img> so page CSS could not reach them,
and two of them shipped a -ko twin that duplicated the geometry to
translate the labels.
Two were drawn dark — navy grounds, white text, cyan strokes — so on a
light docs page they sat as dark panels. Their palettes are mapped onto
the shared tokens, which flips them correctly in both themes, and their
backdrops are dropped: a diagram sits on the page's ground rather than
painting its own. The hardcoded typefaces go too, so they inherit
Archivo and IBM Plex Mono like everything else.
The Korean strings are lifted out of the -ko files into the label files,
matched by document order, so all five diagrams are now one drawing per
diagram. docs/images is empty.
Also fixes the cache guard, which was clearing the wrong store: build
writes to the cache directory, dev writes to .astro beside the config,
and the stamp was shared between them so whichever ran first consumed
the invalidation. It is now per command and build-only — deleting the
store under a running dev server leaves the content layer unable to
render, so dev needs a restart after a diagram edit instead.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(diagrams): align the imported diagrams with the shared vocabulary
Mapping the old palettes onto the theme tokens made those three diagrams
theme-aware, but not part of the system. They still carried 8-16px
corners, painted their own canvas panel or background grid, drew every
connector in the accent, and left arrowheads baked to a colour of their
own — so next to build-run and walkthrough-run they read as imports.
They now use the same roles as the two authored diagrams: .node for
boxes, .edge for connectors, .head for arrowheads, 2px corners, and no
self-painted ground. Accent drops out of all five: it is for the one
thing a drawing points at, which here is a single .node.hot on the
destination box rather than a green that read as a status.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* chore(docs-site): record hast-util-from-html in the lockfile
The dependency was declared in package.json during the move to docs-site
but its entry never reached the lockfile's root block, so the two
disagreed about what the site depends on.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(diagrams): land the arrowheads on their targets in build-run
Three arrows pointed at glyphs rather than at boxes, and all three fell
short: DEFER stopped 10px from the document and aimed at its corner
instead of its body, REJECT stopped 27px from the discard glyph, and the
result returning to you stopped 21px from the person.
The boxes were fine throughout — every arrow into a node already landed
within 2px. What the three had in common is that a glyph sits inside a
translated group, so eyeballing them against the drawing's coordinates
put the endpoints in the wrong place.
Measured across all twenty arrowheads in screen space afterwards: the
largest remaining gap is 3px.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(diagrams): move the DEFER label off its own curve, and clear the
cache on a dev start too
Re-aiming the DEFER arrow at the document glyph swung its curve left,
straight through the label that had been sitting clear of the old path.
The label moves into the pocket between Present and the curve.
Checking it exposed a worse problem: dev was still serving the previous
drawing after a restart, so the fix looked like it had not applied. The
cache guard had been narrowed to build-only after clearing the store
under a live dev server broke rendering — but that failure came from
clearing on a mid-session restart, and the watch that caused those is
gone. On a cold start, before the content layer loads, clearing is safe
in both commands. Confirmed by probe: edit a diagram, restart dev, the
edit is served, no errors.
So the limitation is now what it was documented to be. Previously an
edited diagram needed a full build before dev would show it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(diagrams): give every connector an arrowhead, and clear the boxes
Three defects in development-paths, all inherited from the import:
Connectors were written as two subpaths in one path element. A marker-end
lands on the last vertex of a path, so only the second segment ever drew
a head — which is why Change—Edit had none and Edit→Verify did. Four
connectors are now separate paths, and all twelve carry a head.
The two routed connectors ended exactly on the box they point at, so the
arrowhead sat on the border. They stop 4px clear.
The epic row was 140/130/130 wide with the labels centred on each box.
All three are 140 now, evenly spaced, with the connectors and labels
following.
Band backgrounds were imported as .node, which made every check treat a
connector crossing its own band as an error. They are .band now: same
appearance, but the drawing says what it means.
Also moves the DEFER label in build-run back alongside its curve. The
previous fix pushed it clear of the line and lost the association.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(diagrams): one stroke weight across all five drawings
build-run and walkthrough-run carry no inline stroke-width — the
stylesheet owns it, at 1.5 for a connector and 1 for a box. The three
imported drawings still carried their own: 2, 3, 4 and 2.5, so their
lines were twice as heavy as the authored ones.
That is also what made the arrowhead into "Build × stories" look wrong.
A marker scales with stroke-width by default, so a head defined at 7
units rendered at 21px on a 3px line instead of 10.5px. On a 9px final
drop it overshot the corner and sat on the horizontal run above the box.
Sixty inline stroke-widths are gone, and the two routed connectors get a
longer final drop so the head has room to sit on.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* test(docs-site): cover rehype-inline-diagrams, and fix what it caught
Twelve tests alongside the existing plugin suite, against a temporary
site root: what gets inlined and what is left alone, label substitution
per locale with fallback to the authored English, the accessible name,
and the mtime-keyed re-read the dev server depends on.
The first run failed on the accessible name, and it was right to. hast
camel-cases ARIA attributes, so the guard read `aria-labelledby` and
found nothing — meaning every diagram's own <title> was being replaced
by the markdown alt text. build-run and walkthrough-run both title
themselves with a sentence describing the whole run, and both were
announcing a four-word alt instead.
Now 119 assertions, and a diagram that names itself keeps its name.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(diagrams): recover the Korean walkthrough labels, and correct the guide
Review caught two things.
The style guide sent contributors to website/src/diagrams/, the path
this branch renamed. A diagram placed there would never be found by the
loader or localized.
The second is a regression this branch introduced and the PR described
wrongly. It claimed the non-English pages "fall back to the English text
in the SVG, which is what their pages showed before". That is untrue for
four pages: they had localized exports, and replacing those with one
drawing plus an English-only label file puts English labels in front of
readers who previously had their own language.
walkthrough-diagram-ko.svg was an SVG, so its Korean is recoverable and
is now the ko-KR label set for walkthrough-run — all 22 keys. The other
three were .webp exports, so their text cannot be lifted out:
ko-kr build-a-change build-run ko-KR 0/30 keys
fr explanation/build build-run fr-FR 13/30 keys
fr build/walk-through walkthrough fr-FR 0/22 keys
Those need a translator. The 13 French keys are mine and unreviewed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* i18n(diagrams): complete the French and Korean diagram labels
Fills the three gaps review found: build-run had no Korean and only 13
of 30 French keys, walkthrough-run had no French. All four sets are now
complete.
Terms come from the repository rather than fresh coinage. Korean reuses
what the -ko diagrams and the Korean pages already established — 의도,
구체화, 계획, 검토, 결과, 사양 — and French follows the vocabulary of
docs/fr/explanation/build.md: revue, intention, résultat, implémentation,
spécification, and visite guidée from the French walkthrough page.
The uppercase edge tokens stay as they are. PATCH, REJECT, BAD_SPEC,
INTENT_GAP and DEFER appear in no locale's prose, so they read as
protocol constants, the way bmad-build and path:line are already left
alone in the Korean set.
French runs longer than English and these are fixed-geometry drawings,
so both French pages and the Korean one were checked for labels
overflowing their box, sitting on a connector, or colliding: none.
These are my translations, not a native speaker's. Worth a pass from
whoever owns each locale before release.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(docs-site): satisfy the repo's lint and format rules in the new tests
The diagram tests used .forEach to walk the hast tree, which this repo's
eslint config rejects (unicorn/no-array-for-each), and the file was not
Prettier-formatted. CI had been failing on lint since the tests landed.
Rewritten as for…of and formatted. Verified against every gate the
workflow runs — lint, format:check, test, build — rather than the build
alone.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* docs(website): describe the source of the theme without naming a private repo
The comments cited the private repository and file paths it was ported
from. They point at bmadcode.com instead, which is the public thing a
reader can actually check.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(website): keep footer links in the reader's language
The footer prefixed only BASE_URL to root-locale paths, so a French or
Korean reader following any internal link landed on the English page and
lost their language for the rest of the visit.
The links now carry the page's locale. Every target exists under every
locale — Starlight generates the untranslated ones as fallbacks — so this
is safe rather than a trade of one broken link for another: all 36
routes, 6 links across 6 locales, resolve in the built site.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* refactor(code-review): run through the skill renderer
Make bmad-code-review a rendered skill like bmad-build, bmad-walkthrough
and bmad-retrospective. SKILL.md becomes the render_skill.py launcher,
and a new workflow.md carries the goal, conventions, activation and step
rules. Step files move from steps/ to the skill root, cross-file
references become [[bmad-snapshot:...]] tokens, artifact paths use
{{.implementation_artifacts}} and {{.planning_artifacts}}, and the
present step reads {workflow.on_complete} at render time instead of
calling resolve_customization.py.
The review step now renders {workflow.review_layers} the way bmad-build
does: the renderer emits one section per active layer, drops layers
whose instruction is empty, binds {skill-root} in layer instructions to
the snapshot so reviewer prompts are read from it, and the step only
evaluates each layer's "Run only when" line at run time.
* test(render): hold bmad-code-review to the review-prompt snapshot checks
Move bmad-code-review into the shipped-skills loop so the renderer test
asserts that {spec_file} survives rendering and that the edge-case
hunter prompt lands in the snapshot at the path the rendered review step
names. The customize.toml comment on review layers now lists
{claims_file} among the run-time substitutions.
* fix(code-review): drop the project-context glob and the stale next-step
The activation text asked to load `**/project-context.md`, which in this
repository matches translated documentation pages rather than a project
context file; no other rendered skill loads one, so remove the line. The
next-steps menu pointed at `dev-story`, which is not an installed skill;
point it at `bmad-build`.
ci(coderabbit): turn off the docstring coverage check
CodeRabbit enables docstring coverage by default at an 80% threshold
and warned on #2844 because the renderer's private helpers carry no
docstrings. No repository rule asks for them, so the warning is noise
on every Python change. Greptile has no equivalent check, so nothing
needs mirroring in greptile.json.
Add repeatable --set key=value arguments and an --overrides <file.toml>
file to render_skill.py. Shipped defaults, project TOML, user TOML, the
invocation file, and command-line assignments resolve into one effective
customization using the existing structural merge; persistent files are
never written.
Two --set paths that are equal or nested halt as a caller error. The
renderer keeps no separate schema of customization keys: a --set path
must exist in customize.toml, and any invocation override that reaches
no token or condition halts. Values are validated where consumed.
Standalone [[bmad-if:path == literal]] / [[bmad-else]] / [[bmad-endif]]
lines select sections before token and link resolution. A secondary
file that filters to nothing is omitted from the snapshot; workflow.md
filtering to nothing is an error. Condition inputs join the generation
identity so identical output from different inputs still yields
distinct snapshots.
Document both interfaces, ignore the per-machine skills-lock.json, and
cover precedence, equivalent forms, isolation, conflicts, unused
overrides, malformed input, nested conditions, and snapshot reuse.
* refactor(retrospective): run through the skill renderer
Make bmad-retrospective a rendered skill like bmad-build and
bmad-walkthrough. SKILL.md becomes the render_skill.py launcher, and a
new workflow.md carries the goal, conventions, modes, activation,
inputs, and phase flow. Reference files are reached through
[[bmad-snapshot:...]] tokens, artifact paths use
{{.implementation_artifacts}}, {{.planning_artifacts}} and
{{.output_folder}}, and the finish section reads {workflow.on_complete}
at render time instead of calling resolve_customization.py. The bundled
scripts keep running from {skill-root}/scripts. The greeting step is
gone; its going-in-concerns prompt moves to the point where the epic is
fixed.
* feat(render): bind {skill-root} to the installed skill directory
Rendered skills can bundle scripts and other non-Markdown files that
the snapshot does not carry. Resolve {skill-root} in skill sources to
the absolute installed skill directory at render time, so no runtime
placeholder survives into the snapshot, and add the skill path to the
generation identity so the same sources installed at two locations
publish distinct generations. Customization values keep binding
{skill-root} to the snapshot. The renderer tests now cover all four
rendered skills and the retrospective's script paths.
* docs(skills): tidy activation prose after the greeting removal
Move the retrospective's going-in-concerns prompt above the sprint-mode
split so it applies in stories mode too, and drop the greet-step
mentions from the walkthrough customize.toml comments.
Make bmad-walkthrough a rendered skill like bmad-build and
bmad-build-auto. SKILL.md becomes the render_skill.py launcher, and a
new workflow.md carries the goal, conventions, activation, and global
step rules. Step files move from steps/ to the skill root, cross-file
references become [[bmad-snapshot:...]] tokens, artifact paths use
{{.implementation_artifacts}} and {{.planning_artifacts}}, and the
wrap-up reads {workflow.on_complete} at render time instead of calling
resolve_customization.py.
* fix(docs-site): point the ko-kr install redirect at a page that exists
The Korean install page is under start/, not how-to/. The redirect
sent readers to a 404.
* feat(docs-site): validate redirects against the built site
Every redirect in astro.config.mjs must point at a page the build
produced, must not point at another redirect, and must not shadow a
doc file that still exists. The check runs inside the docs build after
the Astro output is written. The config cannot be imported from plain
Node because Starlight ships TypeScript, so the validator reads the
redirects block from the config source.
The modules page said TEA adds risk-based prioritization and
traceability over the built-in QA skill. The page it links to compares
the two generate skills instead. Say what that page says.
base_branches listed main, which is the default branch and needs no
listing, while every PR now targets dev. The path filter still named
eslint.config.mjs at the root; it moved to docs-site/ in #2834.
It wired Prettier and ESLint as save-time formatters and attached the
package.json schema; none of those exist at the root any more. The
rest was a 2025 spelling list and Copilot chat preferences. Nothing
reads the file. .vscode/ joins the ignored personal editor files so it
does not come back.
The hint pointed at npx bmad-method --version and package.json, which
exist only for the 6.12 npm install. It now covers both: bmad update
for skills installs, npx bmad-method --version for 6.12.
The guideline claiming the core framework has no code now says which
parts are prose and which are Python run through uv. The issue
template links named bug_report.md and feature_request.md, which do
not exist; they now point at bug-report.yaml and feature-request.md.
The Correct Course paragraph read as if the skill only wrote a proposal
and left all bookkeeping to the user. Checklist item 6.4 still updates
sprint-status.yaml once the proposal is approved, so say so, and keep the
story-breakdown re-run as the path for large restructures only.
The root package.json, lockfile, .nvmrc, prettier ignore file and
.npmignore are gone. docs-site has its own package.json and lockfile
with the Astro, ESLint and Prettier dependencies, and its scripts run
relative to that directory. tools/quality.py, both workflows and the
docs all call npm inside docs-site.
stamp_release.py stamps only the 29 skill manifests now; the version
lives nowhere else on this branch. The tests for package stamping go
with it.
* build: replace the npm lint stack with pre-commit
markdownlint-cli2, prettier and eslint for YAML/JSON, husky and
lint-staged are gone. pre-commit runs ruff, rumdl (the same five
markdown rules), yamllint, yamlfix, the JSON checks, both validators
and pytest, at commit time and over the whole tree from
tools/quality.py, which is now what `npm run quality` calls. ESLint and
prettier stay only for the docs-site scripts and tests. quality.yaml
collapses to a Python job and a docs-site job.
yamlfix keeps one blank line and no document-start marker: its defaults
strip blank lines inside block scalars and add `---`, which the sprint
status scripts do not write back. The JSON hook keeps key order and
non-ASCII text.
* style: apply yamlfix and JSON formatting to the tree
Mechanical output of the new hooks; every file parses to the same data.
* docs: state what the commit hook covers
* refactor(docs-site): move the doc tooling out of tools/
The five doc scripts and their test exist because of Starlight: sidebar
order frontmatter, the rehype link convention, the built site, and the
Astro build itself. They now live under docs-site/scripts and
docs-site/test, next to the rehype plugins and the site tests, which
leaves tools/ Python-only. ESLint stops ignoring those two directories
and its script rules now target them; the Astro sources stay excluded.
* ci(docs): deploy the site from dev
main moves only by release fast-forward, so a docs deploy tied to it
would lag every doc change until the next release. Deploy on push to
dev instead; main receives the same tree later and needs no deploy.
* build: declare the Python toolchain in pyproject.toml
Pin the dev environment (pytest, pytest-xdist, pyyaml, ruamel.yaml, ruff)
with uv instead of a one-line --with list in package.json. The project is
marked non-packaged: the tree itself is what gets installed, and shipped
scripts keep their inline metadata. The validate CI job now runs on uv
alone, without Node, and gains a ruff check.
* style: apply ruff to tools and skill scripts
Mechanical output of ruff check --fix and ruff format under the new
config, plus four hand edits: explicit zip strictness in setup.py and
test_sprint_status.py, an f-string for the hex colour in brain.py, and a
noqa on the sys.path-dependent import in render_skill.py. No behaviour
change; 500 tests pass.
* build: declare Python 3.11 as the floor of every shipped script
Eighteen scripts declared 3.8 or 3.10 inline while ruff targeted 3.11,
so an autofix could introduce syntax those scripts did not advertise.
The lower floors were never reachable: every skill that carried one
also runs a 3.11 hub script, and uv fetches whatever interpreter a
script asks for. All inline metadata now says 3.11, and a test keeps
the inline floors equal to requires-python and the ruff target.
Checks that ran when a PR was opened against main are stale once the
retarget workflow moves it to dev. Trigger on the edited event and skip
title and body edits, so a retargeted PR gets fresh checks without the
contributor closing and reopening it.
The Python rewrite of the file-ref checker ported the JS pattern verbatim,
including the `\\\\` that only matched the escaped `C:\\Users` form. Main
fixed the JS copy in #2794 before this branch deleted it; apply the same
pattern here so the rebase does not revert the fix.
Main renamed bmad-checkpoint-preview to bmad-walkthrough; apply the
same rename under skills/, repoint the hub help doc, and drop the
v6 shim main added since this branch removes the shim tree.
Setup resolved config through the script already, but still wrote
core/config.yaml and bmm/config.yaml on every run. Nothing reads them.
Drop the writes and the code that existed only to build them: the
legacy_config projection threaded through materialize_bmad/stage_bmad,
without_manifest_answers, delete_path, stringify, and the whole YAML
parse/render/fill path. ensure_file now merges TOML only.
Existing files are left in place, like the other classic-installer
traces, and both paths join LEGACY_LEFTOVERS so doctor reports them.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Sn1de7Zc9yWcJnJkE6QNis
Sixteen skills read `_bmad/bmm/config.yaml` directly — a flattened
legacy YAML projection that setup.py writes only for `core` and `bmm`.
It coerces every value to a string, lets `[core]` silently win key
collisions with `[modules.bmm]`, and is generated once at setup, so the
`_bmad/custom/` override layers never reach it.
Each now calls resolve_config.py with the exact keys it needs, matching
the eight skills that already did. Nothing reads either YAML projection
after this; setup.py still writes them.
Values stay under `modules.bmm`, which is where config.template.toml
writes them, though these skills declare `module = "method"`.
Drops the fallbacks with them: the `config.user.yaml` hedge (nothing
writes that file), the missing-key defaults, and "never block". The
config step always follows a resolve_customization.py call, so a missing
scripts directory has already surfaced by then.
`load_central_config` read `_bmad/config.user.toml` as layer 2 while
setup.py listed the same file in LEGACY_LEFTOVERS — debris from the
classic installer that doctor reports read-only and never writes. The
mechanism that populated it (the removed JS installer's `module.yaml`
`scope:` partition) is gone, so nothing creates the file and the
resolver read a layer that could only ever be hand-written into a
directory documented as installer-owned.
Central config is now three layers, matching load_customization:
config.toml -> custom/config.toml -> custom/config.user.toml.
Tests keep writing config.user.toml and assert a key unique to it never
reaches the merge, pinning the removal.
setup.py drops build metadata when ordering versions, so 6.12.0+hotfix
compares equal to 6.12.0 and a release stamped that way is invisible to
every installed copy. The runbook warned against it; the stamper accepted
it. Reject it before anything is written.
The version rule is now "orderable and distinguishable", one notch
stricter than setup.py's orderability - the contract test pins that gap
and pins the premise it rests on.