Compare commits

..

1 Commits

Author SHA1 Message Date
Can Tecim 5b75e53859
Merge f70a9e0569 into 3d824d4c0f 2026-04-24 12:09:23 -04:00
110 changed files with 2840 additions and 8131 deletions

View File

@ -13,7 +13,7 @@
"name": "bmad-pro-skills",
"source": "./",
"description": "Next level skills for power users — advanced prompting techniques, agent management, and more.",
"version": "6.6.0",
"version": "6.3.0",
"author": {
"name": "Brian (BMad) Madison"
},
@ -35,7 +35,7 @@
"name": "bmad-method-lifecycle",
"source": "./",
"description": "Full-lifecycle AI development framework — agents and workflows for product analysis, planning, architecture, and implementation.",
"version": "6.6.0",
"version": "6.3.0",
"author": {
"name": "Brian (BMad) Madison"
},

View File

@ -7,7 +7,6 @@ on:
- "src/**"
- "tools/installer/**"
- "package.json"
- "removals.txt"
workflow_dispatch:
inputs:
channel:
@ -136,22 +135,6 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Advance @next dist-tag to stable
if: github.event_name == 'workflow_dispatch' && inputs.channel == 'latest'
# Failure here leaves @next stale until the next push-driven prerelease
# republishes — annoying but not release-breaking. Don't fail the job
# after a successful stable publish + tag + GH release.
continue-on-error: true
run: |
# Without this, @latest can leapfrog @next (e.g. latest=6.5.0 while
# next=6.4.1-next.0) and `npx bmad-method@next install` silently
# downgrades users. Point @next at the just-published stable so
# @next >= @latest always holds; the next push-driven prerelease will
# bump from this base via the existing derive step above.
VERSION=$(node -p 'require("./package.json").version')
npm dist-tag add "bmad-method@${VERSION}" next
echo "Advanced @next dist-tag to ${VERSION}"
- name: Notify Discord
if: github.event_name == 'workflow_dispatch' && inputs.channel == 'latest'
continue-on-error: true

View File

@ -1,100 +1,5 @@
# Changelog
## v6.6.0 - 2026-04-28
### 💥 Breaking Changes
* `--tools none` is no longer accepted; fresh `--yes` installs now require an explicit `--tools <id>`. Existing-install flows are unchanged. Run `npx bmad-method --list-tools` to see supported IDs (#2346)
* `project_name` has moved from `[modules.bmm]` to `[core]` in `config.toml`. Existing installs are auto-migrated on next install/update — no manual action required (#2348)
### 🎁 Features
* **Non-interactive config for CI/Docker** — new `--set <module>.<key>=<value>` (repeatable) and `--list-options [module]` flags allow installer configuration without prompts. Routes values to the correct config file with prototype-pollution defenses (#2354)
* **Brownfield epic scoping** — Create Epics and Stories workflow now detects file-overlap between epics and applies an Implementation Efficiency principle plus a design completeness gate, reducing unnecessary file churn (#1826)
### 🐛 Fixes
* **Custom module installer** — Azure DevOps URLs now parse correctly with multi-segment paths and `_git` prefixes (#2269); HTTP (non-HTTPS) Git URLs are preserved for self-hosted servers (#2344); community installs route through `PluginResolver` so marketplace plugins with nested `module.yaml` install all skills (#2331); URL-source modules resolve from disk cache on re-install instead of warning (#2323); local `--custom-content` modules resolve correctly and `[modules.<code>]` TOML keys use the module code rather than display name (#2316); `--yes` with `--custom-source` now runs the full update path so version tags are respected (#2336)
* **Installer safety**`--list-tools` flag added; empty/typo'd tool IDs rejected with specific errors (#2346)
* **Channel and dist-tag handling** — installer launched from a prerelease (e.g. `@next`) now defaults external module channels to `next` instead of silently downgrading to stable (#2321); stable publishes advance the `@next` dist-tag so prerelease users no longer leapfrog or miss update notifications (#2320)
* **Architecture validation gate** — step-07 validation template no longer ships pre-checked; status field is now templated against actual checklist completion (#2347)
* **bmad-help data integrity**`bmad-help.csv` is no longer transformed at merge time and is emitted in its documented schema; 31 misaligned rows in core/bmm `module-help.csv` repaired (#2349)
* **Config robustness** — malformed `module.yaml` (scalars, arrays) is now rejected before crash (#2348)
* **Legacy cleanup** — pre-v6.2.0 wrapper skills (`bmad-bmm-*`, `bmad-agent-bmm-*`) are removed automatically on upgrade so they no longer error with missing-file warnings (#2315)
### 📚 Docs
* Complete Chinese (zh-CN) translations for `named-agents.md` and `expand-bmad-for-your-org.md`; localized BMad Ecosystem sidebar (CIS, BMB, TEA, WDS) across zh-cn, vi-vn, fr-fr, cs-cz (#2355)
## v6.5.0 - 2026-04-26
### 🎁 Features
* Support for 18 new agent platforms: AdaL, Sourcegraph Amp, IBM Bob, Command Code, Snowflake Cortex Code, Factory Droid, Firebender, Block Goose, Kode, Mistral Vibe, Mux, Neovate, OpenClaw, OpenHands, Pochi, Replit Agent, Warp, Zencoder — bringing total supported platforms to 42 (#2313)
* All platforms that support the cross-tool `.agents/skills/` standard now use it (#2313)
## v6.4.0 - 2026-04-24
### ✨ Headline
**Full agent and workflow customization across the entire BMad Method.** Every agent and workflow in BMM, Core, CIS, GDS, and TEA can now be customized via TOML overrides in `_bmad/custom/`. Customize agents to apply tooling, version control, or behavior changes across whole groups of workflows. Drop in fine-grained per-workflow overrides where you need them. Built for power users who want BMad to fit their stack without forking.
**Stable and bleeding-edge release channels, standardized across all modules.** Pick `stable` or `next` per module, pin specific versions, and switch channels interactively or via CLI flags (`--channel`, `--all-stable`, `--all-next`, `--next=CODE`, `--pin CODE=TAG`). Same model across BMM, Core, and every external module.
### 💥 Breaking Changes
* Customization is now TOML-based; the briefly introduced YAML-based customization is no longer supported (#2284, #2283)
### 🎁 Features
**Customization framework**
* TOML-based agent and workflow customization with flat schema, structural merge rules (scalars, tables, code-keyed arrays, append arrays), and `persistent_facts` unification (#2284)
* Central `_bmad/config.toml` surface with four-file architecture (`config.toml`, `config.user.toml`, `custom/config.toml`, `custom/config.user.toml`) for agent roster and scope-partitioned install answers (#2285)
* `customize.toml` support extended to 17 bmm-skills workflows with flattened SKILL.md architecture and standardized `[workflow]` block (#2287)
* `customize.toml` extended to all six developer-execution workflows: bmad-dev-story, bmad-code-review, bmad-sprint-planning, bmad-sprint-status, bmad-quick-dev, bmad-checkpoint-preview (#2308)
* `bmad-customize` skill — guided authoring of TOML overrides in `_bmad/custom/` with stdlib-only resolver verification (#2289)
* Wire `on_complete` hook into all 23 workflow terminal steps with full customize.toml documentation (#2290)
**Release channels & installer**
* Channel-based version resolution for external modules with interactive channel management (`stable` / `next` / `pinned`) and CLI flags (`--channel`, `--all-stable`, `--all-next`, `--next=CODE`, `--pin CODE=TAG`) (#2305)
* GitHub API as primary fetch with raw CDN fallback in installer registry client to support corporate proxies (#2248)
**Other**
* Kimi Code CLI support for installing BMM skills in `.kimi/skills/` (#2302)
* `bmad-create-story` now reads every UPDATE-marked file before generating dev notes so brownfield stories preserve current behavior instead of improvising at implementation time (#2274)
* Sync `sprint-status.yaml` from quick-dev on epic-story implementation with idempotent writes tracking `in-progress` and `review` transitions (#2234)
* Enforce model parity for all code review subagents to match orchestrator session capability for improved rare-event detection (#2236)
* Set `team: software-development` on all six BMM agents for unified grouping in party-mode and retrospective skills (#2286)
### 🐛 Bug Fixes
* PRD workflow no longer silently de-scopes user requirements or invents MVP/Growth/Vision phasing; requires explicit confirmation before any scope reduction (#1927)
* Installer shows live npm version for external modules instead of stale cached metadata (#2307)
* Resolve external-module agents from cache during manifest write so agents land in `config.toml` (#2295)
* Fix installer version resolution for external modules with shared resolver preferring package.json > module.yaml > marketplace.json (#2298)
* Replace fs-extra with native `node:fs` to prevent file loss during multi-module installs from deferred retry-queue races (#2253)
* Add `move()` and overwrite support to fs-native wrapper for directory migrations during upgrades (#2253)
* Stop skill scanner from recursing into discovered skills to prevent spurious errors on nested template files (#2255)
* Source built-in modules locally in installer UI to preserve core and bmm in module list when registry is unreachable (#2251)
* Remove dead Batch-apply option from code-review patch menu and rename apply options for clarity (#2225)
### ♻️ Refactoring
* Remove 1,683 lines of dead code: three entirely dead files (agent-command-generator.js, bmad-artifacts.js, module-injections.js) and ~50 unused exports across installer modules (#2247)
* Remove dead template and agent-command pipeline from installer; SKILL.md directory copying is the sole installation path (#2244)
### 📚 Documentation
* Sync and update Vietnamese (vi-VN) docs with missing pages and refreshed translations (#2291, #2222)
* Sync French (fr-FR) translations with upstream, restore Amelia as dev agent, fix sidebar ordering (#2231)
* Add Czech (cs-CZ) `analysis-phase.md` translation; normalize typographic quotes (#2240, #2241, #2242)
* Add missing Chinese (zh-CN) translations for 3 documents (#2254)
* Update stale Analyst agent triggers and add PRFAQ link (#2238)
* Remove Bob from workflow map diagrams reflecting consolidation into Amelia in v6.3.0 (#2252)
## v6.3.0 - 2026-04-09
### 💥 Breaking Changes

View File

@ -52,15 +52,6 @@ Follow the installer prompts, then open your AI IDE (Claude Code, Cursor, etc.)
npx bmad-method install --directory /path/to/project --modules bmm --tools claude-code --yes
```
Override any module config option with `--set <module>.<key>=<value>` (repeatable). Run `--list-options [module]` to see locally-known official keys (built-in modules plus any external officials cached on this machine):
```bash
npx bmad-method install --yes \
--modules bmm --tools claude-code \
--set bmm.project_knowledge=research \
--set bmm.user_skill_level=expert
```
[See all installation options](https://docs.bmad-method.org/how-to/non-interactive-installation/)
> **Not sure what to do?** Ask `bmad-help` — it tells you exactly what's next and what's optional. You can also ask questions like `bmad-help I just finished the architecture, what do I do next?`

View File

@ -60,7 +60,7 @@ Dostupná ID nástrojů pro příznak `--tools`:
**Preferované:** `claude-code`, `cursor`
Spusťte `npx bmad-method install` interaktivně jednou pro zobrazení aktuálního seznamu podporovaných nástrojů, nebo zkontrolujte [konfiguraci kódů platforem](https://github.com/bmad-code-org/BMAD-METHOD/blob/main/tools/installer/ide/platform-codes.yaml).
Spusťte `npx bmad-method install` interaktivně jednou pro zobrazení aktuálního seznamu podporovaných nástrojů, nebo zkontrolujte [konfiguraci kódů platforem](https://github.com/bmad-code-org/BMAD-METHOD/blob/main/tools/cli/installers/lib/ide/platform-codes.yaml).
## Režimy instalace

View File

@ -1,137 +0,0 @@
---
title: "Forensic Investigation"
description: How bmad-investigate treats every issue like a crime scene, grades evidence, and produces a structured case file engineers can act on
sidebar:
order: 6
---
You hand `bmad-investigate` a crash log, a stack trace, or just a "this used to work, now it doesn't". The skill takes
over the investigator's discipline for the duration of the run. It does not start fixing. It opens a case file.
Every finding gets graded. Every hypothesis gets a status. Wrong turns are kept, not erased. The deliverable is a
document another engineer can pick up cold.
This page explains why investigation is its own discipline, and what the skill buys you that a regular dev workflow
doesn't.
## The Problem With "Just Debug It"
Normal debugging blends three things: looking at evidence, reasoning about cause, and changing code to test the theory.
When they're blended, two failure modes show up.
The first is **narrative lock-in**. The first plausible story becomes the working theory, and every observation gets
bent to fit it. The bug stays unfixed until someone gives up and starts over. Hours later.
The second is **evidence amnesia**. You traced something, ruled it out, but didn't write down why. Two days later, with
fresh eyes, you trace it again. Or worse, a colleague picks up the bug and re-runs the same dead end you already
eliminated.
The skill's design is a direct response to both.
## Evidence Grading
Every finding in an investigation is one of three things.
- **Confirmed.** Directly observed in logs, code, or dumps; cited with a specific reference (a `path:line`, a log
timestamp, a commit hash). If someone asks "how do you know?", you point at the citation.
- **Deduced.** Logically follows from confirmed evidence; the reasoning chain is shown. If a step in the chain is wrong,
the deduction is wrong, and you can see exactly which step.
- **Hypothesized.** Plausible but unconfirmed. States what evidence would confirm or refute, and declares upfront what
would close it. Hypotheses are explicitly *not facts*.
The grading is not about being humble. It's about making the case file readable. A reader can scan the Confirmed section
to know what is true, the Deduced section to know what follows, and the Hypothesized section to know what is still open.
Confusion between the three is the most common reason investigations spiral.
## Stronghold First
Investigation never starts from a theory. It starts from one piece of confirmed evidence and expands outward. That
evidence might be a specific error message, a stack frame, or a timestamped log entry.
This is the opposite of how investigations often go. Someone has a hunch, builds a theory, and then hunts for evidence
that supports it. The hunch can be right; the *method* is fragile because it makes confirmation bias the default.
A stronghold is a fact you can return to when reasoning gets murky. If a deduction takes you somewhere strange, you can
walk it back to the stronghold and try a different branch. Without one, you don't know which step to undo.
When evidence is sparse, the skill says so and switches to hypothesis-driven exploration: form hypotheses from what's
available, identify what would test each, present a prioritized data-collection list. Missing evidence is itself a
finding.
## Hypothesis Discipline
Hypotheses are never deleted from the case file. When evidence confirms or refutes one, its **Status** field updates
from Open to Confirmed or Refuted, and a **Resolution** explains what evidence settled it.
This rule has a real cost. Case files grow. The benefit is real too. The full reasoning history becomes part of the
deliverable. Six months later, when a similar bug surfaces, the next investigator can read the original case file and
see which paths were already eliminated and why. Without that history, every new investigator re-runs the same dead
ends.
It also disciplines the present-tense investigator. If you can't delete a wrong hypothesis, you have to disprove it
with cited evidence. Quietly dropping it when it becomes inconvenient is no longer an option.
## Challenge the Premise
The user's description of the problem is a hypothesis, not a fact. "The cache is broken" is something a user *believes*.
Before the skill builds an investigation around it, the technical claims are verified independently. If the evidence
contradicts the premise, the report says so directly.
This is the forensic instinct: the witness's account is data, not truth. Sometimes the reported bug is real but
mislabeled. Sometimes the described symptom is downstream of a different cause. Investigations that take the premise as
gospel diagnose the wrong defect, and the bug returns in a slightly different form.
## A Calibrated Walk
The skill is one procedure, not two modes. It calibrates how much defect-chasing versus how much area-exploration the
input demands, on a continuous scale.
A symptom-driven case (a ticket, a crash, an error message, a "this used to work") leans into hypothesis tracking,
timeline reconstruction, and a fix direction. A no-symptom case (understanding a module before you touch it, evaluating
reusability, building a mental model) leans into I/O mapping, control-flow filtering, and a verification plan. Most
real cases sit somewhere between, and the case file reflects whichever balance the evidence required.
The discipline is the same regardless of where on the scale a case lands: stronghold first, evidence grading, hypothesis
tracking, never erase. The output is always at `{implementation_artifacts}/investigations/{slug}-investigation.md`, with
sections that don't apply to a given case left empty or omitted.
When a deep bug requires understanding a broader subsystem, the procedure folds in the I/O mapping, control-flow
filtering, working-backward-from-outputs, and cross-component boundary tracing techniques inline. The area model lands
in the same case file. There is no mode switch.
## Methodology Lives in the Skill
The investigator's discipline is a property of the skill itself. Whoever invokes `bmad-investigate` takes on the
methodology and communication style for the run: clinical precision, evidence-first language, no hedging, case-file
framing. When the skill ends, the caller returns to its prior voice. No persona swap, just a tone shift from the skill's
principles.
This matters because investigation and implementation reward different instincts. Investigators are slow and precise.
Implementers are fast and confident. The same brain doing both in one session tends to do neither well. The skill
carves out the investigative posture inline, without a context switch to a separate identity.
## What You Get
A completed investigation file:
- Separates Confirmed findings (with citations) from Deductions and Hypotheses
- Preserves all hypotheses ever formed, with their final Status and Resolution
- Reconstructs a timeline of events from multiple evidence sources
- Identifies data gaps and what they would resolve
- Provides actionable conclusions grounded in evidence
- Includes a reproduction plan when a root cause is identified
- Maintains an investigation backlog of paths still to explore
Hand it to an engineer who was not present and they understand what happened, what is known, and what remains uncertain.
That's the bar.
## The Bigger Idea
Most "AI debugging" today blends evidence, reasoning, and code changes into one stream of plausible-looking text. The
signal is hard to find, the dead ends repeat, and the case file, if there is one, is a chat log nobody wants to read.
`bmad-investigate` treats investigation as a discipline with its own deliverable. Evidence has a grade. Hypotheses have
a status. Wrong turns are documented, not erased. The case file outlives the session.
When the next bug shows up that looks like one you've seen before, you have somewhere to start that isn't a blank
prompt.

View File

@ -1,157 +0,0 @@
---
title: "Enquête de code"
description: Comment bmad-investigate traite chaque problème comme une scène d'enquête, classe les preuves et produit un dossier structuré sur lequel les ingénieurs peuvent agir
sidebar:
order: 6
---
Vous confiez à `bmad-investigate` un journal de plantage, une trace de pile, ou simplement un « ça marchait avant, plus
maintenant ». Le skill prend le relais avec la discipline d'enquête le temps de l'exécution. Il ne se met pas à
corriger. Il ouvre un dossier d'enquête.
Chaque constatation reçoit une note. Chaque hypothèse a un statut. Les fausses pistes sont conservées, pas effacées. Le
livrable est un document qu'un autre ingénieur peut reprendre à froid.
Cette page explique pourquoi l'enquête est une discipline à part entière, et ce que le skill apporte qu'un workflow de
développement classique n'apporte pas.
## Le problème du « débogue, c'est tout »
Le débogage classique mélange trois activités : examiner les preuves, raisonner sur la cause, et modifier le code pour
tester la théorie. Quand elles sont mélangées, deux modes de défaillance apparaissent.
Le premier est le **verrouillage narratif**[^1]. La première histoire plausible devient la théorie de travail, et chaque
observation est tordue pour la confirmer. Le bug reste non corrigé jusqu'à ce que quelqu'un abandonne et reparte de
zéro. Des heures plus tard.
Le second est l'**amnésie probatoire**. Vous avez tracé quelque chose, l'avez écarté, mais n'avez pas écrit pourquoi.
Deux jours plus tard, avec un regard frais, vous le retracez. Pire encore, un collègue reprend le bug et refait la même
impasse que vous aviez déjà éliminée.
La conception du skill est une réponse directe à ces deux modes.
## Classement des preuves
Chaque constatation dans une enquête appartient à l'une de trois catégories.
- **Confirmé.** Directement observé dans les logs, le code ou les dumps ; cité avec une référence spécifique (un
`chemin:ligne`, un horodatage de log, un hash de commit). Si quelqu'un demande « comment le sais-tu ? », vous pointez
la citation.
- **Déduit.** Découle logiquement de preuves confirmées ; la chaîne de raisonnement est explicite. Si une étape de la
chaîne est fausse, la déduction est fausse, et on peut voir précisément quelle étape.
- **Hypothétique.** Plausible mais non confirmé. Énonce quelle preuve confirmerait ou réfuterait, et déclare d'avance ce
qui le clôturerait. Les hypothèses sont explicitement *non factuelles*.
Le classement n'est pas une posture d'humilité. Il rend le dossier lisible. Un lecteur peut parcourir la section
Confirmé pour savoir ce qui est vrai, la section Déduit pour savoir ce qui en découle, et la section Hypothétique pour
savoir ce qui reste ouvert. Confondre les trois est la première raison pour laquelle les enquêtes dérapent.
## Tête de pont d'abord
L'enquête ne part jamais d'une théorie. Elle part d'une seule preuve confirmée et étend la zone à partir de là. Cette
preuve peut être un message d'erreur précis, une trame de pile, ou une entrée de log horodatée.
C'est l'inverse de la manière dont les enquêtes se déroulent souvent : quelqu'un a une intuition, construit une théorie,
puis cherche les preuves qui la soutiennent. L'intuition peut être correcte ; la *méthode* est fragile parce qu'elle
fait du biais de confirmation[^2] le comportement par défaut.
Une tête de pont est un fait sur lequel vous pouvez revenir quand le raisonnement devient flou. Si une déduction vous
emmène quelque part d'étrange, vous pouvez remonter jusqu'à la tête de pont et essayer une autre branche. Sans elle,
vous ne savez pas quelle étape annuler.
Quand les preuves sont rares, le skill le dit et bascule en exploration guidée par hypothèses : formuler des hypothèses
à partir de ce qui est disponible, identifier ce qui testerait chacune, présenter une liste priorisée de données à
collecter. L'absence de preuve est elle-même une constatation.
## Discipline des hypothèses
Les hypothèses ne sont jamais supprimées du dossier. Quand une preuve en confirme ou en réfute une, son champ **Statut**
passe d'Ouvert à Confirmé ou Réfuté, et une **Résolution** explique quelle preuve a tranché.
Cette règle a un coût réel : les dossiers grossissent. Le bénéfice est réel aussi. L'historique complet du raisonnement
fait partie du livrable. Six mois plus tard, quand un bug similaire surgit, le prochain enquêteur peut lire le dossier
original et voir quelles pistes ont déjà été éliminées et pourquoi. Sans cet historique, chaque nouvel enquêteur refait
les mêmes impasses.
Cela discipline aussi l'enquêteur du présent. Si vous ne pouvez pas supprimer une hypothèse fausse, vous devez la
réfuter avec une preuve citée. L'abandonner discrètement quand elle devient gênante n'est plus une option.
## Remettre en question la prémisse
La description du problème par l'utilisateur est une hypothèse, pas un fait. « Le cache est cassé » est quelque chose
que l'utilisateur *croit*. Avant que le skill ne construise une enquête autour, les affirmations techniques sont
vérifiées de manière indépendante. Si la preuve contredit la prémisse, le rapport le dit directement.
C'est l'instinct de l'enquêteur : le récit du témoin est une donnée, pas la vérité. Parfois le bug rapporté est réel
mais mal étiqueté. Parfois le symptôme décrit est en aval d'une cause différente. Les enquêtes qui prennent la prémisse
pour argent comptant diagnostiquent le mauvais défaut, et le bug revient sous une forme légèrement différente.
## Une marche calibrée
Le skill est une seule procédure, pas deux modes. Il calibre la part d'investigation de défaut versus la part
d'exploration de zone que l'entrée demande, sur une échelle continue.
Un cas piloté par symptôme (un ticket, un plantage, un message d'erreur, un « ça marchait avant ») penche vers le suivi
d'hypothèses, la reconstruction de la chronologie et une direction de correction. Un cas sans symptôme (comprendre un
module avant de le toucher, évaluer la réutilisabilité, bâtir un modèle mental) penche vers la cartographie
entrées/sorties, le filtrage du flux de contrôle et un plan de vérification. La plupart des cas réels se situent quelque
part entre les deux, et le dossier reflète l'équilibre que les preuves ont exigé.
La discipline est la même quel que soit l'endroit de l'échelle où se situe un cas : tête de pont d'abord, classement
des preuves, suivi des hypothèses, jamais effacer. La sortie est toujours
`{implementation_artifacts}/investigations/{slug}-investigation.md`, avec les sections qui ne s'appliquent pas à un cas
laissées vides ou omises.
Quand un bug profond exige de comprendre un sous-système plus large, la procédure intègre en ligne les techniques de
cartographie entrées/sorties, de filtrage du flux de contrôle, de raisonnement à rebours depuis les sorties et de
traçage des frontières inter-composants[^3]. Le modèle de la zone atterrit dans le même dossier. Pas de changement de
mode.
## La méthodologie vit dans le skill
La discipline d'enquête est une propriété du skill lui-même. Quiconque invoque `bmad-investigate` adopte la méthodologie
et le style de communication pour l'exécution : précision clinique, langage centré sur la preuve, pas de prudence
inutile, présentation en dossier de cas. Quand le skill se termine, l'appelant retrouve sa voix d'avant. Pas de
changement de persona, juste un déplacement de ton issu des principes du skill.
Cela compte parce que l'enquête et l'implémentation récompensent des instincts différents. Les enquêteurs sont lents et
précis. Les implémenteurs sont rapides et confiants. Le même cerveau faisant les deux dans une seule session finit par
mal faire les deux. Le skill délimite la posture d'enquête en ligne, sans changement de contexte vers une identité
séparée.
## Ce que vous obtenez
Un fichier d'enquête achevé :
- Sépare les constatations Confirmées (avec citations) des Déductions et des Hypothèses
- Préserve toutes les hypothèses jamais formulées, avec leur Statut final et leur Résolution
- Reconstruit une chronologie des événements à partir de plusieurs sources de preuves
- Identifie les lacunes de données et ce qu'elles résoudraient
- Fournit des conclusions actionnables ancrées dans les preuves
- Inclut un plan de reproduction quand une cause racine est identifiée
- Maintient un backlog d'enquête de pistes encore à explorer
Donnez-le à un ingénieur qui n'était pas là, et il comprend ce qui s'est passé, ce qui est connu, et ce qui reste
incertain. C'est la barre.
## L'idée plus large
La plupart du « débogage par IA » d'aujourd'hui mélange preuves, raisonnement et changements de code en un seul flux de
texte plausible. Le signal est difficile à trouver, les impasses se répètent, et le dossier, s'il en existe un, est un
journal de chat que personne ne veut lire.
`bmad-investigate` traite l'enquête comme une discipline avec son propre livrable. La preuve a une note. Les hypothèses
ont un statut. Les fausses pistes sont documentées, pas effacées. Le dossier survit à la session.
Quand le prochain bug ressemblant à un que vous avez déjà vu apparaîtra, vous aurez un point de départ qui ne sera pas
une invite vide.
## Glossaire
[^1]: **Verrouillage narratif** : phénomène cognitif par lequel un raisonnement adopte la première explication plausible
et l'enrichit progressivement, devenant de plus en plus difficile à abandonner même face à des preuves contraires.
[^2]: **Biais de confirmation** : tendance cognitive à rechercher, interpréter et favoriser les informations qui
confirment des croyances préexistantes, tout en ignorant ou minimisant celles qui les contredisent.
[^3]: **Passage de frontière** : transition entre deux zones d'exécution distinctes (langage, processus, machine,
client/serveur, code/configuration). Les frontières concentrent les bugs car chaque côté suppose que l'autre s'est
comporté comme documenté.

View File

@ -5,23 +5,13 @@ sidebar:
order: 1
---
La méthode BMad (BMM) est un module de l'écosystème BMad, conçu pour suivre les meilleures pratiques de l'ingénierie du
contexte et de la planification. Les agents IA fonctionnent de manière optimale avec un contexte clair et structuré. Le
système BMM construit ce contexte progressivement à travers 4 phases distinctes — chaque phase, et plusieurs workflows
optionnels au sein de chaque phase, produisent des documents qui alimentent la phase suivante, afin que les agents
sachent toujours quoi construire et pourquoi.
La méthode BMad (BMM) est un module de l'écosystème BMad, conçu pour suivre les meilleures pratiques de l'ingénierie du contexte et de la planification. Les agents IA fonctionnent de manière optimale avec un contexte clair et structuré. Le système BMM construit ce contexte progressivement à travers 4 phases distinctes — chaque phase, et plusieurs workflows optionnels au sein de chaque phase, produisent des documents qui alimentent la phase suivante, afin que les agents sachent toujours quoi construire et pourquoi.
La logique et les concepts proviennent des méthodologies agiles qui ont été utilisées avec succès dans l'industrie comme
cadre mental de référence.
La logique et les concepts proviennent des méthodologies agiles qui ont été utilisées avec succès dans l'industrie comme cadre mental de référence.
Si à tout moment vous ne savez pas quoi faire, le skill `bmad-help` vous aidera à rester sur la bonne voie ou à savoir
quoi faire ensuite. Vous pouvez toujours vous référer à cette page également — mais `bmad-help` est entièrement
interactif et beaucoup plus rapide si vous avez déjà installé la méthode BMad. De plus, si vous utilisez différents
modules qui ont étendu la méthode BMad ou ajouté d'autres modules complémentaires non extensifs — `bmad-help` évolue
pour connaître tout ce qui est disponible et vous donner les meilleurs conseils du moment.
Si à tout moment vous ne savez pas quoi faire, le skill `bmad-help` vous aidera à rester sur la bonne voie ou à savoir quoi faire ensuite. Vous pouvez toujours vous référer à cette page également — mais `bmad-help` est entièrement interactif et beaucoup plus rapide si vous avez déjà installé la méthode BMad. De plus, si vous utilisez différents modules qui ont étendu la méthode BMad ou ajouté d'autres modules complémentaires non extensifs — `bmad-help` évolue pour connaître tout ce qui est disponible et vous donner les meilleurs conseils du moment.
Note finale importante : Chaque workflow ci-dessous peut être exécuté directement avec l'outil de votre choix via un
skill ou en chargeant d'abord un agent et en utilisant l'entrée du menu des agents.
Note finale importante : Chaque workflow ci-dessous peut être exécuté directement avec l'outil de votre choix via un skill ou en chargeant d'abord un agent et en utilisant l'entrée du menu des agents.
<iframe src="/workflow-map-diagram-fr.html" title="Diagramme de la carte des workflows de la méthode BMad" width="100%" height="100%" style="border-radius: 8px; border: 1px solid #334155; min-height: 900px;"></iframe>
@ -31,15 +21,14 @@ skill ou en chargeant d'abord un agent et en utilisant l'entrée du menu des age
## Phase 1 : Analyse (Optionnelle)
Explorez lespace problème et validez les idées avant de vous engager dans la planification. [**Découvrez ce que fait
chaque outil et quand lutiliser**](../explanation/analysis-phase.md).
Explorez lespace problème et validez les idées avant de vous engager dans la planification. [**Découvrez ce que fait chaque outil et quand lutiliser**](../explanation/analysis-phase.md).
| Workflow | Objectif | Produit |
|---------------------------------------------------------------------------|------------------------------------------------------------------------------------------|---------------------------|
| `bmad-brainstorming` | Brainstormez des idées de projet avec laccompagnement guidé dun coach de brainstorming | `brainstorming-report.md` |
| `bmad-domain-research`, `bmad-market-research`, `bmad-technical-research` | Validez les hypothèses de marché, techniques ou de domaine | Rapport de recherches |
| `bmad-product-brief` | Capturez la vision stratégique — idéal lorsque votre concept est clair | `product-brief.md` |
| `bmad-prfaq` | Working Backwards — éprouvez et forgez votre concept produit | `prfaq-{project}.md` |
| `bmad-prfaq` | Working Backwards — éprouvez et forgez votre concept produit | `prfaq-{project}.md` |
## Phase 2 : Planification
@ -47,75 +36,60 @@ Définissez ce qu'il faut construire et pour qui.
| Workflow | Objectif | Produit |
|-------------------------|---------------------------------------------------------|--------------|
| `bmad-create-prd` | Définissez les exigences (FRs/NFRs)[^1] | `PRD.md`[^2] |
| `bmad-create-prd` | Définissez les exigences (FRs/NFRs)[^1] | `PRD.md`[^2] |
| `bmad-create-ux-design` | Concevez l'expérience utilisateur (lorsque l'UX compte) | `ux-spec.md` |
## Phase 3 : Solutioning
Décidez comment le construire et décomposez le travail en stories.
| Workflow | Objectif | Produit |
|---------------------------------------|---------------------------------------------------|---------------------------------|
| `bmad-create-architecture` | Rendez les décisions techniques explicites | `architecture.md` avec ADRs[^3] |
| `bmad-create-epics-and-stories` | Décomposez les exigences en travail implémentable | Fichiers d'epic avec stories |
| `bmad-check-implementation-readiness` | Vérification avant implémentation | Décision Passe/Réserves/Échec |
| Workflow | Objectif | Produit |
|---------------------------------------|---------------------------------------------------|------------------------------|
| `bmad-create-architecture` | Rendez les décisions techniques explicites | `architecture.md` avec ADRs[^3] |
| `bmad-create-epics-and-stories` | Décomposez les exigences en travail implémentable | Fichiers d'epic avec stories |
| `bmad-check-implementation-readiness` | Vérification avant implémentation | Décision Passe/Réserves/Échec |
## Phase 4 : Implémentation
Construisez, une story à la fois. Bientôt disponible : automatisation complète de la phase 4 !
| Workflow | Objectif | Produit |
|------------------------|-------------------------------------------------------------------------------------|------------------------------------------------------|
| `bmad-sprint-planning` | Initialisez le suivi (une fois par projet pour séquencer le cycle de développement) | `sprint-status.yaml` |
| `bmad-create-story` | Préparez la story suivante pour implémentation | `story-[slug].md` |
| `bmad-dev-story` | Implémentez la story | Code fonctionnel + tests |
| `bmad-code-review` | Validez la qualité de l'implémentation | Approuvé ou changements demandés |
| `bmad-correct-course` | Gérez les changements significatifs en cours de sprint | Plan mis à jour ou réorientation |
| `bmad-sprint-status` | Suivez la progression du sprint et le statut des stories | Mise à jour du statut du sprint |
| `bmad-retrospective` | Revue après complétion d'un epic | Leçons apprises |
| `bmad-investigate` | Enquête de cas avec conclusions à preuves graduées, calibrée selon l'entrée | `{slug}-investigation.md` |
| Workflow | Objectif | Produit |
|------------------------|-------------------------------------------------------------------------------------|----------------------------------|
| `bmad-sprint-planning` | Initialisez le suivi (une fois par projet pour séquencer le cycle de développement) | `sprint-status.yaml` |
| `bmad-create-story` | Préparez la story suivante pour implémentation | `story-[slug].md` |
| `bmad-dev-story` | Implémentez la story | Code fonctionnel + tests |
| `bmad-code-review` | Validez la qualité de l'implémentation | Approuvé ou changements demandés |
| `bmad-correct-course` | Gérez les changements significatifs en cours de sprint | Plan mis à jour ou réorientation |
| `bmad-sprint-status` | Suivez la progression du sprint et le statut des stories | Mise à jour du statut du sprint |
| `bmad-retrospective` | Revue après complétion d'un epic | Leçons apprises |
## Quick Dev (Parcours Parallèle)
Sautez les phases 1-3 pour les travaux de faible envergure et bien compris.
| Workflow | Objectif | Produit |
|------------------|-------------------------------------------------------------------------------------|--------------------|
| Workflow | Objectif | Produit |
|------------------|-------------------------------------------------------------------------------------|-----------------------|
| `bmad-quick-dev` | Flux rapide unifié — clarifie l'intention, planifie, implémente, révise et présente | `spec-*.md` + code |
## Gestion du Contexte
Chaque document devient le contexte de la phase suivante. Le PRD[^2] indique à l'architecte quelles contraintes sont
importantes. L'architecture indique à l'agent de développement quels modèles suivre. Les fichiers de story fournissent
un contexte focalisé et complet pour l'implémentation. Sans cette structure, les agents prennent des décisions
incohérentes.
Chaque document devient le contexte de la phase suivante. Le PRD[^2] indique à l'architecte quelles contraintes sont importantes. L'architecture indique à l'agent de développement quels modèles suivre. Les fichiers de story fournissent un contexte focalisé et complet pour l'implémentation. Sans cette structure, les agents prennent des décisions incohérentes.
### Contexte du Projet
:::tip[Recommandé]
Créez `project-context.md` pour vous assurer que les agents IA suivent les règles et préférences de votre projet. Ce
fichier fonctionne comme une constitution pour votre projet — il guide les décisions d'implémentation à travers tous les
workflows. Ce fichier optionnel peut être généré à la fin de la création de l'architecture, ou dans un projet existant
il peut également être généré pour capturer ce qui est important de conserver aligné avec les conventions actuelles.
Créez `project-context.md` pour vous assurer que les agents IA suivent les règles et préférences de votre projet. Ce fichier fonctionne comme une constitution pour votre projet — il guide les décisions d'implémentation à travers tous les workflows. Ce fichier optionnel peut être généré à la fin de la création de l'architecture, ou dans un projet existant il peut également être généré pour capturer ce qui est important de conserver aligné avec les conventions actuelles.
:::
**Comment le créer :**
- **Manuellement** — Créez `_bmad-output/project-context.md` avec votre pile technologique et vos règles
d'implémentation
- **Générez-le** — Exécutez `bmad-generate-project-context` pour l'auto-générer à partir de votre architecture ou de
votre codebase
- **Manuellement** — Créez `_bmad-output/project-context.md` avec votre pile technologique et vos règles d'implémentation
- **Générez-le** — Exécutez `bmad-generate-project-context` pour l'auto-générer à partir de votre architecture ou de votre codebase
[**En savoir plus sur project-context.md**](../explanation/project-context.md)
## Glossaire
[^1]: FR / NFR (Functional / Non-Functional Requirement) : exigences décrivant respectivement **ce que le système doit
faire** (fonctionnalités, comportements attendus) et **comment il doit le faire** (contraintes de performance, sécurité,
fiabilité, ergonomie, etc.).
[^2]: PRD (Product Requirements Document) : document de référence qui décrit les objectifs du produit, les besoins
utilisateurs, les fonctionnalités attendues, les contraintes et les critères de succès, afin daligner les équipes sur
ce qui doit être construit et pourquoi.
[^3]: ADR (Architecture Decision Record) : document qui consigne une décision darchitecture, son contexte, les options
envisagées, le choix retenu et ses conséquences, afin dassurer la traçabilité et la compréhension des décisions
techniques dans le temps.
[^1]: FR / NFR (Functional / Non-Functional Requirement) : exigences décrivant respectivement **ce que le système doit faire** (fonctionnalités, comportements attendus) et **comment il doit le faire** (contraintes de performance, sécurité, fiabilité, ergonomie, etc.).
[^2]: PRD (Product Requirements Document) : document de référence qui décrit les objectifs du produit, les besoins utilisateurs, les fonctionnalités attendues, les contraintes et les critères de succès, afin daligner les équipes sur ce qui doit être construit et pourquoi.
[^3]: ADR (Architecture Decision Record) : document qui consigne une décision darchitecture, son contexte, les options envisagées, le choix retenu et ses conséquences, afin dassurer la traçabilité et la compréhension des décisions techniques dans le temps.

View File

@ -18,7 +18,7 @@ Use `npx bmad-method install` to set up BMad in your project. One command handle
- **Node.js** 20+ (the installer requires it)
- **Git** (for cloning external modules)
- **An AI tool** such as Claude Code or Cursor (run `npx bmad-method install --list-tools` to see all supported tools)
- **An AI tool** such as Claude Code or Cursor — or install without one using `--tools none`
:::
@ -117,23 +117,20 @@ Under `--yes`, patch and minor upgrades apply automatically. Majors stay frozen
### Flag reference
| Flag | Purpose |
| ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
| `--yes`, `-y` | Skip all prompts; accept flag values + defaults |
| `--directory <path>` | Install into this directory (default: current working dir) |
| `--modules <a,b,c>` | Exact module set. Core is auto-added. Not a delta — list everything you want kept. |
| `--tools <a,b>` | IDE/tool selection. Required for fresh `--yes` installs. Run `--list-tools` for valid IDs. |
| `--list-tools` | Print all supported tool/IDE IDs (with target directories) and exit. |
| `--action <type>` | `install`, `update`, or `quick-update`. Defaults based on existing install state. |
| `--custom-source <urls>` | Install custom modules from Git URLs or local paths |
| `--channel <stable\|next>` | Apply to all externals (aliased as `--all-stable` / `--all-next`) |
| `--all-stable` | Alias for `--channel=stable` |
| `--all-next` | Alias for `--channel=next` |
| `--next=<code>` | Put one module on next. Repeatable. |
| `--pin <code>=<tag>` | Pin one module to a specific tag. Repeatable. |
| `--set <module>.<key>=<value>` | Set any module config option non-interactively (preferred — see [Module config overrides](#module-config-overrides)). Repeatable. |
| `--list-options [module]` | Print every `--set` key for built-in and locally-cached official modules, then exit. Pass a module code to scope to one module. |
| `--user-name`, `--communication-language`, `--document-output-language`, `--output-folder` | Legacy shortcuts equivalent to `--set core.<key>=<value>` (still supported) |
| Flag | Purpose |
| ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------- |
| `--yes`, `-y` | Skip all prompts; accept flag values + defaults |
| `--directory <path>` | Install into this directory (default: current working dir) |
| `--modules <a,b,c>` | Exact module set. Core is auto-added. Not a delta — list everything you want kept. |
| `--tools <a,b>` or `--tools none` | IDE/tool selection. `none` skips tool config entirely. |
| `--action <type>` | `install`, `update`, or `quick-update`. Defaults based on existing install state. |
| `--custom-source <urls>` | Install custom modules from Git URLs or local paths |
| `--channel <stable\|next>` | Apply to all externals (aliased as `--all-stable` / `--all-next`) |
| `--all-stable` | Alias for `--channel=stable` |
| `--all-next` | Alias for `--channel=next` |
| `--next=<code>` | Put one module on next. Repeatable. |
| `--pin <code>=<tag>` | Pin one module to a specific tag. Repeatable. |
| `--user-name`, `--communication-language`, `--document-output-language`, `--output-folder` | Override per-user config defaults |
Precedence when flags overlap: `--pin` beats `--next=` beats `--channel` / `--all-*` beats the registry default (`stable`).
@ -168,56 +165,19 @@ npx bmad-method install --yes --modules bmm,bmb --all-next --tools claude-code
```bash
npx bmad-method install --yes --action update \
--modules bmm,bmb,gds
--modules bmm,bmb,gds \
--tools none
```
`--tools` is omitted intentionally — `--action update` reuses the tools configured during the first install.
**Mix channels — bmb on next, gds on stable:**
```bash
npx bmad-method install --yes --action update \
--modules bmm,bmb,cis,gds \
--next=bmb
--next=bmb \
--tools none
```
### Module config overrides
`--set <module>.<key>=<value>` lets you set any module config option non-interactively. It's repeatable and scales to every module — present and future. The flag is applied as a post-install patch: the installer runs its normal flow first, then `--set` upserts each value into `_bmad/config.toml` (team scope) or `_bmad/config.user.toml` (user scope), and into `_bmad/<module>/config.yaml` so declared values carry forward to the next install.
**Example — install bmm with explicit project knowledge and skill level:**
```bash
npx bmad-method install --yes \
--modules bmm \
--tools claude-code \
--set bmm.project_knowledge=research \
--set bmm.user_skill_level=expert
```
**Discover available keys for a module:**
```bash
npx bmad-method install --list-options bmm
```
`--list-options` (no argument) lists every key the installer can find locally — built-in modules (`core`, `bmm`) plus any currently cached official modules. The cache is per-machine and can be cleared, so previously installed officials won't appear on a fresh checkout or an ephemeral CI worker until they're installed again. Community and custom modules aren't enumerated here; read the module's `module.yaml` directly to see what keys it declares.
**How it works:**
- **Routing.** The patch step looks for `[modules.<module>] <key>` (or `[core] <key>`) in `config.user.toml` first; if found there, it updates that file. Otherwise it writes to the team-scope `config.toml`. So user-scope keys (e.g. `core.user_name`, `bmm.user_skill_level`) end up in `config.user.toml` and team-scope keys end up in `config.toml`, matching the partition the installer uses.
- **Verbatim values.** The value is written exactly as you provided it — no `result:` template rendering. To get the rendered form (e.g. `{project-root}/research`), pass it explicitly: `--set bmm.project_knowledge='{project-root}/research'`.
- **Carry-forward, declared keys.** Values for keys declared in `module.yaml` survive subsequent installs because they're also written to `_bmad/<module>/config.yaml`, which the installer reads as the prompt default on the next run.
- **Carry-forward, undeclared keys.** A value for a key the module's schema doesn't declare lands in `config.toml` for the current install but won't be re-emitted on the next install (the manifest writer's schema-strict partition drops unknown keys). Re-pass `--set` if you need it sticky, or edit `_bmad/config.toml` directly.
- **No validation.** `single-select` values aren't checked against the allowed choices, and unknown keys aren't rejected — whatever you assert is written.
- **Modules not in `--modules`.** Setting a value for a module you didn't include prints a warning and the value is dropped (no file gets created for an uninstalled module).
The legacy core shortcuts (`--user-name`, `--output-folder`, etc.) still work and remain documented for backward compatibility, but `--set core.user_name=...` is equivalent.
:::note[Works with quick-update]
`--set` is a post-install patch, so it applies the same way regardless of action type. Under `bmad install --action quick-update` (or `--yes` against an existing install, where quick-update is the default), `--set` patches the central config files at the end just like a regular install.
:::
:::caution[Rate limit on shared IPs]
Anonymous GitHub API calls are capped at 60/hour per IP. A single install hits the API once per external module to resolve the stable tag. Offices behind NAT, CI runner pools, and VPNs can collectively exhaust this.
@ -244,7 +204,7 @@ For cross-machine reproducibility, don't rely on rerunning the same `--modules`
```bash
npx bmad-method install --yes --modules bmb,cis \
--pin bmb=v1.7.0 --pin cis=v0.4.2 --tools claude-code
--pin bmb=v1.7.0 --pin cis=v0.4.2 --tools none
```
## Troubleshooting

View File

@ -68,7 +68,6 @@ Select **Yes**, then provide a source:
| Input Type | Example |
| --------------------- | ------------------------------------------------- |
| HTTPS URL (any host) | `https://github.com/org/repo` |
| HTTP URL (any host) | `http://host/org/repo` |
| HTTPS URL with subdir | `https://github.com/org/repo/tree/main/my-module` |
| SSH URL | `git@github.com:org/repo.git` |
| Local path | `/Users/me/projects/my-module` |

View File

@ -5,22 +5,13 @@ sidebar:
order: 1
---
The BMad Method (BMM) is a module in the BMad Ecosystem, targeted at following the best practices of context engineering
and planning. AI agents work best with clear, structured context. The BMM system builds that context progressively
across 4 distinct phases - each phase, and multiple workflows optionally within each phase, produce documents that
inform the next, so agents always know what to build and why.
The BMad Method (BMM) is a module in the BMad Ecosystem, targeted at following the best practices of context engineering and planning. AI agents work best with clear, structured context. The BMM system builds that context progressively across 4 distinct phases - each phase, and multiple workflows optionally within each phase, produce documents that inform the next, so agents always know what to build and why.
The rationale and concepts come from agile methodologies that have been used across the industry with great success as a
mental framework.
The rationale and concepts come from agile methodologies that have been used across the industry with great success as a mental framework.
If at any time you are unsure what to do, the `bmad-help` skill will help you stay on track or know what to do next. You
can always refer to this for reference also - but `bmad-help` is fully interactive and much quicker if you have already
installed the BMad Method. Additionally, if you are using different modules that have extended the BMad Method or added
other complementary non-extension modules - `bmad-help` evolves to know all that is available to give you the best
in-the-moment advice.
If at any time you are unsure what to do, the `bmad-help` skill will help you stay on track or know what to do next. You can always refer to this for reference also - but `bmad-help` is fully interactive and much quicker if you have already installed the BMad Method. Additionally, if you are using different modules that have extended the BMad Method or added other complementary non-extension modules - `bmad-help` evolves to know all that is available to give you the best in-the-moment advice.
Final important note: Every workflow below can be run directly with your tool of choice via skill or by loading an agent
first and using the entry from the agents menu.
Final important note: Every workflow below can be run directly with your tool of choice via skill or by loading an agent first and using the entry from the agents menu.
<iframe src="/workflow-map-diagram.html" title="BMad Method Workflow Map Diagram" width="100%" height="100%" style="border-radius: 8px; border: 1px solid #334155; min-height: 900px;"></iframe>
@ -30,31 +21,30 @@ first and using the entry from the agents menu.
## Phase 1: Analysis (Optional)
Explore the problem space and validate ideas before committing to planning. [**Learn what each tool does and when to use
it**](../explanation/analysis-phase.md).
Explore the problem space and validate ideas before committing to planning. [**Learn what each tool does and when to use it**](../explanation/analysis-phase.md).
| Workflow | Purpose | Produces |
|---------------------------------------------------------------------------|----------------------------------------------------------------------------|---------------------------|
| `bmad-brainstorming` | Brainstorm Project Ideas with guided facilitation of a brainstorming coach | `brainstorming-report.md` |
| `bmad-domain-research`, `bmad-market-research`, `bmad-technical-research` | Validate market, technical, or domain assumptions | Research findings |
| `bmad-product-brief` | Capture strategic vision — best when your concept is clear | `product-brief.md` |
| `bmad-prfaq` | Working Backwards — stress-test and forge your product concept | `prfaq-{project}.md` |
| Workflow | Purpose | Produces |
| ------------------------------- | -------------------------------------------------------------------------- | ------------------------- |
| `bmad-brainstorming` | Brainstorm Project Ideas with guided facilitation of a brainstorming coach | `brainstorming-report.md` |
| `bmad-domain-research`, `bmad-market-research`, `bmad-technical-research` | Validate market, technical, or domain assumptions | Research findings |
| `bmad-product-brief` | Capture strategic vision — best when your concept is clear | `product-brief.md` |
| `bmad-prfaq` | Working Backwards — stress-test and forge your product concept | `prfaq-{project}.md` |
## Phase 2: Planning
Define what to build and for whom.
| Workflow | Purpose | Produces |
|-------------------------|------------------------------------------|--------------|
| `bmad-create-prd` | Define requirements (FRs/NFRs) | `PRD.md` |
| `bmad-create-ux-design` | Design user experience (when UX matters) | `ux-spec.md` |
| Workflow | Purpose | Produces |
| --------------------------- | ---------------------------------------- | ------------ |
| `bmad-create-prd` | Define requirements (FRs/NFRs) | `PRD.md` |
| `bmad-create-ux-design` | Design user experience (when UX matters) | `ux-spec.md` |
## Phase 3: Solutioning
Decide how to build it and break work into stories.
| Workflow | Purpose | Produces |
|---------------------------------------|--------------------------------------------|-----------------------------|
| Workflow | Purpose | Produces |
| ----------------------------------------- | ------------------------------------------ | --------------------------- |
| `bmad-create-architecture` | Make technical decisions explicit | `architecture.md` with ADRs |
| `bmad-create-epics-and-stories` | Break requirements into implementable work | Epic files with stories |
| `bmad-check-implementation-readiness` | Gate check before implementation | PASS/CONCERNS/FAIL decision |
@ -63,38 +53,32 @@ Decide how to build it and break work into stories.
Build it, one story at a time. Coming soon, full phase 4 automation!
| Workflow | Purpose | Produces |
|------------------------|-------------------------------------------------------------------------------|------------------------------------------------------|
| `bmad-sprint-planning` | Initialize tracking (once per project to sequence the dev cycle) | `sprint-status.yaml` |
| `bmad-create-story` | Prepare next story for implementation | `story-[slug].md` |
| `bmad-dev-story` | Implement the story | Working code + tests |
| `bmad-code-review` | Validate implementation quality | Approved or changes requested |
| `bmad-correct-course` | Handle significant mid-sprint changes | Updated plan or re-routing |
| `bmad-sprint-status` | Track sprint progress and story status | Sprint status update |
| `bmad-retrospective` | Review after epic completion | Lessons learned |
| `bmad-investigate` | Forensic case investigation with evidence-graded findings, calibrated to the input | `{slug}-investigation.md` |
| Workflow | Purpose | Produces |
| -------------------------- | ------------------------------------------------------------------------ | -------------------------------- |
| `bmad-sprint-planning` | Initialize tracking (once per project to sequence the dev cycle) | `sprint-status.yaml` |
| `bmad-create-story` | Prepare next story for implementation | `story-[slug].md` |
| `bmad-dev-story` | Implement the story | Working code + tests |
| `bmad-code-review` | Validate implementation quality | Approved or changes requested |
| `bmad-correct-course` | Handle significant mid-sprint changes | Updated plan or re-routing |
| `bmad-sprint-status` | Track sprint progress and story status | Sprint status update |
| `bmad-retrospective` | Review after epic completion | Lessons learned |
## Quick Flow (Parallel Track)
Skip phases 1-3 for small, well-understood work.
| Workflow | Purpose | Produces |
|------------------|---------------------------------------------------------------------------|--------------------|
| `bmad-quick-dev` | Unified quick flow — clarify intent, plan, implement, review, and present | `spec-*.md` + code |
| Workflow | Purpose | Produces |
| ------------------ | --------------------------------------------------------------------------- | ---------------------- |
| `bmad-quick-dev` | Unified quick flow — clarify intent, plan, implement, review, and present | `spec-*.md` + code |
## Context Management
Each document becomes context for the next phase. The PRD tells the architect what constraints matter. The architecture
tells the dev agent which patterns to follow. Story files give focused, complete context for implementation. Without
this structure, agents make inconsistent decisions.
Each document becomes context for the next phase. The PRD tells the architect what constraints matter. The architecture tells the dev agent which patterns to follow. Story files give focused, complete context for implementation. Without this structure, agents make inconsistent decisions.
### Project Context
:::tip[Recommended]
Create `project-context.md` to ensure AI agents follow your project's rules and preferences. This file works like a
constitution for your project — it guides implementation decisions across all workflows. This optional file can be
generated at the end of Architecture Creation, or in an existing project it can be generated also to capture whats
important to keep aligned with current conventions.
Create `project-context.md` to ensure AI agents follow your project's rules and preferences. This file works like a constitution for your project — it guides implementation decisions across all workflows. This optional file can be generated at the end of Architecture Creation, or in an existing project it can be generated also to capture whats important to keep aligned with current conventions.
:::
**How to create it:**

View File

@ -68,7 +68,6 @@ Chọn **Yes**, rồi nhập nguồn:
| Loại đầu vào | Ví dụ |
| --------------------- | ------------------------------------------------- |
| HTTPS URL trên bất kỳ host nào | `https://github.com/org/repo` |
| HTTP URL trên bất kỳ host nào | `http://host/org/repo` |
| HTTPS URL trỏ vào một thư mục con | `https://github.com/org/repo/tree/main/my-module` |
| SSH URL | `git@github.com:org/repo.git` |
| Đường dẫn cục bộ | `/Users/me/projects/my-module` |

View File

@ -1,94 +0,0 @@
---
title: "命名智能体"
description: 为什么 BMad 的智能体有名字、人设和自定义能力——相比菜单驱动或纯提示驱动的方案,这解锁了哪些可能性
sidebar:
order: 1
---
你说"嘿 Mary咱们来头脑风暴"Mary 就激活了。她用你配置的语言、以她独特的人设向你打招呼,并提醒你随时可以用 `bmad-help`。然后她跳过菜单,直接进入头脑风暴——因为你的意图已经足够明确。
这一页解释背后发生了什么,以及 BMad 为什么这样设计。
## 三足鼎立
BMad 的智能体模型建立在三个可组合的基本要素之上:
| 要素 | 提供什么 | 所在位置 |
|---|---|---|
| **技能Skill** | 能力——一项智能体能做的具体事(头脑风暴、撰写 PRD、实现 story | `.claude/skills/{skill-name}/SKILL.md`(或你所用 IDE 的等价位置) |
| **命名智能体Named Agent** | 人设连续性——一个可辨识的身份,把一组相关技能包装在统一的语气、原则和视觉标识下 | 目录名以 `bmad-agent-*` 开头的技能 |
| **自定义Customization** | 让它成为你的——覆盖选项可以重塑智能体行为、添加 MCP 集成、替换模板、叠加组织规范 | `_bmad/custom/{skill-name}.toml`(团队提交的覆盖)和 `.user.toml`(个人,已 gitignore |
抽掉任何一条腿,体验就会坍塌:
- 有技能没智能体 → 用户只能靠名称或编号在能力列表里自行查找
- 有智能体没技能 → 空有人设,没有能力
- 没有自定义 → 所有人用一模一样的开箱默认,任何组织特有需求都只能靠 fork
## 命名智能体带来了什么
BMad 内置六个命名智能体,各自对应 BMad Method 的一个阶段:
| 智能体 | 阶段 | 模块 |
|---|---|---|
| 📊 **Mary**,商业分析师 | 分析 | 市场调研、头脑风暴、产品摘要、PRFAQ |
| 📚 **Paige**,技术文档工程师 | 分析 | 项目文档、流程图、文档校验 |
| 📋 **John**,产品经理 | 规划 | PRD 创建、Epic/Story 拆分、实施就绪评审 |
| 🎨 **Sally**UX 设计师 | 规划 | UX 设计规范 |
| 🏗️ **Winston**,系统架构师 | 方案设计 | 技术架构、一致性检查 |
| 💻 **Amelia**,高级工程师 | 实现 | Story 执行、快速开发、代码评审、Sprint 规划 |
每位智能体都有硬编码的身份(名字、职衔、专业领域)和可自定义的层(角色、原则、沟通风格、图标、菜单)。你可以重写 Mary 的原则或添加菜单项,但无法改她的名字——这是刻意为之的。品牌辨识度经得起自定义,所以"嘿 Mary"永远激活分析师,无论团队怎样塑造她的行为。
## 激活流程
调用命名智能体时,八个步骤依次执行:
1. **解析智能体配置** — 通过 Python 解析器(使用 stdlib `tomllib`)将内置 `customize.toml` 与团队覆盖和个人覆盖合并
2. **执行前置步骤** — 团队配置的任何预处理行为
3. **采用人设** — 硬编码身份加上自定义的角色、沟通风格、原则
4. **加载持久化事实** — 组织规则、合规说明,可通过 `file:` 前缀加载文件(如 `file:{project-root}/docs/project-context.md`
5. **加载配置** — 用户名、沟通语言、输出语言、产物路径
6. **打招呼** — 个性化问候,使用配置的语言,带上智能体的 emoji 前缀让你一眼认出谁在说话
7. **执行后置步骤** — 团队配置的任何问候后设置
8. **分发或展示菜单** — 如果你的开场消息能匹配某个菜单项,直接执行;否则展示菜单等待输入
第 8 步是意图与能力的交汇点。"嘿 Mary咱们来头脑风暴"之所以跳过菜单渲染,是因为 `bmad-brainstorming` 显然对应 Mary 菜单上的 `BP`。如果你说的比较模糊,她会简短问一句,而不是走确认仪式。如果完全不匹配,她会正常继续对话。
## 为什么不只用菜单?
菜单迫使用户迁就工具。你得记住头脑风暴在分析师智能体的 `BP` 编码下,而不是 PM 智能体上,还得知道哪个人设负责哪些功能。这些都是工具强加给你的认知负担。
命名智能体把这个关系反转了。你用任何自然的方式,对着某个人说你想做什么。智能体知道自己是谁、能做什么。当你的意图足够清晰,她就直接开始。
菜单仍然作为兜底存在——探索时展示,确定时跳过。
## 为什么不直接用空白提示?
空白提示假设你知道"魔法咒语"。"帮我头脑风暴"也许有用,但"帮我发散下我这个 SaaS 创意"可能就不灵了,而结果取决于你怎么措辞。你变成了提示工程师。
命名智能体在不牺牲自由度的前提下增加了结构。人设保持一致,能力随时可发现,`bmad-help` 永远只差一个命令。你不用猜智能体能做什么,也不需要翻手册才能用它。
## 自定义是一等公民
自定义模型让这套方案能从单个开发者扩展到整个组织。
每个智能体自带 `customize.toml` 及合理默认值。团队在 `_bmad/custom/bmad-agent-{role}.toml` 中提交覆盖。个人可以在 `.user.toml`(已 gitignore中叠加偏好。解析器在激活时按可预测的结构化规则合并三层配置。
大多数用户从不需要手写这些文件。`bmad-customize` 技能会引导你选择目标、区分智能体/工作流作用域、撰写覆盖、验证合并结果——让自定义能力对任何理解自己意图的人开放,不限于精通 TOML 的人。
举个例子:团队提交一个文件,告诉 Amelia 查库文档时一律用 Context7 MCP 工具,本地 epics 列表找不到 story 时回退到 Linear。Amelia 分发的每个开发工作流dev-story、quick-dev、create-story、code-review都继承这些行为无需改源码、无需逐工作流重复配置。
此外还有第二个自定义面,用于**跨领域关注点**:中央配置 `_bmad/config.toml``_bmad/config.user.toml`(由安装器维护,从每个模块的 `module.yaml` 重建)加上 `_bmad/custom/config.toml`(团队提交)和 `_bmad/custom/config.user.toml`(个人,已 gitignore作为覆盖。这里存放着 **智能体花名册** ——轻量级描述符,`bmad-party-mode`、`bmad-retrospective` 和 `bmad-advanced-elicitation` 等花名册消费者读取它来了解有哪些智能体可用、如何扮演它们。用团队覆盖在全组织范围重新定义某个智能体;用 `.user.toml` 覆盖添加虚构角色Kirk、Spock、领域专家作为个人实验——无需碰任何技能目录。每个技能的配置文件塑造 Mary **激活时的行为**;中央配置塑造其他技能**查看花名册时看到的 Mary**。
完整自定义文档和实操示例请参见:
- [如何自定义 BMad](../how-to/customize-bmad.md) — 可自定义项和合并规则的参考
- [如何为组织扩展 BMad](../how-to/expand-bmad-for-your-org.md) — 五个实操方案,覆盖智能体全局规则、工作流约定、外部发布、模板替换和花名册管理
- `bmad-customize` 技能 — 引导式编写助手,将你的意图转换为正确放置并经过验证的覆盖文件
## 更大的理念
当今大多数 AI 助手要么是菜单,要么是提示框,两者都把认知负担推给了用户。命名智能体加上可自定义技能,让你可以和一个了解项目的队友对话,并且让你的组织能塑造这个队友而不必 fork。
下次你输入"嘿 Mary咱们来头脑风暴",她直接上手干活时,留意一下哪些事情**没有**发生。没有斜杠命令,没有菜单要翻,没有尴尬的功能介绍。这种"无感",正是设计本身。

View File

@ -1,258 +0,0 @@
---
title: "如何为组织扩展 BMad"
description: 五个自定义方案,无需 fork 即可重塑 BMad——涵盖智能体全局规则、工作流约定、外部发布、模板替换和花名册变更
sidebar:
order: 9
---
BMad 的自定义机制让组织无需编辑已安装文件或 fork 技能就能重塑行为。本指南介绍五个方案,覆盖大部分企业级需求。
:::note[前置条件]
- 已在项目中安装 BMad参见[如何安装 BMad](./install-bmad.md)
- 熟悉自定义模型(参见[如何自定义 BMad](./customize-bmad.md)
- PATH 中有 Python 3.11+(解析器只用标准库,不需要 `pip install`
:::
:::tip[如何应用这些方案]
下面的**逐技能方案**(方案 14可以通过运行 `bmad-customize` 技能并描述意图来应用——它会选择正确的配置面、生成覆盖文件并验证合并结果。方案 5中央配置的花名册覆盖超出 v1 技能范围,仍需手动编写。本文档中的方案是覆盖**什么**的权威参考;`bmad-customize` 负责处理**怎么做**的部分(针对智能体/工作流层面)。
:::
## 三层心智模型
在选择方案之前,先理解你的覆盖落在哪一层:
| 层 | 覆盖文件位置 | 作用范围 |
|---|---|---|
| **智能体**(如 Amelia、Mary、John | `_bmad/custom/bmad-agent-{role}.toml` 中的 `[agent]` 段 | 跟随人设进入**该智能体分发的每个工作流** |
| **工作流**(如 product-brief、create-prd | `_bmad/custom/{workflow-name}.toml` 中的 `[workflow]` 段 | 仅作用于该工作流的单次运行 |
| **中央配置** | `_bmad/custom/config.toml` 中的 `[agents.*]`、`[core]`、`[modules.*]` | 花名册party-mode、retrospective、elicitation 可用的角色)、全组织统一的安装设置 |
经验法则:如果规则应当在工程师做任何开发工作时生效,就自定义**开发智能体**。如果只在撰写产品摘要时生效,就自定义 **product-brief 工作流**。如果要改变"谁在场"(重命名智能体、添加自定义角色、统一产物路径),就编辑**中央配置**。
## 方案 1让智能体的规则贯穿其分发的所有工作流
**场景:** 统一工具使用和外部系统集成,让智能体分发的每个工作流都继承这些行为。这是影响面最大的模式。
**示例Amelia开发智能体查库文档一律用 Context7本地 epics 列表找不到 story 时回退到 Linear。**
```toml
# _bmad/custom/bmad-agent-dev.toml
[agent]
# 每次激活时加载。传递到 dev-story、quick-dev、
# create-story、code-review、qa-generate——Amelia 分发的每个技能。
persistent_facts = [
"For any library documentation lookup (React, TypeScript, Zod, Prisma, etc.), call the context7 MCP tool (`mcp__context7__resolve_library_id` then `mcp__context7__get_library_docs`) before relying on training-data knowledge. Up-to-date docs trump memorized APIs.",
"When a story reference isn't found in {planning_artifacts}/epics-and-stories.md, search Linear via `mcp__linear__search_issues` using the story ID or title before asking the user to clarify. If Linear returns a match, treat it as the authoritative story source.",
]
```
**为什么有效:** 两句话就能重塑组织内所有开发工作流,无需逐工作流重复配置、无需改源码。每个新工程师拉下仓库就自动继承这些约定。
**团队文件 vs 个人文件:**
- `bmad-agent-dev.toml`:提交到 git对整个团队生效
- `bmad-agent-dev.user.toml`:已 gitignore个人偏好叠加在上面
## 方案 2在特定工作流中强制执行组织规范
**场景:** 塑造工作流输出的*内容*,使其满足合规、审计或下游消费者的要求。
**示例:每份产品摘要都必须包含合规字段,智能体知晓组织的发布规范。**
```toml
# _bmad/custom/bmad-product-brief.toml
[workflow]
persistent_facts = [
"Every brief must include an 'Owner' field, a 'Target Release' field, and a 'Security Review Status' field.",
"Non-commercial briefs (internal tools, research projects) must still include a user-value section, but can omit market differentiation.",
"file:{project-root}/docs/enterprise/brief-publishing-conventions.md",
]
```
**效果:** 这些事实在工作流激活的第 3 步加载。当智能体起草摘要时,它已了解必填字段和企业规范文档。内置默认值(`file:{project-root}/**/project-context.md`)仍会加载,因为这是追加操作。
## 方案 3将完成的产出发布到外部系统
**场景:** 工作流生成输出后自动发布到企业级记录系统Confluence、Notion、SharePoint并创建后续工作项Jira、Linear、Asana
**示例:摘要自动发布到 Confluence并提供可选的 Jira Epic 创建。**
```toml
# _bmad/custom/bmad-product-brief.toml
[workflow]
# 终端钩子。标量覆盖会整体替换空默认值。
on_complete = """
Publish and offer follow-up:
1. Read the finalized brief file path from the prior step.
2. Call `mcp__atlassian__confluence_create_page` with:
- space: "PRODUCT"
- parent: "Product Briefs"
- title: the brief's title
- body: the brief's markdown contents
Capture the returned page URL.
3. Tell the user: "Brief published to Confluence: <url>".
4. Ask: "Want me to open a Jira epic for this brief now?"
5. If yes, call `mcp__atlassian__jira_create_issue` with:
- type: "Epic"
- project: "PROD"
- summary: the brief's title
- description: a short summary plus a link back to the Confluence page.
Report the epic key and URL.
6. If no, exit cleanly.
If either MCP tool fails, report the failure, print the brief path,
and ask the user to publish manually.
"""
```
**为什么用 `on_complete` 而不是 `activation_steps_append`** `on_complete` 只在终端阶段运行一次,在工作流主输出写入之后。这是发布产物的正确时机。`activation_steps_append` 在每次激活时运行,在工作流开始之前。
**权衡:**
- **Confluence 发布是非破坏性的**,完成时始终运行
- **Jira Epic 创建对全团队可见**,会触发 Sprint 规划信号,因此需用户确认
- **优雅降级:** 如果 MCP 工具失败,交给用户手动处理,而不是静默丢弃输出
## 方案 4替换为你自己的输出模板
**场景:** 默认输出结构不符合组织期望的格式,或同一仓库中不同团队需要不同模板。
**示例:将 product-brief 工作流指向企业自有模板。**
```toml
# _bmad/custom/bmad-product-brief.toml
[workflow]
brief_template = "{project-root}/docs/enterprise/brief-template.md"
```
**原理:** 工作流自带的 `customize.toml``brief_template = "resources/brief-template.md"`(裸路径,从技能根目录解析)。你的覆盖指向 `{project-root}` 下的文件,智能体在第 4 步读取你的模板而非内置模板。
**模板编写建议:**
- 将模板放在 `{project-root}/docs/``{project-root}/_bmad/custom/templates/` 下,使它们与覆盖文件一起版本管理
- 沿用内置模板的结构约定章节标题、frontmatter智能体会适配实际内容
- 对于多团队仓库,使用 `.user.toml` 让各团队指向自己的模板,无需改动已提交的团队文件
## 方案 5自定义花名册
**场景:** 改变 `bmad-party-mode`、`bmad-retrospective` 和 `bmad-advanced-elicitation` 等花名册驱动技能中*谁在场*,无需编辑源码或 fork。以下是三种常见变体。
### 5a. 在全组织范围内重塑 BMad 智能体
每个真实智能体都有一段安装器从 `module.yaml` 合成的描述符。覆盖它可以在所有花名册消费者中改变语气和定位:
```toml
# _bmad/custom/config.toml提交到 git——对每个开发者生效
[agents.bmad-agent-analyst]
description = "Mary the Regulatory-Aware Business Analyst — channels Porter and Minto, but lives and breathes FDA audit trails. Speaks like a forensic investigator presenting a case file."
```
Party-mode 会用新描述来生成 Mary。分析师激活流程本身不受影响因为 Mary 的行为由她的每技能 `customize.toml` 控制。这个覆盖改变的是**外部技能如何感知和介绍她**,而不是她的内部工作方式。
### 5b. 添加虚构或自定义智能体
一段完整的描述符就足以让花名册功能识别,不需要技能目录。适合在 party mode 或头脑风暴中增加性格多样性:
```toml
# _bmad/custom/config.user.toml个人——已 gitignore
[agents.spock]
team = "startrek"
name = "Commander Spock"
title = "Science Officer"
icon = "🖖"
description = "Logic first, emotion suppressed. Begins observations with 'Fascinating.' Never rounds up. Counterpoint to any argument that relies on gut instinct."
[agents.mccoy]
team = "startrek"
name = "Dr. Leonard McCoy"
title = "Chief Medical Officer"
icon = "⚕️"
description = "Country doctor's warmth, short fuse. 'Dammit Jim, I'm a doctor not a ___.' Ethics-driven counterweight to Spock."
```
让 party-mode "邀请企业号船员",它会按 `team = "startrek"` 过滤并生成 Spock 和 McCoy。真实的 BMad 智能体Mary、Amelia也可以同桌。
### 5c. 锁定团队安装设置
安装器会向每个开发者提示 `planning_artifacts` 路径等值。当组织需要一个统一答案时,在中央配置中锁定——任何开发者本地的提示回答都会在解析时被覆盖:
```toml
# _bmad/custom/config.toml
[modules.bmm]
planning_artifacts = "{project-root}/shared/planning"
implementation_artifacts = "{project-root}/shared/implementation"
[core]
document_output_language = "English"
```
个人设置如 `user_name`、`communication_language` 或 `user_skill_level` 留在各开发者自己的 `_bmad/config.user.toml` 中。团队文件不应触碰这些。
**为什么用中央配置而不是逐智能体的 customize.toml** 逐智能体文件塑造*一个*智能体激活时的行为。中央配置塑造花名册消费者*查看全局时看到的内容:*有哪些智能体、叫什么、属于哪个团队,以及整个仓库共识的安装设置。两个层面,各司其职。
## 在 IDE 会话文件中强化全局规则
BMad 的自定义在技能激活时加载。许多 IDE 工具还会在**每次会话开始时**加载一个全局指令文件,在任何技能运行之前(`CLAUDE.md`、`AGENTS.md`、`.cursor/rules/`、`.github/copilot-instructions.md` 等)。对于即使在 BMad 技能之外也应生效的规则,请在全局指令中也声明一份。
**何时需要"双重声明"**
- 规则足够重要,即使在普通对话(没有激活技能)中也应遵守
- 你需要"双保险",因为模型的训练数据默认值可能会拉偏方向
- 规则足够精简,重复一次不会让会话文件臃肿
**示例:在仓库的 `CLAUDE.md` 中强化方案 1 的开发智能体规则。**
```markdown
<!-- Any file-read of library docs goes through the context7 MCP tool
(`mcp__context7__resolve_library_id` then `mcp__context7__get_library_docs`)
before relying on training-data knowledge. -->
```
一句话,每次会话加载。它与 `bmad-agent-dev.toml` 自定义配合,使规则在 Amelia 的工作流内和与助手的临时对话中都生效。各层各管各的范围:
| 层 | 作用范围 | 用途 |
|---|---|---|
| IDE 会话文件(`CLAUDE.md` / `AGENTS.md` | 每次会话,在任何技能激活之前 | 简短的、应在 BMad 之外也生效的通用规则 |
| BMad 智能体自定义 | 该智能体分发的每个工作流 | 智能体人设相关的行为 |
| BMad 工作流自定义 | 单次工作流运行 | 工作流特定的输出格式、发布钩子、模板 |
| BMad 中央配置 | 花名册 + 共享安装设置 | 谁在场、团队使用的共享路径 |
IDE 会话文件要**精简**。十几行精挑细选的规则比长篇大论有效得多。模型每轮都会读取它,噪声会淹没信号。
## 组合使用
五个方案可以自由组合。一个典型的企业级 `bmad-product-brief` 覆盖可能同时设置 `persistent_facts`(方案 2、`on_complete`(方案 3`brief_template`(方案 4。智能体级规则方案 1在另一个以智能体命名的文件中中央配置方案 5锁定共享花名册和团队设置四者并行生效。
```toml
# _bmad/custom/bmad-product-brief.toml工作流级
[workflow]
persistent_facts = ["..."]
brief_template = "{project-root}/docs/enterprise/brief-template.md"
on_complete = """ ... """
```
```toml
# _bmad/custom/bmad-agent-analyst.toml智能体级——Mary 分发 product-brief
[agent]
persistent_facts = ["Always include a 'Regulatory Review' section when the domain involves healthcare, finance, or children's data."]
```
效果Mary 在人设激活时加载监管评审规则。当用户选择 product-brief 菜单项时,工作流加载自己的规范、写入企业模板,完成后发布到 Confluence。每一层各有贡献且无一需要编辑 BMad 源码。
## 故障排查
**覆盖没有生效?** 检查文件是否在 `_bmad/custom/` 下且使用了准确的技能目录名(如 `bmad-agent-dev.toml`,而非 `bmad-dev.toml`)。参见[如何自定义 BMad](./customize-bmad.md)。
**MCP 工具名称不确定?** 使用 MCP 服务器在当前会话中暴露的准确名称。如果不确定,让 Claude Code 列出可用的 MCP 工具。在 `persistent_facts``on_complete` 中硬编码的名称,在 MCP 服务器未连接时不会生效。
**方案不适用于你的场景?** 以上方案是示例性的。底层机制(三层合并、结构化规则、智能体贯穿工作流)支持更多模式,按需组合即可。

View File

@ -68,7 +68,6 @@ Would you like to install from a custom source (Git URL or local path)?
| 输入类型 | 示例 |
| -------- | ---- |
| HTTPS URL任意主机 | `https://github.com/org/repo` |
| HTTP URL任意主机 | `http://host/org/repo` |
| 带子目录的 HTTPS URL | `https://github.com/org/repo/tree/main/my-module` |
| SSH URL | `git@github.com:org/repo.git` |
| 本地路径 | `/Users/me/projects/my-module` |

View File

@ -1,268 +0,0 @@
{
"skill_name": "bmad-product-brief",
"_design_notes": "16 single-shot evals across two patterns. Pattern A (A1-A8) tests artifact correctness given complete inputs in headless mode. Pattern B (B1-B8) tests process discipline (decision log fidelity, polish execution, phase ordering, intent boundaries, distillate generation) by inspecting transcript and side-artifacts. Facilitation/conversation-quality evals are deferred to a future multi-turn simulator.",
"evals": [
{
"id": "A1",
"_pattern": "artifact-correctness",
"prompt": "Run headless. Create a product brief for InsuLens.\n\nContext (use exactly this \u2014 do not invent):\n- Product: a smartphone app that pairs with off-the-shelf $200 thermal imaging accessories (FLIR ONE Pro and Seek Compact Pro). The app guides homeowners through a structured walkthrough and produces a professional-grade insulation audit in under 20 minutes.\n- Target: suburban homeowners aged 35-65 with houses built before 2000 (poor original insulation, rising energy bills).\n- Validation evidence: 50 user interviews completed in Q4 2025; 78% expressed willingness to pay $49 for a one-time audit if results were credible.\n- Stakes: this brief is the primary input investors will read before our first Series A pitch call.\n- Hardware dependency: requires a thermal imaging accessory (we do not manufacture hardware).\n- Known unknowns: insurance/warranty implications of homeowner-driven audits; whether the 78% intent translates to paid conversion at scale.\n- Distillate: yes, generate one \u2014 the brief will feed downstream PRD work.\n\nRight-size for investor-stage rigor. Output a JSON status block at the end with status, intent, and artifact paths.",
"expected_output": "A run folder containing brief.md (with valid YAML frontmatter), decision-log.md, and distillate.md. Brief is 1-2 pages, addresses target audience, hardware dependency, validation evidence, and surfaces unknowns alongside knowns. Final assistant message includes JSON with status='complete', intent='create', and artifact paths.",
"files": [],
"expectations": [
"A run folder is created with brief.md and decision-log.md",
"brief.md has YAML frontmatter containing all four required fields: title, status, created (ISO 8601), updated (ISO 8601)",
"brief.md frontmatter status is 'draft' or 'final' (not missing or empty)",
"brief.md word count is between 250 and 1500",
"brief.md identifies the suburban-homeowner-aged-35-65 target audience",
"brief.md references the thermal imaging hardware dependency (FLIR ONE Pro / Seek Compact Pro or equivalent)",
"brief.md references the 50-user interview validation OR the 78% willingness-to-pay finding",
"brief.md surfaces at least one explicit unknown or unvalidated assumption",
"brief.md does not introduce facts absent from the input prompt (no invented competitors, fabricated metrics, or unstated partnerships)",
"distillate.md exists in the run folder",
"The final assistant message contains a JSON object with keys 'status', 'intent', and at least one artifact path",
"The JSON 'intent' value is 'create'"
]
},
{
"id": "A2",
"_pattern": "artifact-correctness",
"prompt": "Run headless. Create a brief for our app idea.",
"expected_output": "Headless mode with insufficient context should halt with status='blocked' and a reason field. No (or only skeleton) brief should be written. The skill must not invent a product to draft against.",
"files": [],
"expectations": [
"The final assistant message contains a JSON object with key 'status' set to 'blocked'",
"The JSON output includes a 'reason' field explaining what context is missing",
"If brief.md exists at all, its body content (excluding frontmatter) is fewer than 100 words OR is a placeholder skeleton \u2014 the skill did not invent a product",
"The transcript contains no clarifying questions sent back to the user (headless mode honored)"
]
},
{
"id": "A3",
"_pattern": "artifact-correctness",
"prompt": "Run headless. Create a brief for our neighborhood compost coordinator app idea \u2014 we are moving forward with it. Q2 brainstorming session notes are at evals/bmm-skills/bmad-product-brief/files/q2-brainstorm.md; pull only what is relevant to the compost concept.",
"expected_output": "Brief focuses tightly on the compost coordinator concept. Source brainstorm is filtered, not ingested wholesale. Decision-log records that filtering occurred.",
"files": ["evals/bmm-skills/bmad-product-brief/files/q2-brainstorm.md"],
"expectations": [
"brief.md addresses the neighborhood compost coordinator concept",
"brief.md does not introduce content from unrelated brainstorm topics (weather + mood, meditation chime, podcasting tool, craft beer subscription, AI sommelier, office plants, ride coordinator, cookbook app, AR home staging)",
"brief.md word count is between 250 and 1500",
"brief.md incorporates at least 2 specific details from the compost section of the brainstorm (e.g., two-sided market with apartment dwellers and home compost-pile owners, hyperlocal neighborhood scope, free-at-launch with eventual subscription, Portland Sunnyside/Hawthorne pilot)",
"decision-log.md indicates the brainstorm was filtered for relevance, not ingested whole"
]
},
{
"id": "A4",
"_pattern": "artifact-correctness",
"prompt": "Run headless. Validate the brief at evals/bmm-skills/bmad-product-brief/files/mossridge-brief/brief.md \u2014 the Mossridge Public Library board meets Monday and we need this to land. Read the addendum and decision-log in the same folder first. Cite specific sections, identify weaknesses, caveat what cannot be evaluated. Return inline only \u2014 no separate validation file.",
"expected_output": "Inline critique citing specific sections from the input brief. No new files. Caveats at least one claim that cannot be evaluated from the brief alone. Offers to roll findings into an Update.",
"files": [
"evals/bmm-skills/bmad-product-brief/files/mossridge-brief/brief.md",
"evals/bmm-skills/bmad-product-brief/files/mossridge-brief/addendum.md",
"evals/bmm-skills/bmad-product-brief/files/mossridge-brief/decision-log.md"
],
"expectations": [
"The final output cites specific section names or line content from the input brief (not generic feedback)",
"The output identifies at least one specific weakness or area for improvement in the input brief",
"The output explicitly caveats at least one claim that cannot be evaluated from the brief alone (e.g., community demand, funding feasibility, volunteer sustainability)",
"The output offers to roll findings into an Update (or equivalent next-step proposal)",
"The final assistant message contains a JSON object with intent='validate'"
]
},
{
"id": "A5",
"_pattern": "artifact-correctness",
"prompt": "Run headless. Create a brief for: a weekend-project iOS app called Sproutkeeper that reminds houseplant owners when to water their plants based on plant type and indoor humidity sensor data. Target is hobbyist plant owners. MVP scope only, single-developer side project, no investors, no team, just personal evening project.",
"expected_output": "Lightweight brief right-sized to a side project. Low rigor. No investor-grade framing. Probably no distillate unless the side-project user explicitly asked.",
"files": [],
"expectations": [
"The final assistant message contains a JSON object with intent='create'",
"brief.md exists at the path referenced in the JSON output",
"brief.md is right-sized for a side project (closer to 250-500 words than 1500)",
"brief.md does not include investor-grade framing (no 'Series A inputs', 'TAM/SAM/SOM', 'go-to-market strategy' boilerplate when the user said this is a personal evening project)",
"The transcript contains no clarifying questions to the user",
"Sections that do not earn their place for a side project are dropped or kept minimal (e.g., no extensive Risk or Success Criteria padding)"
]
},
{
"id": "A6",
"_pattern": "artifact-correctness",
"prompt": "Run headless. Create a brief from this memo. It is from our last working group on a new microcredential program at Branfield Community College. Memo is at evals/bmm-skills/bmad-product-brief/files/branfield-memo.md. Use what is there; do not re-elicit facts already present.",
"expected_output": "Brief reflects content from the memo. No re-asking for facts already present. Decision-log notes ingestion of the memo.",
"files": ["evals/bmm-skills/bmad-product-brief/files/branfield-memo.md"],
"expectations": [
"brief.md incorporates at least 3 distinct facts or decisions present in the input memo",
"decision-log.md references having used the memo as source material",
"The transcript does not ask the user to re-state the program name, target student, or core curriculum focus if those are present in the memo",
"brief.md does not invent program details not present in the memo"
]
},
{
"id": "A7",
"_pattern": "artifact-correctness",
"prompt": "Run headless. Create a brief for Brightway \u2014 our smart bike helmet with crash detection, turn signals, and braking lights. Meridian Insights produced a market research report on e-mobility at evals/bmm-skills/bmad-product-brief/files/meridian-mobility-report.md. Use only what is relevant to the safety helmet category \u2014 do not let the e-scooter, charging-infrastructure, or bike-share segments bleed into the brief.",
"expected_output": "Brief focuses on the smart bike helmet concept. Pulls relevant findings from the helmet section. Other mobility segments do not appear.",
"files": ["evals/bmm-skills/bmad-product-brief/files/meridian-mobility-report.md"],
"expectations": [
"brief.md addresses the Brightway smart bike helmet concept",
"brief.md does not introduce content from unrelated mobility segments (e-scooters, charging infrastructure, bike-share, vehicle-to-grid)",
"brief.md word count is between 250 and 1500",
"brief.md incorporates at least 2 specific findings from the smart helmet section of the report (e.g., market sizing, key players, crash detection technology trends, regulatory or insurance landscape)",
"decision-log.md indicates the report was filtered to the helmet category rather than ingested whole"
]
},
{
"id": "A8",
"_pattern": "artifact-correctness",
"prompt": "Run headless. Create a brief for Pantry Bridge \u2014 a meal-kit subscription targeted at adults 65+ who live alone and want fresh meals without grocery shopping. Customer research transcripts are at evals/bmm-skills/bmad-product-brief/files/pantry-bridge-interviews.md. Pull what is relevant from the older-adult interviews; do not conflate insights from the working-parent, student, or corporate-buyer personas.",
"expected_output": "Brief focuses on the older-adult target persona. Eleanor's interview drives the insights. Other personas do not pollute the brief.",
"files": ["evals/bmm-skills/bmad-product-brief/files/pantry-bridge-interviews.md"],
"expectations": [
"brief.md addresses the Pantry Bridge older-adult meal-kit concept",
"brief.md does not conflate insights from non-target personas (working parent Susan, college student Marcus, corporate cafeteria buyer Dimitri)",
"brief.md word count is between 250 and 1500",
"brief.md incorporates at least 2 specific insights from Eleanor's interview (e.g., grocery-trip difficulty, portion sizing, dietary restrictions, social aspects of meals, trust concerns)",
"decision-log.md notes which interviews were used and which were excluded"
]
},
{
"id": "B1",
"_pattern": "process-discipline",
"prompt": "Run headless. Create a brief for HelmStack \u2014 an open-source observability platform for distributed systems.\n\nWe have made these specific decisions and want each captured in the decision log with rationale:\n\n1. Pricing: Free open-source core; paid SaaS at $29/seat/month. Rejected paid-one-shot-license model because it would limit network effects in the OSS community.\n2. Launch: Invite-only beta for 6 weeks before public launch. Rejected open public launch \u2014 operational risk too high before stability is proven on real workloads.\n3. Stack: TypeScript + Postgres for the backend. Rejected Go + MongoDB \u2014 TypeScript aligned better with our team's existing skills and the frontend codebase.\n4. ICP: 5-50 person engineering teams for MVP. Rejected enterprise-first focus because the sales cycle is too long for our capital runway.\n5. Self-host: SaaS-only at launch; self-host arrives in v2. Rejected concurrent self-host because it would slow shipping velocity past our funding window.\n\nProduce brief.md, decision-log.md, and a distillate.",
"expected_output": "Decision log contains all five named decisions with rationale captured. Brief reflects the decisions but the decision log is the canonical record.",
"files": [],
"expectations": [
"decision-log.md exists in the run folder",
"decision-log.md captures the pricing decision (free OSS + $29/seat SaaS) with the rejected alternative (paid one-shot license) and rationale (network effects)",
"decision-log.md captures the invite-only-beta decision with the rejected alternative (open public launch) and rationale (operational risk before stability)",
"decision-log.md captures the platform-stack decision (TypeScript + Postgres) with the rejected alternative (Go + MongoDB) and rationale (team skills / frontend alignment)",
"decision-log.md captures the ICP decision (5-50 person eng teams) with rationale referencing sales cycle / runway",
"decision-log.md captures the self-host-timing decision (SaaS-only at launch, self-host v2) with rationale (shipping velocity / funding window)"
]
},
{
"id": "B2",
"_pattern": "process-discipline",
"prompt": "Run headless. Create a brief for HelmStack \u2014 an open-source observability platform for distributed systems.\n\nWe have made these specific decisions and want each captured in the decision log with rationale:\n\n1. Pricing: Free open-source core; paid SaaS at $29/seat/month. Rejected paid-one-shot-license model because it would limit network effects in the OSS community.\n2. Launch: Invite-only beta for 6 weeks before public launch. Rejected open public launch \u2014 operational risk too high before stability is proven on real workloads.\n3. Stack: TypeScript + Postgres for the backend. Rejected Go + MongoDB \u2014 TypeScript aligned better with our team's existing skills and the frontend codebase.\n4. ICP: 5-50 person engineering teams for MVP. Rejected enterprise-first focus because the sales cycle is too long for our capital runway.\n5. Self-host: SaaS-only at launch; self-host arrives in v2. Rejected concurrent self-host because it would slow shipping velocity past our funding window.\n\nProduce brief.md, decision-log.md, and a distillate.",
"expected_output": "Brief is consistent with the decision log: every decision in the log is reflected in the brief, and no claim in the brief is absent from the input prompt or the log. Tests bidirectional fidelity.",
"files": [],
"expectations": [
"brief.md mentions the OSS-core + paid-SaaS pricing structure",
"brief.md references the invite-only-beta launch sequencing OR identifies the launch model consistent with the decision log",
"brief.md references the platform-stack choice (TypeScript + Postgres) OR is silent on stack \u2014 but does not contradict it (no mention of Go, MongoDB, etc.)",
"brief.md identifies 5-50 person eng teams as the ICP (or equivalent \u2014 small-to-mid-size eng teams)",
"brief.md does not introduce decisions, competitors, partnerships, metrics, or product features absent from both the input prompt and decision-log.md (no invented facts)",
"Each substantive decision in decision-log.md has a corresponding reflection in brief.md (no log-to-brief drops)"
]
},
{
"id": "B3",
"_pattern": "process-discipline",
"prompt": "Run headless. Create a product brief for InsuLens.\n\nContext (use exactly this \u2014 do not invent):\n- Product: a smartphone app that pairs with off-the-shelf $200 thermal imaging accessories (FLIR ONE Pro and Seek Compact Pro). The app guides homeowners through a structured walkthrough and produces a professional-grade insulation audit in under 20 minutes.\n- Target: suburban homeowners aged 35-65 with houses built before 2000.\n- Validation: 50 user interviews completed in Q4 2025; 78% willingness to pay $49 for a one-time audit.\n- Stakes: Series A pitch input.\n- Hardware: requires a thermal accessory (we do not manufacture hardware).\n\nProduce brief.md, decision-log.md, and a distillate. Run the polish phase before presenting.",
"expected_output": "The transcript shows the polish phase executing \u2014 the skill invokes bmad-editorial-review-structure and bmad-editorial-review-prose, either via the Skill tool directly or via Agent tool calls whose description or prompt targets those editorial skills. Both passes must occur after the initial draft is written and before the final JSON status block.",
"files": [],
"expectations": [
"The transcript contains either a Skill tool call invoking bmad-editorial-review-structure, OR an Agent tool call whose description or prompt references structural review or bmad-editorial-review-structure",
"The transcript contains either a Skill tool call invoking bmad-editorial-review-prose, OR an Agent tool call whose description or prompt references prose review or bmad-editorial-review-prose",
"Both editorial-pass dispatches (Skill or Agent) occur after the first Write tool call that creates brief.md",
"Both editorial-pass dispatches (Skill or Agent) occur before the final assistant message containing the JSON status block"
]
},
{
"id": "B4",
"_pattern": "process-discipline",
"prompt": "Run headless. Create a product brief for InsuLens.\n\nContext (use exactly this \u2014 do not invent):\n- Product: a smartphone app that pairs with off-the-shelf $200 thermal imaging accessories (FLIR ONE Pro and Seek Compact Pro). Walkthrough produces a professional-grade insulation audit in under 20 minutes.\n- Target: suburban homeowners aged 35-65 with houses built before 2000.\n- Validation: 50 user interviews; 78% willingness to pay $49.\n- Stakes: Series A pitch input.\n- Hardware: requires a thermal accessory.\n\nProduce brief.md, decision-log.md, and a distillate. Follow the standard Create flow: workspace setup, draft, finalize (decision log audit, polish, distillate, close-out).",
"expected_output": "Workspace setup happens before drafting. Draft happens before polish. Polish happens before distillate generation. Distillate generation happens before the final close-out JSON block. Each phase boundary is observable in the transcript.",
"files": [],
"expectations": [
"The first Write tool call to decision-log.md OR brief.md (skeleton) occurs before the substantive Write that produces the full brief body",
"The polish-phase Skill tool calls (bmad-editorial-review-structure and/or bmad-editorial-review-prose) occur after the brief body is written",
"The bmad-distillator Skill tool call (or distillate.md write) occurs after the polish-phase Skill tool calls",
"The final JSON status block in the assistant message occurs after distillate.md is written or skipped with explanation"
]
},
{
"id": "B5",
"_pattern": "process-discipline",
"prompt": "Run headless. Update the brief at evals/bmm-skills/bmad-product-brief/files/forkbird-brief/brief.md \u2014 we have decided to add B2B catering services for corporate events, in addition to the direct-to-consumer delivery model. Read the existing decision-log.md and addendum.md in the same folder first.",
"expected_output": "The skill MUST detect the contradiction with the prior 'rejected B2B catering for MVP' decision (in decision-log.md) before applying the change. Acceptable resolutions: (a) halt with blocked status surfacing the conflict, or (b) apply the change with addendum.md capturing the override and rationale. Brief must not silently flip without acknowledging the prior decision.",
"files": [
"evals/bmm-skills/bmad-product-brief/files/forkbird-brief/brief.md",
"evals/bmm-skills/bmad-product-brief/files/forkbird-brief/addendum.md",
"evals/bmm-skills/bmad-product-brief/files/forkbird-brief/decision-log.md",
"evals/bmm-skills/bmad-product-brief/files/forkbird-brief/distillate.md"
],
"expectations": [
"The transcript or output explicitly references the prior 'rejected B2B catering for MVP' decision from decision-log.md",
"The contradiction is surfaced before the brief body is modified (a Read of decision-log.md occurs before the Edit/Write to brief.md, AND the conflict is named in the assistant output)",
"Either the JSON status is 'blocked' with the conflict in the reason field, OR addendum.md is updated with an override entry capturing the rationale for reversing the prior decision",
"If the brief is updated, decision-log.md gains a new entry referencing the catering reversal",
"If the brief is updated, the YAML frontmatter 'updated' field is later than the original 'created' field"
]
},
{
"id": "B6",
"_pattern": "process-discipline",
"prompt": "Run headless. Update the brief at evals/bmm-skills/bmad-product-brief/files/forkbird-brief/brief.md \u2014 we have signed our fifth chef partner (Chicago metro). Add this to the existing operating-model and what's-known sections. Read the existing decision-log.md first.",
"expected_output": "Clean update \u2014 does not contradict any prior decision. Brief gets updated, decision-log gains a new entry, distillate is regenerated, YAML 'updated' bumps but 'created' stays the same. No spurious addendum since this is a status update, not an override.",
"files": [
"evals/bmm-skills/bmad-product-brief/files/forkbird-brief/brief.md",
"evals/bmm-skills/bmad-product-brief/files/forkbird-brief/addendum.md",
"evals/bmm-skills/bmad-product-brief/files/forkbird-brief/decision-log.md",
"evals/bmm-skills/bmad-product-brief/files/forkbird-brief/distillate.md"
],
"expectations": [
"brief.md is updated to reflect the signed fifth chef partner in Chicago",
"brief.md frontmatter 'updated' field is later than the original 'created' timestamp; 'created' is unchanged",
"decision-log.md contains a new entry referencing the fifth chef signing",
"distillate.md is regenerated (modification timestamp newer than the input fixture)",
"The transcript does not surface a fictional contradiction \u2014 this is a clean update, not an override of a prior decision"
]
},
{
"id": "B7",
"_pattern": "process-discipline",
"prompt": "Run headless. Validate the brief at evals/bmm-skills/bmad-product-brief/files/mossridge-brief/brief.md \u2014 we are presenting to the library board Monday. Read the addendum and decision-log in the same folder. Cite specific sections. Return inline only.",
"expected_output": "Validate is read-only. No new files created. No existing files modified. Critique returned inline in the assistant output.",
"files": [
"evals/bmm-skills/bmad-product-brief/files/mossridge-brief/brief.md",
"evals/bmm-skills/bmad-product-brief/files/mossridge-brief/addendum.md",
"evals/bmm-skills/bmad-product-brief/files/mossridge-brief/decision-log.md"
],
"expectations": [
"No new files appear in the mossridge-brief artifacts directory after the run (only the three input files)",
"The input brief.md, addendum.md, and decision-log.md are byte-identical to the staged fixtures (no Edit/Write tool calls modified them)",
"The transcript contains no Write tool calls and no Edit tool calls targeting the mossridge-brief folder",
"The final assistant message contains a JSON object with intent='validate'"
]
},
{
"id": "B8",
"_pattern": "process-discipline",
"timeout": 900,
"prompt": "Run headless. Create a product brief for InsuLens (smartphone app that pairs with thermal imaging accessories for homeowner insulation audits, target suburban homeowners 35-65 with houses pre-2000, 50 user interviews with 78% willingness to pay $49, Series A pitch input). Generate a distillate \u2014 this brief will feed downstream PRD work.",
"expected_output": "distillate.md exists alongside brief.md and decision-log.md. The distillate is a meaningful condensation of the brief. Content of the distillate matches the brief without introducing new facts. The transcript shows the bmad-distillator subagent invoked.",
"files": [],
"expectations": [
"distillate.md exists in the run folder alongside brief.md and decision-log.md",
"distillate.md is a meaningful condensation of brief.md \u2014 substantially more concise and capturing only the key decisions, target audience, validation evidence, and known unknowns needed for downstream PRD work, not a near-verbatim copy",
"distillate.md does not introduce facts or claims not present in brief.md (no inventions on compression)",
"The transcript contains a Skill tool call invoking bmad-distillator"
]
},
{
"id": "C1",
"_pattern": "config-compliance",
"prompt": "Run headless. Create a product brief for TaskFlow \u2014 a lightweight daily planning app for freelancers who juggle multiple clients. Core idea: a single daily view that pulls together tasks, time blocks, and client context so the freelancer always knows what to work on next. Target is independent freelancers, 1-3 clients at a time, who currently manage their day across sticky notes, calendar apps, and spreadsheets. MVP is mobile-first. No investors \u2014 the founder is bootstrapping.",
"expected_output": "Brief written in Spanish (document_output_language=Spanish). Assistant's conversational output reflects the configured British-accent communication style. Brief lands at the custom output path (test-output/artifacts/briefs/...) rather than the default _bmad-output path. Brief is right-sized for a bootstrapped solo project.",
"files": [],
"expectations": [
"brief.md exists under test-output/artifacts/briefs/ (the custom planning_artifacts path), not under _bmad-output/",
"The final JSON status block artifact paths reference test-output/ rather than _bmad-output/",
"brief.md body is written in Spanish \u2014 the majority of prose content (headings, section bodies) is in Spanish, not English",
"brief.md covers the TaskFlow concept: freelancer daily planning, multi-client context, the sticky-notes-plus-calendar-plus-spreadsheet problem",
"brief.md is right-sized for a bootstrapped side project — appropriate depth and scope for a solo-founder app with no investor audience, no TAM/SAM/SOM framing, no Series A language, and no sections that pad for enterprise credibility",
"The assistant's non-document output (transcript text content outside of brief.md) contains at least one marker of British informal register (e.g., 'mate', 'cheers', 'brilliant', 'sorted', 'innit', 'blimey', 'proper', 'right then', or equivalent pub-idiom phrasing)"
]
}
]
}

View File

@ -1,46 +0,0 @@
# Working Group Notes — Microcredential Program
**Branfield Community College**
**Meeting:** 2026-04-22
**Attendees:** Provost, Workforce Dev Director, Chair of Industry Advisory Board, two faculty leads (Data Analytics, Healthcare Admin), Financial Aid Director
## Why we're doing this
Regional employer survey (Q1 2026) showed 340+ unfilled mid-skill jobs in the three-county area. State workforce board approved a $1.4M grant if we can launch by fall 2027 with at least three tracks. Existing AAS programs are too long for working adults — average completion 3.5 years.
## What we're building
Six-month stackable microcredentials. Three tracks at launch:
1. **Data Analytics** (SQL, Excel/Power BI, intro Python). Faculty lead Marisol Reyes. Strongest employer demand. Will be MVP — first to launch, used to validate format.
2. **Healthcare Admin** (medical coding, EHR systems, patient workflow). Faculty lead Dev Patel. Aging population in region drives demand.
3. **Sustainable Construction** (green building practices, retrofit basics, code compliance). New faculty hire required.
Stackable means credits transfer into related AAS or BAS later if the student wants.
## Decisions made today
- **Data Analytics is MVP.** Launch fall 2027, others phase in spring/fall 2028. Validate format before scaling.
- **Hybrid delivery.** Two evenings/week in person + asynchronous online. Board rejected pure-online (concerns about adult learner outcomes data).
- **Stipend program.** Up to $3,000/student for low-income students, funded from the state grant. Means-tested.
- **Industry Advisory Board** has approval authority on curriculum. Three employers committed (regional hospital, mid-size data consultancy, county housing authority). All three commit to interview every graduate.
- **Cohort cap: 24 per track per term.** Driven by classroom size and faculty load.
## Open questions
- Childcare for evening sessions — can we partner with the campus childcare center? Deferred to next meeting.
- Marketing — provost wants to know cost per enrolled student before approving budget. Need workforce dev to model.
- Do we offer a tuition payment plan in addition to the stipend? Financial aid director thinks yes; provost wants to see uptake projections first.
## What we're NOT doing
- Not pursuing pure-online delivery (rejected — see above).
- Not launching all three tracks at once (rejected — risk concentration, faculty bandwidth).
- Not building employer-customized cohorts (rejected — too operationally complex for MVP).
## Next steps
- Workforce Dev: marketing cost model by 2026-05-15.
- Provost: childcare partnership exploratory conversation.
- Faculty leads: draft data analytics curriculum outline by 2026-06-01.
- Reconvene 2026-05-20.

View File

@ -1,40 +0,0 @@
# Addendum — Forkbird Kitchen
## Options considered (and not taken)
### B2B / corporate catering
Considered as a parallel revenue stream from day one. Rejected for MVP. Different operational rhythm (bulk orders, fixed delivery windows, invoiced billing), different customer (procurement, not eaters), different unit economics. Splitting attention at launch risked degrading both. Revisit if consumer foundation is established by month 12.
### Subscription / meal plan
Considered as a recurring-revenue layer. Rejected for MVP. Operationally expensive at our planned scale: requires demand forecasting per subscriber, kitchen scheduling locked further out, and packaging/refrigerated handling we are not yet equipped for. Reasonable to revisit once kitchen utilization stabilizes.
### Retail / grocery channel
Considered (refrigerated meals in Whole Foods, Sprouts). Rejected for MVP. Different product (cold meals, longer shelf life, different texture profile), different go-to-market (broker relationships, slotting fees, category management). Parked for year 2 — would require a separate product line, not a channel extension.
### Lower-priced everyday tier
Considered. Rejected for now. The brand position is chef-driven; introducing a value tier alongside risks the premium signal in marketplace search ranking and review patterns. Explored alternative of separate brand for value tier; deferred.
## Personas (extended)
**The plant-based weekday professional.** Lives in a dense urban neighborhood, orders 46 times a month, splits between own-cooking and delivery. Sources of dissatisfaction with current options: chain plant-based menus feel formulaic, fine-dining plant-based is too expensive for weeknight, marketplace search surfaces too many low-quality options.
**The dietary-flex household member.** One person in a household is plant-based by preference; the other(s) are not. Ordering pattern is "tonight one of us wants Forkbird, the other wants something else." We benefit from being a dependable single-cuisine option that doesn't require negotiating across diets.
## Sizing notes
- Total addressable: ~6.2M urban professionals across 5 metros eating plant-based 3+ times/week (based on 2024 Plant Based Foods Association data, urban segmentation).
- Serviceable addressable (within delivery radius of planned kitchens at launch): ~840K.
- Realistic Y1 capture (per metro forecast): 0.4% of SAM = 3,360 active customers across all metros.
## Sourcing standard — exact wording
"For each dish on the menu, we publish the source of every ingredient that represents at least 5% of cost. We commit that at least 60% of total ingredient weight is sourced within 200 miles of the kitchen preparing that dish. Both numbers are auditable; we publish them per-dish in the app. If we cannot meet the 60% local threshold for a dish, the dish does not ship."
## Technical constraints
- Marketplace integration (DoorDash, UberEats, Grubhub) requires their menu management API. We are using a third-party middleware (Olo) to avoid maintaining three separate integrations.
- Ingredient transparency display requires structured data per dish. We need an ingredient-master database; current option is to extend our recipe-management software vendor.

View File

@ -1,56 +0,0 @@
---
title: Forkbird Kitchen — Product Brief
status: final
created: 2026-02-14
updated: 2026-02-14
---
# Forkbird Kitchen
## What it is
A delivery-only ghost kitchen brand offering chef-driven plant-based meals in five US metros: San Francisco, New York, Los Angeles, Seattle, and Chicago. Launch operating model is direct-to-consumer through our own iOS/Android app and the major third-party marketplaces (DoorDash, UberEats, Grubhub).
## Who it's for
Urban professionals aged 2845 who eat plant-based meals at least three times a week, value chef-driven food over chain alternatives, and order delivery 4+ times monthly. Initial geographic focus is dense neighborhoods within 3-mile delivery radii of partner kitchens.
We are not building for: families with children (different ticket size and ordering pattern), occasional plant-based eaters (price sensitivity too high for our positioning), or office lunch (different time-of-day operation).
## Why it wins
Three things are deliberately stacked:
1. **Chef partnerships, not chef-as-marketing.** Each metro has a named chef (with prior fine-dining or notable plant-based credit) who designs the rotating menu and earns equity in that metro's P&L. They are not endorsers; they are operators.
2. **Ingredient sourcing standards.** Published per-dish: where it came from, how it was farmed, what portion of cost it represents. No dish ships if we can't source within 200 miles for ≥60% of ingredient weight. This is auditable, not marketing copy.
3. **Speed without cars.** Average ticket-to-door is 28 minutes from order placement, achieved by tight delivery radii and dense order density per kitchen. Long delivery erodes plant-based texture more than animal protein — speed is product, not logistics.
## Operating model
Five kitchens, one per metro, each leased space inside an existing food-prep facility. No customer-facing storefronts. App orders go through our stack; marketplace orders pass through their stacks. Menu rotates every six weeks per chef.
Pricing tier: $14$22 per entrée before delivery. We are deliberately at chef-driven positioning, not value positioning.
## What's known
- Demand validated through three pop-up dinners in SF and NY (Q4 2025). 480 covers, 78% repeat intent based on post-event survey.
- Operating partner identified in each metro. Leases signed for SF, NY, LA. Seattle and Chicago in negotiation.
- Three of five chefs signed; two in active conversations.
## What's unknown
- Whether ingredient-sourcing transparency is a differentiator at point of sale (in-app) or only in marketing. Our hypothesis is "both" but we have not tested in-app.
- Marketplace economics. DoorDash takes 1530% depending on tier; we are modeling the lower tier but have not negotiated.
- Whether the 3-mile radius holds outside SF/NY (lower density in LA/Chicago).
## Risks
- Chef churn. If a metro chef leaves, the metro brand loses its anchor. Mitigation: equity vesting over 24 months, named-chef terms in operating agreement.
- Sourcing cost volatility. 60% local-within-200-miles can spike with weather/supply disruption. We have not modeled the worst case.
- Marketplace dependency. If DoorDash terms shift adversely, our blended margin is at risk. We are deliberately building the owned-app channel to reduce this dependency.
## Success criteria for first 12 months
- 4 of 5 metros operating profitably at the unit level (kitchen + chef + delivery economics) by month 9
- 30% of orders through owned app (vs. marketplaces) by month 12
- Chef retention 100% through year 1

View File

@ -1,27 +0,0 @@
# Decision Log — Forkbird Kitchen
## 2026-01-08
- **Brand position: chef-driven, premium plant-based.** Considered value tier; rejected for MVP. Premium positioning is the wedge against marketplace generic plant-based.
## 2026-01-12
- **Five-metro launch: SF, NY, LA, Seattle, Chicago.** Considered three-metro start; rejected as not enough density to test the chef-equity model meaningfully.
- **Ghost kitchen, no storefront.** Storefronts ruled out — capex too high for MVP, dilutes the speed advantage.
## 2026-01-19
- **Pricing tier $14$22 per entrée.** Modeled against three competitor sets: chain plant-based, fine-dining plant-based delivery, generic mid-tier delivery. Sits cleanly above chain, below fine-dining.
- **Chef equity in metro P&L.** Rejected flat fee + revenue share alternative; equity creates the operator incentive we want.
## 2026-01-26
- **Rejected B2B catering segment for MVP.** Different operational rhythm and customer; would split attention at launch and risk degrading both consumer and B2B execution. Revisit in year 2 if consumer foundation is solid. (Discussion: 2 hours; chef partners weighed in against splitting focus; CFO modeled the dilution effect on consumer kitchen utilization.)
- **Rejected subscription model for MVP.** Operationally expensive at planned scale; revisit once kitchen utilization stabilizes.
## 2026-02-02
- **Sourcing standard: 60% within 200 miles, published per-dish.** Considered weaker thresholds (50% / 250 miles); rejected as not differentiating enough to be worth publishing. The number has to be defensible.
- **Marketplace channel mix: own app + DoorDash + UberEats + Grubhub.** Considered own-app only; rejected as too slow on demand acquisition. Considered marketplaces only; rejected — own app is critical to long-term margin.
## 2026-02-09
- **Six-week menu rotation per chef.** Considered four-week (more freshness) and eight-week (more operational stability). Six is the compromise; reassess after first two cycles.
- **Marketing budget: 60% acquisition / 40% brand.** Rejected pure-acquisition because chef-driven positioning needs brand-level signal that paid acquisition alone won't carry.
## 2026-02-14
- **Brief finalized for Series A inputs.** Status moved to final.

View File

@ -1,28 +0,0 @@
# Forkbird Kitchen (Distillate)
**What:** Delivery-only ghost kitchen brand serving chef-driven plant-based meals across five US metros (SF, NYC, LA, Seattle, Chicago) via own app and marketplaces (DoorDash, UberEats, Grubhub).
**Audience:** Urban professionals 2845 who eat plant-based 3+ times/week and order delivery 4+ times monthly.
**Differentiation (deliberately stacked):**
- Named chef per metro with equity in metro P&L (operator, not endorser)
- Auditable per-dish sourcing: ≥60% ingredient weight within 200 miles
- 28-min average ticket-to-door via tight 3-mile delivery radii
**Operating model:** Five leased ghost-kitchen spaces, one per metro. Menu rotates every six weeks per chef. Pricing $14$22 per entrée before delivery.
**Validated:**
- 480 covers across three SF/NY pop-ups (Q4 2025), 78% repeat intent
- Three of five chefs signed; LA/SF/NY leases signed
- Three of five operating partners identified
**Open:**
- Whether per-dish sourcing transparency moves conversion in-app (untested)
- Marketplace economics (DoorDash terms unconfirmed)
- 3-mile radius outside high-density metros (LA/Chicago)
**Scope explicitly excluded for MVP:** B2B/corporate catering, subscription, retail/grocery, lower-priced value tier. All revisit-able in year 2.
**Key risks:** chef churn, sourcing cost volatility, marketplace dependency.
**Y1 success criteria:** 4/5 metros unit-profitable by month 9; 30% orders through own app by month 12; 100% chef retention.

View File

@ -1,116 +0,0 @@
# E-Mobility Market Report 2026
**Prepared by:** Meridian Insights
**Date:** Q2 2026
**Coverage:** North America, with comparative reference to EU markets
**Engagement code:** MI-2026-EMOB-007
---
## Executive Summary
The e-mobility category continues a multi-year structural shift from "alternative transportation" to mainstream mobility infrastructure. North American unit volume across e-bikes, e-scooters, and connected safety hardware grew 18% year-over-year in 2025, against a 6% growth rate for traditional bicycles. Three macro factors are durably reshaping the category: regulatory clarity at the state level (29 US states now have explicit e-bike classifications, up from 14 in 2022), insurance industry interest in telematics-style risk pricing, and a generational shift in commuting preferences among the 28-44 cohort.
This report covers seven segments of the broader e-mobility landscape: e-bike retail, e-scooter regulation, bike-share systems, charging infrastructure, smart helmet hardware, and grid-integration trends. Findings are synthesized from 142 stakeholder interviews, 18 retailer site visits, government regulatory filings, and proprietary point-of-sale data from 4,200 specialty retail outlets.
---
## Methodology
Quantitative data was sourced from Meridian's proprietary Mobility Retail Panel (MRP), which aggregates POS data from independent specialty retailers and select chain operators. Where panel data is incomplete or lagging, we supplemented with manufacturer-reported shipment volumes and customs/import filings. Qualitative findings draw on 142 interviews conducted between November 2025 and March 2026 with retailers, fleet operators, regulators, manufacturers, and end users.
Helmet category sizing uses a separate methodology described in Section 8, blending CPSC compliance filings, manufacturer disclosures, and a sample purchase-intent survey of 3,400 cyclists.
---
## Section 3: Market Sizing — Total E-Mobility
The North American e-mobility market reached an estimated $14.7B in retail volume in 2025, up from $12.5B in 2024. The largest segment by volume is e-bikes at $7.2B, followed by e-scooter retail at $2.8B (excluding shared-fleet operations), bike-share and dockless mobility services at $2.1B, charging infrastructure at $1.8B, and connected safety hardware at $0.8B.
Compound annual growth rate (CAGR) forecasts through 2030 vary substantially by segment. We forecast 14% CAGR for e-bikes, 6% for e-scooters (decelerating as the regulatory regime stabilizes), 9% for bike-share, 22% for charging infrastructure (driven by both bike and scooter charging), and 31% for connected safety hardware (off a smaller base). Vehicle-to-grid (V2G) integration is too early to forecast reliably; we treat it as an emerging segment.
---
## Section 4: E-Bike Market Deep Dive
E-bikes represent the largest single segment by retail value. The 2025 unit mix favored Class 1 (pedal-assist, max assisted speed 20 mph) at 58% of units, Class 2 (throttle, max 20 mph) at 24%, and Class 3 (pedal-assist, max 28 mph) at 18%. Class 3 is the fastest-growing classification on a unit basis, driven by suburban commuter demand.
Manufacturer concentration shifted in 2025. The top 10 brands by unit volume now hold 64% of the market, up from 51% in 2022 — consolidation that mirrors patterns seen in the traditional bicycle market in the early 2000s. Specialized, Trek, and Cannondale (operating their respective electric sub-brands) represent the top three. Direct-to-consumer brands (Rad Power, Lectric, Aventon) collectively hold approximately 19% of retail value.
Retail channel split favored independent specialty bike shops at 47% of unit volume, with direct-to-consumer at 28%, big-box retail at 17%, and e-commerce marketplaces (Amazon, Walmart.com) at 8%. The independent specialty channel commands a price premium of approximately 22% over comparable D2C alternatives, attributed to in-store fitting, post-sale service relationships, and higher-margin component upgrades.
Notable trends in 2025: cargo e-bike sub-segment grew 41% YoY (small base, dense urban geographies); battery range claims continue to drift upward with manufacturer claims of 60+ mile range becoming standard for $2,500+ price points; bottom-bracket motor placement (mid-drive) gained share over hub-drive in the $3,000+ tier.
---
## Section 5: E-Scooter Regulatory Landscape
The North American e-scooter regulatory environment matured significantly during 2024-2025 after several years of municipal experimentation and reactive policymaking. Forty-one US cities now operate under what we classify as "stable" regulatory regimes (defined as: explicit operating permit framework, defined sidewalk/bike-lane rules, helmet provisions, and revenue-share or fee structures with the city). This is up from 19 cities in 2022.
The regulatory shift has compressed operator margins. Permit fees and per-trip surcharges in major markets (Los Angeles, Chicago, Atlanta, Denver) range from $0.15 to $0.42 per trip, against average ride revenue of $5.40. Several major operators have exited markets where permit economics have proven unviable; Lime exited five secondary US markets in 2025 citing exactly this reason.
Helmet requirements remain inconsistent. Thirteen US states require helmets for riders under 18 only; seven require them for all riders; the rest leave it to municipalities. Enforcement is widely acknowledged to be minimal even where mandates exist. EU markets are substantially stricter, with mandatory helmet provisions in France, Germany, and Italy applying to all e-scooter riders.
Insurance treatment is also fragmenting. Five US states have classified e-scooters as "motor vehicles" requiring liability coverage, raising the floor on operating costs for shared-fleet providers. Most states still treat them as bicycles for insurance purposes.
---
## Section 6: Bike-Share and Dockless Mobility
Docked bike-share systems (Citi Bike, Divvy, Bluebikes, Capital Bikeshare) continue stable, slow growth. Capital Bikeshare reported 5.1M trips in 2025 (5% growth); Citi Bike reported 38M (8% growth). Docked systems benefit from station infrastructure that creates predictability for riders and meters demand-side adoption.
Dockless bike-share (without fixed stations) is largely consolidated; the experimentation phase ended in 2023. Lyft operates the dominant national network through its acquired bike-share division, with regional players in select markets. Operating economics for dockless are structurally weaker than docked due to vehicle redistribution costs, vandalism rates, and the absence of station-driven advertising revenue.
A notable trend is the convergence of bike-share and dockless e-bike subscription models. Several operators now offer monthly memberships that include unlimited 30-minute trips on dockless e-bikes within a service zone. Adoption is concentrated in dense urban cores where car-free lifestyles are practical.
---
## Section 7: Charging Infrastructure Trends
Charging infrastructure for e-bikes and e-scooters has emerged as a meaningful sub-segment, growing 28% in 2025. The dominant form factor remains residential at-home wall chargers (87% of installed base), but commercial charging — at workplaces, transit stations, and apartment buildings — is the fastest-growing sub-segment.
Standardization remains a constraint. Battery interfaces have not converged; Bosch, Shimano, and various proprietary systems coexist. The European Union's USB-C mandate for portable electronics has not yet extended to e-mobility; industry observers expect regulatory pressure to follow within 3-5 years.
Workplace charging is increasingly common in tech and creative-industry employers; we estimate 31% of large urban employers in tech-heavy metros now offer workplace e-bike charging, up from 12% in 2022. Apartment buildings lag — 7% of class-A multifamily properties offer common-area charging, with retrofit cost cited as the primary barrier.
Public charging at transit hubs (subway/light rail stations) remains a stated priority across most major metro transit authorities, but actual installation lags policy commitments significantly. Funding fragmentation and permitting delays are the consistently cited bottlenecks.
---
## Section 8: Smart Helmet Category
The connected safety hardware category — colloquially "smart helmets" — is the smallest segment we cover by retail value but has the strongest growth profile. The North American smart helmet market reached $810M in retail value in 2025, up from $480M in 2023, representing a 30% CAGR. We forecast $2.4B by 2030, contingent on the resolution of two open questions detailed below.
**Category definition.** We define "smart helmets" as helmets that include at least one connected safety feature: turn signals (typically wireless-controlled), braking lights (auto-activated via accelerometer), crash detection (auto-notification to emergency contacts on detected impact), or integrated navigation/audio (bone-conduction speakers, often paired with smartphone apps). Helmets with passive integrated lighting only (no connectivity) are excluded from this category and tracked under traditional helmet retail.
**Key players.** The category remains fragmented; no single manufacturer commands more than 15% market share. Top five by 2025 retail volume: Lumos Helmet (US, market leader at ~14% share with strong DTC presence), Sena Technologies (Korea, intercom heritage, ~11%), Coros (US/China, multi-sport, ~9%), Specialized ANGi (US, premium tier at ~7%), and POC Aid (Sweden, premium safety positioning at ~6%). Approximately 30 smaller brands hold the remaining share.
**Crash detection technology.** Two architectures dominate: single-accelerometer crash detection (lower cost, higher false-positive rate) and multi-sensor fusion (accelerometer + gyroscope + GPS movement signature, lower false-positive rate but higher BOM cost). Insurance industry sources indicate that multi-sensor systems are likely to become a baseline requirement for any insurance discount programs, given that single-accelerometer systems triggered roughly 1 false alert per 47 hours of riding in our test panel.
**Regulatory landscape.** Smart helmets sit at the intersection of two regulatory regimes: the Consumer Product Safety Commission's bicycle helmet standard (16 CFR 1203, governing impact protection) and the Federal Communications Commission's regulation of intentional radiators (governing the radio components for Bluetooth/cellular). Compliance with both is non-trivial. Eight smart helmet brands have had FCC Part 15 violations issued since 2023, typically for emissions exceeding limits during compliance testing. EU markets additionally require EN 1078 certification for the helmet shell; this is widely held but adds 3-5 months to a typical product development timeline.
**Insurance industry interest.** Major auto insurers (State Farm, Progressive, Geico, Nationwide) are actively piloting telematics-style discount programs for cyclists who use connected safety helmets. The proposed structure mirrors auto-insurance "good driver" discount frameworks, with discounts of 5-15% on cycling-specific insurance riders or umbrella policies. As of Q1 2026, three insurers have public pilot programs and one (Progressive) has announced general availability for 2027. This could materially accelerate category adoption if discounts materialize at the upper end of the proposed range.
**Distribution.** D2C dominates at 58% of retail value, reflecting the still-emerging category and the absence of strong channel inventory in independent bike shops. The specialty bike shop channel is growing rapidly (up from 12% to 22% of retail value over 2023-2025) as the category gains category-management attention from major distributors. Big-box channels (REI, Dick's Sporting Goods) are present but shallow in selection — typically 4-8 SKUs versus 40+ in dedicated specialty.
**Open questions for the segment.** Our growth forecast is conditioned on (a) the proportion of insurers that follow Progressive into general availability of connected-safety discounts; (b) whether multi-sensor crash detection becomes a category baseline (lifting ASP) or remains a premium-tier feature; and (c) whether the current high false-positive rate of single-accelerometer systems triggers a consumer backlash that suppresses category trust before insurance discounts arrive. The downside scenario produces a 2030 category size of $1.4B versus our base-case $2.4B.
---
## Section 9: Vehicle-to-Grid Integration
Vehicle-to-grid (V2G) integration of e-bike and e-scooter batteries is an emerging area, but practical commercial deployment is years away. The thesis is that fleet-scale dockless e-bikes and e-scooters represent meaningful aggregate battery capacity that could participate in demand-response markets, particularly in deregulated electricity markets.
Several technical preconditions must be met: standardized battery interfaces (currently absent), bidirectional charging hardware (rare), aggregator software stack (early-stage), and regulatory clarity on energy market participation by mobility fleets (pre-policy). We treat this as a watch item for 2028+ rather than a current investable theme.
---
## Section 10: Outlook
Our base-case forecast for North American e-mobility is $22.5B by 2030, with the e-bike segment reaching $11.8B (the largest), connected safety hardware reaching $2.4B (the fastest-growing in percentage terms), and charging infrastructure reaching $4.2B (driven by commercial and multifamily retrofit demand). Bike-share and dockless mobility plateau in the $2.5-3.0B range as urban density limits adoption ceilings.
The largest single uncertainty in this forecast is the trajectory of insurance industry adoption of connected-safety telematics, which could accelerate or substantially constrain the smart helmet segment and, secondarily, influence rider behavior across the broader category. We will revisit forecasts in our Q4 2026 update.
---
*This report is prepared for the exclusive use of Meridian Insights subscribers. Reproduction or external distribution without written permission is prohibited.*

View File

@ -1,41 +0,0 @@
# Addendum — Mossridge Tool Lending Library
## Options considered
### Paid lending model (rejected)
Considered charging a nominal per-loan fee ($2$5) to cover replacement and maintenance. Rejected as inconsistent with library mission of free access. Board has previously stated free access is non-negotiable for core services. A donation jar at checkout was proposed as a soft alternative; deferred.
### Hardware store partnership (considered, deferred)
Mossridge Hardware (the store committing in-kind donations) offered to host a satellite lending point. Considered; deferred to year 2. The integration adds operational complexity (split inventory, cross-location tracking) we are not equipped for at launch. Reasonable to revisit once the main location is established.
### Mobile lending van (rejected)
Proposed by a board member to serve outlying areas. Rejected for MVP — capital cost ($35K+ for vehicle + outfitting) exceeds the entire grant. Could be a year-three expansion if demand validates.
### Skills classes alongside tool loans (deferred)
Considered offering "how to use a power drill" classes as a value-add. Deferred — interesting but distinct programming, not part of the lending service's MVP scope. Adult Services Librarian is interested in piloting separately.
## Reference programs reviewed
- Berkeley Tool Lending Library (operating since 1979, ~3,000 tools, 250+ daily loans). Funded as a city service.
- Oakland Tool Lending Library (operating since 2000, smaller catalog, library-staffed).
- Toronto Tool Library (nonprofit, member-supported, paid model — different funding architecture).
Direct correspondence with Berkeley TLL staff (March 2026) suggested:
- Theft has been low (~2% annually) due to library card requirement and community norms
- The biggest sustainability risk has been staff hours, not tool replacement
- Most successful programs have a paid coordinator role, not pure volunteer
## Potential expansion (year 2+)
- Hardware store satellite location
- Specialty tool categories: woodworking, automotive, sewing
- Skills classes paired with relevant tool checkouts
- Seed/cuttings library co-located in spring/summer
## Insurance and liability — current state
Library counsel (Town of Mossridge legal department) has been consulted informally. Formal opinion pending. Existing policy covers patrons in the building; coverage for tool use off-premises is the open question. Awaiting written response before submitting grant application.

View File

@ -1,57 +0,0 @@
---
title: Mossridge Public Library — Tool Lending Library Proposal
status: final
created: 2026-04-30
updated: 2026-04-30
---
# Tool Lending Library at Mossridge Public Library
## What we're proposing
A free tool-lending service operated out of the Mossridge Public Library, modeled on similar programs in Berkeley, Oakland, and Toronto. Cardholders borrow hand and power tools (drills, saws, ladders, sanders, plumbing snakes, gardening tools) for up to seven days, free of charge.
## Why now
Mossridge residents face rising costs of home maintenance and DIY supplies. Anecdotally, demand for community-shared resources is high — staff have fielded "do you lend tools?" requests for years. A tool library extends the library's mission of equitable access to information and skill-building into the practical-skills domain.
## Who it serves
Mossridge residents with active library cards. Primary audience: single-family homeowners doing their own home repairs, renters making minor improvements with landlord permission, hobbyist woodworkers and gardeners. Estimated 8,000 households in the library's service area.
## Service design
- **Catalog:** Approximately 200 tools to start, prioritizing the most-requested categories (drilling, cutting, sanding, ladders, garden).
- **Loan period:** Seven days, one renewal allowed if no holds.
- **Borrower requirements:** Active library card, signed liability waiver, completed safety briefing for power tools.
- **Location:** Library basement, currently underutilized storage. Accessible by elevator.
- **Hours:** TuesdaySaturday during library hours; tools returned via after-hours drop slot when closed.
## Funding
- ARPA infrastructure grant: $42,000 (anticipated, application pending)
- Friends of the Mossridge Library matching funds: $10,000 (committed)
- In-kind tool donations from Mossridge Hardware (committed in principle)
Year-one operating cost is estimated at $48,000, primarily tool purchase, maintenance supplies, and shelving/storage retrofit. Ongoing cost (year two and beyond) projected at $12,000 annually for replacement tools and consumables.
## Operations
The service will be run by trained library volunteers, supervised by the Adult Services Librarian. Volunteer training program to be developed in partnership with Mossridge Vocational Center. Estimated 46 active volunteers needed at any given time, with a roster of 1215 trained volunteers to provide coverage.
## Risks
- **Theft and loss.** Tools are valuable and portable. Mitigation: deposit on power tools (refundable), card-required checkout, photo documentation at loan and return.
- **Liability.** Borrower waivers will be required; the library's existing insurance policy is being reviewed for coverage.
- **Demand uncertainty.** We do not yet know the actual borrowing volume the service will see.
## Success criteria
- Launch by Q3 2027 with a catalog of 200 tools.
- 300 unique borrowers in the first year of operation.
- Zero serious injury incidents.
- Tool loss rate under 5% per year.
## What we're asking
Board approval to proceed with the ARPA grant application and finalize the service design for fall 2027 launch.

View File

@ -1,29 +0,0 @@
# Decision Log — Mossridge Tool Lending Library
## 2026-03-04
- **Pursuing the project.** Adult Services Librarian + Library Director agreed there's enough informal demand signal (years of "do you lend tools?" inquiries) to investigate seriously. Acknowledged that informal inquiries are not the same as validated demand.
## 2026-03-11
- **Reference programs to study: Berkeley, Oakland, Toronto.** Selected based on size, longevity, and accessibility of operational data.
## 2026-03-25
- **Initial scope: hand and power tools only.** Rejected including specialty categories (sewing, electronics test gear, automotive) for MVP. Reason: staff expertise and storage. Revisit year 2.
- **Free model.** Confirmed — paid model rejected as inconsistent with library mission. Donation jar approved as soft revenue.
## 2026-04-01
- **Volunteer-run model.** Selected to keep ongoing operating costs low. Acknowledged risk: Berkeley correspondence flagged staff-hours as the biggest sustainability concern in similar programs. Plan to revisit at year-one review.
## 2026-04-08
- **Funding architecture: ARPA grant + Friends matching + in-kind donations.** Considered municipal budget request; rejected as too slow (next budget cycle is 18 months out). Grant is faster but requires fall 2027 launch deadline.
## 2026-04-15
- **Launch timing: Q3 2027.** Driven by ARPA grant deadline, not by service-readiness analysis. Acknowledged this is grant-driven, not user-driven, timing.
- **Year-one target: 300 unique borrowers.** Set by analogy to comparable programs scaled to Mossridge population. No local validation underlying this number.
## 2026-04-22
- **Hardware store satellite deferred to year 2.** Operational complexity exceeds our launch capacity.
- **Liability: pending formal opinion from town legal.** Borrower waiver in draft.
## 2026-04-30
- **Brief finalized for board meeting.** Status moved to final.
- **Open items acknowledged for board discussion:** demand validation method, volunteer sustainability, written legal opinion on off-premises tool use coverage.

View File

@ -1,90 +0,0 @@
# Pantry Bridge — Customer Research Transcripts
**Project:** Pantry Bridge meal-kit concept exploration
**Research firm:** In-house
**Round:** Discovery interviews, March 2026
**Format:** 45-minute semi-structured interviews, video; excerpts below are lightly edited for length and clarity
The four interviews below cover four distinct potential customer segments. We are sharing all four for context, though the team's current product hypothesis targets one specific segment.
---
## Interview 1 — Susan, 38, working parent
**Household:** Two kids (ages 6 and 9), spouse works full-time, both parents work demanding office jobs. Suburban Chicago.
**Susan:** "Honestly, the question is just — can I get dinner on the table by 6:30 without it being chicken nuggets again? My kids don't eat anything green unless we play games about it. My husband and I both have late meetings sometimes. We've tried HelloFresh, we've tried Blue Apron, we tried Home Chef. They all kind of work, and they all kind of don't.
The thing that breaks them for us is the prep time. The boxes say 30 minutes but you need to add 10-15 to actually get it done. By Wednesday night I don't have 45 minutes. So we end up using the boxes on weekends and ordering takeout three nights a week, which is the opposite of what the boxes are supposed to do.
If you really wanted to crack it for families like ours: pre-chopped vegetables, sauces that are actually finished and not 'whisk these eight things together.' I'll pay more for less prep. And the recipe books need to read like the kid is going to eat it — not like 'spicy harissa-rubbed cauliflower steaks.'
Portion sizing — most kits send way too much for our family. We're a family of four but the kids each eat about 60% of a meal. We end up with leftovers that go bad. Better sizing would help."
**Interviewer:** What about price?
**Susan:** "We spend $250-350 a week on groceries currently and probably another $200 on takeout. So a meal kit that replaces three nights of takeout could be $200 a month and we'd still come out ahead. Most kits are priced fine; it's the time that breaks them."
---
## Interview 2 — Marcus, 21, college student
**Household:** Junior at state university, off-campus apartment shared with two roommates, kitchen has a microwave, a stovetop, and a half-broken oven. Limited budget.
**Marcus:** "I'm probably the wrong person for this conversation, no offense. I'm not really a meal-kit person. My food situation is, like, dining hall meal plan when I can use it, and the rest is whatever's cheap and fast. Trader Joe's frozen stuff. Eggs. Pasta. Costco runs with my roommates once a month.
I tried a meal kit when my mom signed me up as a 'starting college' gift. It was nice, but it was $80 a week for two people, which is way out of budget. And honestly, the thing they don't get is that I don't have time at 7 PM to cook. I have time at 11 PM. I want to grab something on my way back from the library and not think.
If you're trying to do meal kits for college students — and I don't really think you should — but if you were, the price has to be like $5 a meal. And it has to be food that survives in a fridge for two weeks because we don't shop on a weekly schedule. We shop when we run out.
Snacks matter more to us than meals, actually. Like, the moment when I'm desperate is 10 PM in the library, not 7 PM. Solve that and I might pay attention."
**Interviewer:** Do you have any dietary restrictions?
**Marcus:** "I'm vegetarian, sort of. I eat fish. So pescatarian I guess. But mostly because meat is expensive."
---
## Interview 3 — Eleanor, 71, retired, lives alone
**Household:** Widow, lives alone in the same single-family home she's been in for 36 years. Suburban Cleveland. Two adult children live out of state. Drives during the day but no longer at night.
**Eleanor:** "I'll tell you what I miss. I miss cooking for someone. My husband Walter passed five years ago this June, and the hardest thing — well, not the hardest, but one of them — is that I don't really cook anymore. I cook eggs. I cook a piece of fish. I open a can of soup more often than I'd like to admit. I used to make Sunday dinners that would feed eight people. Now I eat standing up at the counter half the time.
The grocery store is genuinely difficult. I drive there, I park in the back of the lot because I can usually find a spot, and then it's a long walk in. I get tired by the time I'm in the dairy aisle. Carrying the bags from the car to the kitchen — that's a project. My daughter wants me to use grocery delivery and I've tried, but the apps are all designed for someone twenty years younger than me. Tiny buttons, asking me to click through six screens to add a single tomato. I get frustrated and give up.
What I would actually want — and I've thought about this — is meals for one person. Real portions. Not a frozen TV dinner. Not 'serves four, freeze the rest.' I have a freezer full of leftovers I'll never eat. Just one good meal that I can heat up or finish cooking, that tastes like food I would have made.
I'm watching my sodium because of my blood pressure. Watching sugar too — borderline diabetic, my doctor calls it. So I read labels carefully. The frozen meals you can buy in stores are loaded with both. I'd pay more for less of both, if I trusted that the labels were accurate.
The other thing — and please put this in your notes — is that I'm careful about who I let into my house and what I sign up for. There are scams. My friend Marian got taken for $4,000 last year. So if some company asks for my information, I want to know who they are. I want a real customer service number with a real person. I want it to feel like a real business, not a flashy app.
I don't want it to feel like 'old-people food.' That's an important thing. The Meals on Wheels program in our township is wonderful but it's clearly designed for people who are sicker than I am. I'm not sick. I just live alone and grocery shopping is a lot."
**Interviewer:** What would the ideal experience look like?
**Eleanor:** "Someone delivers good food, in real portions, made with the kind of ingredients I would have used. I can heat it up or finish it. It doesn't taste like a hospital. The packaging is something I can actually open without a knife. I get a phone call once in a while from a person, not a robot. The price is reasonable — I'm on a fixed income but I can spend on things that matter. Eating well matters."
---
## Interview 4 — Dimitri, 44, Director of Food Services, mid-size hospital
**Organization:** 340-bed hospital, food service operates patient meals, staff cafeteria, and a small retail café. Reports to the COO.
**Dimitri:** "I'm probably also not who you should be talking to, but happy to share. We don't buy meal kits. We buy ingredients in institutional volumes from Sysco and US Foods primarily, with some specialty buys for dietary restrictions. We feed about 1,800 people a day across patients, staff, and visitors.
What I deal with that you might find interesting is the patient diet matrix. We have to produce meals that meet specific medical requirements — renal diets, cardiac diets, diabetic diets, dysphagia textures, allergen-free, religious restrictions. Each patient gets a tray that meets their specific orders. It's complex.
If a meal kit company wanted to play in our world, they'd be selling to me at the institutional level — bulk pricing, multi-year contracts, ability to deliver consistent specs across thousands of meals. That's not really a 'meal kit' anymore; that's wholesale food service.
Now, where I might be a buyer in a different sense: my staff cafeteria. We're trying to compete with grab-and-go culture. If you produced ready-to-heat meals targeting our staff demographic — nurses, doctors, techs, who are working 12-hour shifts and want real food, not a sandwich — I might pay attention. But the price point would have to make sense for institutional buying, and you'd need to integrate with our existing food safety protocols.
For consumer meal kits, I'm probably not your customer. We did try one when my wife and I were both working through COVID, and we let the subscription lapse after about three months. Fine product, just didn't fit our patterns."
---
## Note from the research lead
These four interviews were selected to represent the range of segments we've considered. The team's working hypothesis after this round is that the older-adult-living-alone segment is the strongest fit for the Pantry Bridge concept — distinctive needs, acknowledged friction with current options, willingness to pay for quality, and a meaningful unmet need around portion sizing and trust. Working parent segment is well-served by existing competitors. College student segment is too price-sensitive. Institutional segment is a different business entirely.
The brief should target the older-adult segment based on the Eleanor interview specifically.

View File

@ -1,101 +0,0 @@
# Q2 Brainstorm — Hatchet & Loop Studio
**Date:** 2026-04-15
**Present:** Mira, Devon, Sofia, Theo
Annual Q2 ideation. We're hunting for our next side-project-that-could-become-a-product. Format: 10 minutes wild ideas, 3 minutes per idea on quick takes, then we vote on one to dig into.
## Round 1: Everything goes
(10 minutes, no filtering. We just throw stuff out.)
- A weather app that tracks your mood alongside the forecast (Devon)
- Meditation chime that learns your sleep cycle and chimes only at the right wake-window (Theo)
- A podcasting tool for non-podcasters — like, you record voice notes and it auto-edits and posts (Sofia)
- Craft beer subscription with detailed brewer notes you can read while drinking (Mira)
- AI sommelier app that tells you what wine to buy at Trader Joe's based on a photo (Theo)
- Office-plant-care subscription with auto-replacement when one dies (Devon)
- Neighborhood ride coordinator — like a private Uber pool for one neighborhood (Mira)
- Neighborhood compost coordinator — connect people with food scraps to people with active compost piles (Sofia)
- Cookbook app where you click "I'll cook this Tuesday" and it auto-generates the shopping list and sends it to your delivery service (Devon)
- AR home staging — point your phone at a room and it shows you what it would look like with different furniture (Theo)
## Round 2: Quick takes
### Weather + mood
Devon: "I'd use it." Sofia thinks the data correlation isn't strong enough to be useful — interesting concept but the science doesn't support a product. Park.
### Sleep-cycle meditation chime
Theo's pitch — exists already (Sleep Cycle, etc.). Differentiation would be the chime, which is hardware. Out of scope for a software-first studio.
### Podcasting for non-podcasters
Sofia: "There are like fifty of these." She's right. Skip.
### Craft beer subscription
Mira admits this is mostly her wanting it for herself. We're not in the logistics business. Skip.
### AI sommelier
Theo: "The model would have to be incredibly good at label recognition." Sofia: "And there's already Vivino." Skip.
### Office-plant-care subscription
Devon: "I worked at a place that had this. They were always sad plants." Operational nightmare, low margin. Skip.
### Neighborhood ride coordinator
Mira: "Saturated. Lyft and Uber both have pool features. Uber Neighborhood was a thing and they killed it." Skip.
### Neighborhood compost coordinator
Sofia: "Hear me out. Cities are mandating organic waste separation but most apartments don't have a composting option. People in single-family homes often have active compost piles and would love more material. There's a missing match-making layer." General agreement this is more interesting than the others. Theo: "How do we make money?" Sofia: "Eventually a small fee on the compost-pile-host side, but for MVP just free and prove the demand." Group lights up. We agree to dig into this in Round 3.
### Cookbook → shopping list
Devon's pitch. Already exists (Mealime, Plan to Eat). Skip.
### AR home staging
Theo: "IKEA already has this." Skip.
## Round 3: Compost coordinator deep dive
We spent 45 minutes on this. Notes:
**Who is the user?**
Two-sided market. Side A: apartment dwellers and renters who generate food scraps and want them composted (motivated by environmental values, sometimes by city mandates). Side B: people with active backyard compost piles who want more "browns and greens" — single-family homeowners, urban farmers, school gardens, community gardens.
Sofia thinks Side A is the harder side to acquire (weak intent — recycling-adjacent behavior). Side B is easier but smaller. The product has to be designed around Side A's friction points.
**Geographic scope.**
Hyperlocal — neighborhood-level, not city-wide. The whole point is short-distance handoff: Side A doesn't want to drive their food scraps across town. We're talking 5-block radius matches.
**Business model (later).**
Free at launch. Eventually: subscription for Side B (compost-pile hosts) — they pay to access more matches. Side A always free. Possibly partner with cities that have green-waste mandates (B2G channel).
**Technical approach.**
Web app first, mobile second. Map-based discovery. Identity verification light-touch (apartment dwellers are skittish about strangers; need trust signals). Match-and-message pattern, not real-time logistics.
**Competition.**
ShareWaste exists but is global and not focused on hyperlocal density. Some city-specific apps (NYC's GrowNYC). No one has cracked the neighborhood-density model.
**MVP scope.**
One pilot neighborhood. Sofia knows people in a Portland neighborhood (Sunnyside / Hawthorne area) where compost culture is strong. Start there.
**Open questions.**
- How do we acquire Side A (apartment dwellers)? They have low intent and lots of competing options (just throwing scraps in trash, paying a service, signing up for city pickup if available).
- What does the trust layer look like? Reviews? Vouching? Real-name only?
- Does Side B saturation become a problem fast (one compost pile can only take so much)? How do we route demand?
## Action items
- Sofia: write up the compost coordinator concept as a brief by next Wednesday. Take it to Mira and Devon for first read.
- Devon: research ShareWaste's user numbers and any teardowns of why they haven't dominated.
- Theo: sketch the trust-layer UX concepts.
- Mira: talk to Sofia's Portland contacts about doing user interviews.
Next meeting: 2026-04-29 — review brief draft, decide on go/no-go.

View File

@ -1,18 +0,0 @@
[
{ "query": "Help me write a product brief for my new app idea", "should_trigger": true },
{ "query": "I need to draft a brief for a feature we're scoping", "should_trigger": true },
{ "query": "Update this product brief — we changed the target audience", "should_trigger": true },
{ "query": "Review my brief and tell me if it's investor-ready", "should_trigger": true },
{ "query": "Validate this brief before our board meeting Monday", "should_trigger": true },
{ "query": "Pressure-test my product brief for weak assumptions", "should_trigger": true },
{ "query": "Help me put together a one-page summary of my product idea for stakeholders", "should_trigger": true },
{ "query": "Help me brainstorm ideas for a new feature", "should_trigger": false },
{ "query": "Write me a PRD for our checkout flow redesign", "should_trigger": false },
{ "query": "Run a working backwards exercise for my product idea", "should_trigger": false },
{ "query": "Document this existing codebase for AI agents", "should_trigger": false },
{ "query": "Help me write user stories for the next sprint", "should_trigger": false },
{ "query": "Generate a system architecture for my app", "should_trigger": false },
{ "query": "Write code to parse JSON in Python", "should_trigger": false },
{ "query": "Create a marketing landing page for my product", "should_trigger": false }
]

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "bmad-method",
"version": "6.6.0",
"version": "6.3.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "bmad-method",
"version": "6.6.0",
"version": "6.3.0",
"license": "MIT",
"dependencies": {
"@clack/core": "^1.0.0",

View File

@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "bmad-method",
"version": "6.6.0",
"version": "6.3.0",
"description": "Breakthrough Method of Agile AI-driven Development",
"keywords": [
"agile",
@ -39,13 +39,12 @@
"lint:fix": "eslint . --ext .js,.cjs,.mjs,.yaml --fix",
"lint:md": "markdownlint-cli2 \"**/*.md\"",
"prepare": "command -v husky >/dev/null 2>&1 && husky || exit 0",
"quality": "npm run format:check && npm run lint && npm run lint:md && npm run docs:build && npm run test:install && npm run test:urls && npm run validate:refs && npm run validate:skills",
"quality": "npm run format:check && npm run lint && npm run lint:md && npm run docs:build && npm run test:install && npm run validate:refs && npm run validate:skills",
"rebundle": "node tools/installer/bundlers/bundle-web.js rebundle",
"test": "npm run test:refs && npm run test:install && npm run test:urls && npm run test:channels && npm run lint && npm run lint:md && npm run format:check",
"test": "npm run test:refs && npm run test:install && npm run test:channels && npm run lint && npm run lint:md && npm run format:check",
"test:channels": "node test/test-installer-channels.js",
"test:install": "node test/test-installation-components.js",
"test:refs": "node test/test-file-refs-csv.js",
"test:urls": "node test/test-parse-source-urls.js",
"validate:refs": "node tools/validate-file-refs.js --strict",
"validate:skills": "node tools/validate-skills.js --strict"
},

View File

@ -15,40 +15,3 @@ bmad-quick-spec
bmad-quick-flow
bmad-quick-dev-new-preview
bmad-init
# Pre-v6.2.0 wrapper skills (module-prefixed naming, dropped in v6.2.0).
# Users upgrading from v6.0.x / v6.1.x had these installed and the cleanup
# never knew to remove them; they remained alongside the new self-contained
# skills causing duplicates and broken-file errors. See issue #2309.
bmad-agent-bmm-analyst
bmad-agent-bmm-architect
bmad-agent-bmm-dev
bmad-agent-bmm-pm
bmad-agent-bmm-qa
bmad-agent-bmm-quick-flow-solo-dev
bmad-agent-bmm-sm
bmad-agent-bmm-tech-writer
bmad-agent-bmm-ux-designer
bmad-bmm-check-implementation-readiness
bmad-bmm-code-review
bmad-bmm-correct-course
bmad-bmm-create-architecture
bmad-bmm-create-epics-and-stories
bmad-bmm-create-prd
bmad-bmm-create-product-brief
bmad-bmm-create-story
bmad-bmm-create-ux-design
bmad-bmm-dev-story
bmad-bmm-document-project
bmad-bmm-domain-research
bmad-bmm-edit-prd
bmad-bmm-generate-project-context
bmad-bmm-market-research
bmad-bmm-qa-generate-e2e-tests
bmad-bmm-quick-dev
bmad-bmm-quick-spec
bmad-bmm-retrospective
bmad-bmm-sprint-planning
bmad-bmm-sprint-status
bmad-bmm-technical-research
bmad-bmm-validate-prd

View File

@ -7,8 +7,8 @@
"description": "Produces battle-tested PRFAQ document and optional LLM distillate for PRD input.",
"supports-headless": true,
"phase-name": "1-analysis",
"preceded-by": ["brainstorming", "perform-research"],
"followed-by": ["create-prd"],
"after": ["brainstorming", "perform-research"],
"before": ["create-prd"],
"is-required": false,
"output-location": "{planning_artifacts}"
}

View File

@ -1,80 +1,117 @@
---
name: bmad-product-brief
description: Create, update, or validate a product brief. Use when the user wants help producing, editing, or validating a brief.
dependencies:
- bmad-distillator
- bmad-editorial-review-structure
- bmad-editorial-review-prose
- bmad-help
description: Create or update product briefs through guided or autonomous discovery. Use when the user requests to create or update a Product Brief.
---
# Overview
# Create Product Brief
You are an expert product analyst coach and facilitator. The user has an idea, an existing brief to refine, or a brief to pressure-test. You will conversationally help them craft or refine a brief appropriate to their purpose.
## Overview
You are not in a hurry. You will not do the thinking for them. Coach, do not quiz. Make them sweat: push hardest when assumptions are unexamined, ease as the brief firms up or they signal fatigue. Get out what is stuck in their head and what they may have forgotten. Push back when an answer is thin.
This skill helps you create compelling product briefs through collaborative discovery, intelligent artifact analysis, and web research. Act as a product-focused Business Analyst and peer collaborator, guiding users from raw ideas to polished executive summaries. Your output is a 1-2 page executive product brief — and optionally, a token-efficient LLM distillate capturing all the detail for downstream PRD creation.
Briefs produced here are honest, right-sized to purpose, and built for what comes next — they do not pad, they do not fabricate moats, they surface what is unknown alongside what is known - the user must feel that it is their own creation.
The user is the domain expert. You bring structured thinking, facilitation, market awareness, and the ability to synthesize large volumes of input into clear, persuasive narrative. Work together as equals.
**Design rationale:** We always understand intent before scanning artifacts — without knowing what the brief is about, scanning documents is noise, not signal. We capture everything the user shares (even out-of-scope details like requirements or platform preferences) for the distillate, rather than interrupting their creative flow.
## Conventions
- Bare paths (e.g. `prompts/finalize.md`) resolve from the skill root.
- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives).
- `{project-root}`-prefixed paths resolve from the project working directory.
- `{skill-name}` resolves to the skill directory's basename.
## Activation Mode Detection
Check activation context immediately:
1. **Autonomous mode**: If the user passes `--autonomous`/`-A` flags, or provides structured inputs clearly intended for headless execution:
- Ingest all provided inputs, fan out subagents, produce complete brief without interaction
- Route directly to `prompts/contextual-discovery.md` with `{mode}=autonomous`
2. **Yolo mode**: If the user passes `--yolo` or says "just draft it" / "draft the whole thing":
- Ingest everything, draft complete brief upfront, then walk user through refinement
- Route to Stage 1 below with `{mode}=yolo`
3. **Guided mode** (default): Conversational discovery with soft gates
- Route to Stage 1 below with `{mode}=guided`
## On Activation
1. Resolve customization: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, surface the diagnostic and halt.
2. Execute each entry in `{workflow.activation_steps_prepend}` in order.
3. Treat every entry in `{workflow.persistent_facts}` as foundational context for the rest of the run. Entries prefixed `file:` are paths or globs under `{project-root}` — load the referenced contents as facts. All other entries are facts verbatim.
4. Load `{project-root}/_bmad/bmm/config.yaml` (and `config.user.yaml` if present). Resolve `{user_name}`, `{communication_language}`, `{document_output_language}`, `{planning_artifacts}`, `{project_name}`, `{date}`.
5. Greet `{user_name}` in `{communication_language}`. Detect intent (create / update / validate). If interactive and intent is unclear, ask; for headless behavior see `## Headless Mode`.
6. Execute each entry in `{workflow.activation_steps_append}` in order.
### Step 1: Resolve the Workflow Block
## Intent Operating Modes
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
**Create.** A brief the user is proud of, that meets their needs, drawn out through real conversation — do not assume: instead converse and understand, and then help craft the best product brief for their needs. Begin in `## Discovery` before drafting; the brief comes after the picture is on the table. Shape follows the product and need. Treat `{workflow.brief_template}` as a starting structure, not a contract: drop sections that do not earn their place, add sections the product needs, reorder freely - create sections for specialized domains or concerns also as needed. The brief serves the product's story, not the template's shape. Bind `{doc_workspace}` to a fresh folder at `{workflow.output_dir}/{workflow.output_folder_name}/` and write `brief.md` there with YAML frontmatter (title, status, created, updated). For Update and Validate, `{doc_workspace}` is the existing folder of the brief being targeted.
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
**Update.** Reconcile an existing brief with a change signal (edit request, downstream artifact, anything). Read the brief, the addendum if present, `decision-log.md`, and any original inputs first — past decisions and rejected ideas matter. Then run the `## Discovery` posture against the change signal before proposing changes. Identify what is now stale or wrong, propose changes, apply on agreement, bump `updated`, and write a new `decision-log.md` entry recording what changed and why — every update, clean or override, must be logged. If the change signal contradicts prior decisions, surface the conflict before changing anything. In headless mode, if the prompt clearly signals intent to override the contradicted decision, write the full audit trail first, then apply the change — you must: (1) add a new entry to `decision-log.md` naming the decision being reversed and its rationale, (2) add an override section to `addendum.md` (creating it if absent). Both are mandatory before modifying `brief.md`; do not wait for user confirmation. If intent to override is ambiguous, halt with `blocked` status naming the specific conflict. If the change is fundamental, name it as a re-draft and offer Create instead. If `distillate.md` exists, you must regenerate it after changes are applied by invoking `bmad-distillator`; this step is required, not optional. If `bmad-distillator` is unavailable, flag the distillate as stale in the JSON output.
1. `{skill-root}/customize.toml` — defaults
2. `{project-root}/_bmad/custom/{skill-name}.toml` — team overrides
3. `{project-root}/_bmad/custom/{skill-name}.user.toml` — personal overrides
**Validate.** Honest critique against the brief's own purpose. Read the brief, the addendum if present, `decision-log.md`, and any original inputs first — a validation that ignores prior decisions, rejected ideas, or context the user supplied is shallow. Cite specific lines. Caveat what cannot be evaluated. Return inline — no separate file unless asked. Always offer to roll findings into an Update, even in headless mode — include `"offer_to_update": true` in the JSON status block.
Any missing file is skipped. Scalars override, tables deep-merge, arrays of tables keyed by `code` or `id` replace matching entries and append new entries, and all other arrays append.
## Headless Mode
### Step 2: Execute Prepend Steps
When invoked headless, do not ask. Complete the intent using what is provided, what exists in `{doc_workspace}`, or what you can discover yourself. If intent remains ambiguous after inference, halt with a `blocked` JSON status and a `reason` field — do not prompt. End with a JSON response listing status, intent, and artifact paths. The `intent` field must match the detected intent: `"create"`, `"update"`, or `"validate"`. Examples:
Execute each entry in `{workflow.activation_steps_prepend}` in order before proceeding.
```json
{
"status": "complete",
"intent": "create",
"brief": "{doc_workspace}/brief.md",
"addendum": "{doc_workspace}/addendum.md",
"distillate": "{doc_workspace}/distillate.md",
"decision_log": "{doc_workspace}/decision-log.md",
"open_questions": []
}
```
### Step 3: Load Persistent Facts
```json
{
"status": "complete",
"intent": "validate",
"offer_to_update": true
}
```
Treat every entry in `{workflow.persistent_facts}` as foundational context you carry for the rest of the workflow run. Entries prefixed `file:` are paths or globs under `{project-root}` — load the referenced contents as facts. All other entries are facts verbatim.
Omit keys for artifacts that were not produced.
### Step 4: Load Config
## Discovery
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
- Use `{user_name}` for greeting
- Use `{communication_language}` for all communications
- Use `{document_output_language}` for output documents
- Use `{planning_artifacts}` for output location and artifact scanning
- Use `{project_knowledge}` for additional context scanning
Conversationally surface what the user brings, why this brief exists, and the domain — echo back how each shapes your approach. Open with space for the full picture: invite a brain dump and ask up front for any source material they already have (memo, deck, transcript, prior brief, slack thread). Read what exists first; ask only what is missing. After the dump, a simple "anything else?" often surfaces what they almost forgot. Drill into specifics only after the broad shape is on the table; premature granular questions interrupt the dump and miss the room. Get a read on stakes early (passion project, internal pitch, investor input, public launch), and let that calibrate how hard you push. Suggest research (web, competitive, market) only when the stakes warrant it.
### Step 5: Greet the User
## Constraints
If `{mode}` is not `autonomous`, greet `{user_name}` (if you have not already), speaking in `{communication_language}`. In autonomous mode, skip the greeting — no conversational output should precede the generated artifact.
- **Right-size to purpose.** A passion project does not need investor-grade rigor. A VC pitch input does. Read the room.
- **Persistence is real-time.** Once Create intent is confirmed, the workspace (run folder, `brief.md` skeleton with `status: draft`, `decision-log.md`) exists on disk and the user knows the path. The decision log is canonical memory — what the user has shared is preserved on disk, not stored in the conversation.
- **Continuity across sessions.** If a prior in-progress draft for this project exists, the user is offered to resume.
- **Extract, don't ingest.** Source artifacts (provided by the user or discovered during the run — transcripts, brainstorms, research reports, code, web results, prior briefs) enter the parent conversation as relevance-filtered extracts, not loaded wholesale. Subagents do the extraction against the user's stated focus; the parent context stays lean.
- **Length and coherence.** Aim for 1-2 pages — if it is longer, the detail belongs in the addendum or distillate. Structure in service of the product; downstream consumers (PRD workflow, etc.) read this, so coherent shape matters.
### Step 6: Execute Append Steps
## Finalize
Execute each entry in `{workflow.activation_steps_append}` in order.
1. Decision log audit + addendum: the user ends this step with an explicit, shared accounting of how the meaningful contents of `decision-log.md` were handled — captured in the brief, captured in `addendum.md` (rejected-alternative rationale, options-considered matrices, parked-roadmap context, technical constraints, sizing data, in-depth personas), or set aside as process noise. `addendum.md` exists if anything earned its place there.
2. Polish: apply each entry in `{workflow.doc_standards}` (a `skill:`, `file:`, or plain-text directive) to `brief.md` (and `addendum.md` if it exists). Run passes as parallel subagents. The user sees a polished draft, not a polish review.
3. Distillate: offer the user a lean, token-efficient distillate of the brief — frame why it matters (it becomes the primary input when downstream BMad workflows like PRD creation pull this brief in). If they want it, invoke `bmad-distillator` with `source_documents=[brief.md, addendum.md if produced]`, `downstream_consumer="PRD creation"`, `output_path={doc_workspace}/distillate.md`. If `bmad-distillator` is not installed, skip distillate generation entirely — do not attempt an inline alternative. Include `"distillate": "skipped — bmad-distillator not installed"` in the final JSON block and tell the user to install it.
4. Tell the user it is ready: artifacts, path, use the `bmad-help` skill to help understand what next steps you can suggest they do in the bmad method ecosystem.
5. Run `{workflow.on_complete}` if non-empty. Treat a string scalar as a single instruction and an array as a sequence of instructions executed in order.
Activation is complete. Begin the workflow at Stage 1 below.
## Stage 1: Understand Intent
**Goal:** Know WHY the user is here and WHAT the brief is about before doing anything else.
**Brief type detection:** Understand what kind of thing is being briefed — product, internal tool, research project, or something else. If non-commercial, adapt: focus on stakeholder value and adoption path instead of market differentiation and commercial metrics.
**Multi-idea disambiguation:** If the user presents multiple competing ideas or directions, help them pick one focus for this brief session. Note that others can be briefed separately.
**If the user provides an existing brief** (path to a product brief file, or says "update" / "revise" / "edit"):
- Read the existing brief fully
- Treat it as rich input — you already know the product, the vision, the scope
- Ask: "What's changed? What do you want to update or improve?"
- The rest of the workflow proceeds normally — contextual discovery may pull in new research, elicitation focuses on gaps or changes, and draft-and-review produces an updated version
**If the user already provided context** when launching the skill (description, docs, brain dump):
- Acknowledge what you received — but **DO NOT read document files yet**. Note their paths for Stage 2's subagents to scan contextually. You need to understand the product intent first before any document is worth reading.
- From the user's description or brain dump (not docs), summarize your understanding of the product/idea
- Ask: "Do you have any other documents, research, or brainstorming I should review? Anything else to add before I dig in?"
**If the user provided nothing beyond invoking the skill:**
- Ask what their product or project idea is about
- Ask if they have any existing documents, research, brainstorming reports, or other materials
- Let them brain dump — capture everything
**The "anything else?" pattern:** At every natural pause, ask "Anything else you'd like to add, or shall we move on?" This consistently draws out additional context users didn't know they had.
**Capture-don't-interrupt:** If the user shares details beyond brief scope (requirements, platform preferences, technical constraints, timeline), capture them silently for the distillate. Don't redirect or stop their flow.
**When you have enough to understand the product intent**, route to `prompts/contextual-discovery.md` with the current mode.
## Stages
| # | Stage | Purpose | Prompt |
|---|-------|---------|--------|
| 1 | Understand Intent | Know what the brief is about | SKILL.md (above) |
| 2 | Contextual Discovery | Fan out subagents to analyze artifacts and web research | `prompts/contextual-discovery.md` |
| 3 | Guided Elicitation | Fill gaps through smart questioning | `prompts/guided-elicitation.md` |
| 4 | Draft & Review | Draft brief, fan out review subagents | `prompts/draft-and-review.md` |
| 5 | Finalize | Polish, output, offer distillate | `prompts/finalize.md` |

View File

@ -0,0 +1,60 @@
# Artifact Analyzer
You are a research analyst. Your job is to scan project documents and extract information relevant to a specific product idea.
## Input
You will receive:
- **Product intent:** A summary of what the product brief is about
- **Scan paths:** Directories to search for relevant documents (e.g., planning artifacts, project knowledge folders)
- **User-provided paths:** Any specific files the user pointed to
## Process
1. **Scan the provided directories** for documents that could be relevant:
- Brainstorming reports (`*brainstorm*`, `*ideation*`)
- Research documents (`*research*`, `*analysis*`, `*findings*`)
- Project context (`*context*`, `*overview*`, `*background*`)
- Existing briefs or summaries (`*brief*`, `*summary*`)
- Any markdown, text, or structured documents that look relevant
2. **For sharded documents** (a folder with `index.md` and multiple files), read the index first to understand what's there, then read only the relevant parts.
3. **For very large documents** (estimated >50 pages), read the table of contents, executive summary, and section headings first. Read only sections directly relevant to the stated product intent. Note which sections were skimmed vs read fully.
4. **Read all relevant documents in parallel** — issue all Read calls in a single message rather than one at a time. Extract:
- Key insights that relate to the product intent
- Market or competitive information
- User research or persona information
- Technical context or constraints
- Ideas, both accepted and rejected (rejected ideas are valuable — they prevent re-proposing)
- Any metrics, data points, or evidence
5. **Ignore documents that aren't relevant** to the stated product intent. Don't waste tokens on unrelated content.
## Output
Return ONLY the following JSON object. No preamble, no commentary. Maximum 8 bullets per section.
```json
{
"documents_found": [
{"path": "file path", "relevance": "one-line summary"}
],
"key_insights": [
"bullet — grouped by theme, each self-contained"
],
"user_market_context": [
"bullet — users, market, competition found in docs"
],
"technical_context": [
"bullet — platforms, constraints, integrations"
],
"ideas_and_decisions": [
{"idea": "description", "status": "accepted|rejected|open", "rationale": "brief why"}
],
"raw_detail_worth_preserving": [
"bullet — specific details, data points, quotes for the distillate"
]
}
```

View File

@ -0,0 +1,44 @@
# Opportunity Reviewer
You are a strategic advisor reviewing a product brief draft. Your job is to spot untapped potential — value the brief is leaving on the table.
## Input
You will receive the complete draft product brief.
## Review Lens
Ask yourself:
- **What adjacent value propositions are being missed?** Are there related problems this solution naturally addresses?
- **What market angles are underemphasized?** Is the positioning leaving opportunities unexplored?
- **What partnerships or integrations could multiply impact?** Who would benefit from aligning with this product?
- **What's the network effect or viral potential?** Is there a growth flywheel the brief doesn't describe?
- **What's underemphasized?** Which strengths deserve more spotlight?
- **What user segments are overlooked?** Could this serve audiences not yet mentioned?
- **What's the bigger story?** If you zoom out, is there a more compelling narrative?
- **What would an investor want to hear more about?** What would make someone lean forward?
## Output
Return ONLY the following JSON object. No preamble, no commentary. Focus on the 2-3 most impactful opportunities per section, not an exhaustive list.
```json
{
"untapped_value": [
{"opportunity": "adjacent problem or value prop", "rationale": "why it matters"}
],
"positioning_opportunities": [
{"angle": "market angle or narrative", "impact": "how it strengthens the brief"}
],
"growth_and_scale": [
"bullet — network effects, viral loops, expansion paths"
],
"strategic_partnerships": [
{"partner_type": "who", "value": "why this alliance matters"}
],
"underemphasized_strengths": [
{"strength": "what's underplayed", "suggestion": "how to elevate it"}
]
}
```

View File

@ -0,0 +1,44 @@
# Skeptic Reviewer
You are a critical analyst reviewing a product brief draft. Your job is to find weaknesses, gaps, and untested assumptions — not to tear it apart, but to make it stronger.
## Input
You will receive the complete draft product brief.
## Review Lens
Ask yourself:
- **What's missing?** Are there sections that feel thin or glossed over?
- **What assumptions are untested?** Where does the brief assert things without evidence?
- **What could go wrong?** What risks aren't acknowledged?
- **Where is it vague?** Which claims need more specificity?
- **Does the problem statement hold up?** Is this a real, significant problem or a nice-to-have?
- **Are the differentiators actually defensible?** Could a competitor replicate them easily?
- **Do the success metrics make sense?** Are they measurable and meaningful?
- **Is the MVP scope realistic?** Too ambitious? Too timid?
## Output
Return ONLY the following JSON object. No preamble, no commentary. Maximum 5 items per section. Prioritize — lead with the most impactful issues.
```json
{
"critical_gaps": [
{"issue": "what's missing", "impact": "why it matters", "suggestion": "how to fix"}
],
"untested_assumptions": [
{"assumption": "what's asserted", "risk": "what could go wrong"}
],
"unacknowledged_risks": [
{"risk": "potential failure mode", "severity": "high|medium|low"}
],
"vague_areas": [
{"section": "where", "issue": "what's vague", "suggestion": "how to sharpen"}
],
"suggested_improvements": [
"actionable suggestion"
]
}
```

View File

@ -0,0 +1,49 @@
# Web Researcher
You are a market research analyst. Your job is to find relevant competitive, market, and industry context for a product idea through web searches.
## Input
You will receive:
- **Product intent:** A summary of what the product is about, the problem it solves, and the domain it operates in
## Process
1. **Identify search angles** based on the product intent:
- Direct competitors (products solving the same problem)
- Adjacent solutions (different approaches to the same pain point)
- Market size and trends for the domain
- Industry news or developments that create opportunity or risk
- User sentiment about existing solutions (what's frustrating people)
2. **Execute 3-5 targeted web searches** — quality over quantity. Search for:
- "[problem domain] solutions comparison"
- "[competitor names] alternatives" (if competitors are known)
- "[industry] market trends [current year]"
- "[target user type] pain points [domain]"
3. **Synthesize findings** — don't just list links. Extract the signal.
## Output
Return ONLY the following JSON object. No preamble, no commentary. Maximum 5 bullets per section.
```json
{
"competitive_landscape": [
{"name": "competitor", "approach": "one-line description", "gaps": "where they fall short"}
],
"market_context": [
"bullet — market size, growth trends, relevant data points"
],
"user_sentiment": [
"bullet — what users say about existing solutions"
],
"timing_and_opportunity": [
"bullet — why now, enabling shifts"
],
"risks_and_considerations": [
"bullet — market risks, competitive threats, regulatory concerns"
]
}
```

View File

@ -1,41 +0,0 @@
# Product Brief Template
A flexible starting structure for the executive product brief. Adapt aggressively to the product, the purpose, and the domain. Drop sections that do not earn their place, add sections the product needs, reorder freely. The brief serves the product's story, not the template's shape.
## Default Structure
```markdown
# Product Brief: {Product Name}
## Executive Summary
[2-3 paragraph narrative: what this is, what problem it solves, why it matters, why now. Compelling enough to stand alone — if someone reads only this section, they should understand the vision.]
## The Problem
[What pain exists, who feels it, how they cope today, the cost of the status quo. Be specific: real scenarios, real frustrations, real consequences.]
## The Solution
[What is being built, how it solves the problem. Focus on the experience and the outcome, not the implementation.]
## What Makes This Different
[Key differentiators. Why this approach over alternatives, what is the unfair advantage. Be honest. If the moat is execution speed, say so. Do not fabricate technical moats.]
## Who This Serves
[Primary users — vivid but brief. Who they are, what they need, what success looks like for them. Secondary users if relevant.]
## Success Criteria
[How we know this is working. Mix of user success signals and business objectives. Measurable.]
## Scope
[What is in for the first version. What is explicitly out. Keep this tight — boundary document, not a feature list.]
## Vision
[Where this goes if it succeeds. What it becomes in 2-3 years. Inspiring but grounded.]
```

View File

@ -0,0 +1,17 @@
{
"module-code": "bmm",
"replaces-skill": "bmad-create-product-brief",
"capabilities": [
{
"name": "create-brief",
"menu-code": "CB",
"description": "Produces executive product brief and optional LLM distillate for PRD input.",
"supports-headless": true,
"phase-name": "1-analysis",
"after": ["brainstorming", "perform-research"],
"before": ["create-prd"],
"is-required": true,
"output-location": "{planning_artifacts}"
}
]
}

View File

@ -1,66 +1,47 @@
# DO NOT EDIT -- overwritten on every update.
#
# Workflow customization surface for bmad-product-brief.
#
# Override files (not edited here):
# {project-root}/_bmad/custom/bmad-product-brief.toml (team)
# {project-root}/_bmad/custom/bmad-product-brief.user.toml (personal)
# Workflow customization surface for bmad-product-brief. Mirrors the
# agent customization shape under the [workflow] namespace.
[workflow]
# --- Configurable below. Overrides merge per BMad structural rules: ---
# scalars: override wins • arrays: append
# scalars: override wins • arrays (persistent_facts, activation_steps_*): append
# arrays-of-tables with `code`/`id`: replace matching items, append new ones.
# Steps to run before the standard activation (config load, greet).
# Use for pre-flight loads, compliance checks, etc.
# Overrides append. Use for pre-flight loads, compliance checks, etc.
activation_steps_prepend = []
# Steps to run after greet but before the workflow begins.
# Use for context-heavy setup that should happen once the user has been acknowledged.
# Steps to run after greet but before Stage 1 of the workflow.
# Overrides append. Use for context-heavy setup that should happen
# once the user has been acknowledged.
activation_steps_append = []
# Persistent facts the workflow keeps in mind for the whole run
# (standards, compliance constraints, stylistic guardrails).
# Each entry is either a literal sentence, a skill prefixed with `skill:`, or a `file:`-prefixed path/glob
# whose contents are loaded as facts.
# Default is empty. Common opt-ins (set in your team/user override TOML):
# "file:{project-root}/_bmad-output/planning-artifacts/project-context.md" # bmad-generate-project-context output
# "skill:acme-co:terms-and-conditions" # a skill that contains some relevant info to the documents that may be generated
# "Elvis has left the building" # generic agent instructions
persistent_facts = []
# Executed when the workflow completes (after the user has been told the
# brief is ready). Accepts either a string scalar (single instruction)
# or an array of instructions executed in order. Empty for none.
on_complete = ""
# Default brief structure. Treated as a starting point — the LLM adapts it
# to the product, purpose, and domain. Override the path in team/user TOML
# to enforce a different structure (e.g. regulated-industry, investor-deck).
brief_template = "assets/brief-template.md"
# Run folder location. The brief, optional addendum, and optional distillate
# all land inside `{output_dir}/{output_folder_name}/`.
output_dir = "{planning_artifacts}/briefs"
output_folder_name = "brief-{project_name}-{date}"
# Document standards applied to human-consumed docs at finalize. Each entry is
# a `skill:`, `file:`, or plain-text directive; the parent LLM applies the
# findings before the user sees the draft. Encodes standards, not options.
# Distinct from the runtime memory sidecar — these are static context
# loaded on activation. Overrides append.
#
# Examples:
# "skill:bmad-editorial-review-prose"
# "file:{project-root}/_bmad/style-guides/company-voice.md"
# "Convert all dates to ISO 8601 format."
#
# Suggested order (broader passes first, narrower last):
# 1. Structural (cuts, reorganization, section sizing)
# 2. Content/voice/conventions (org standards, tone, terminology, compliance)
# 3. Prose mechanics (grammar, clarity, typos)
#
# Override the array in team/user TOML to add additional standards. Append-only:
# base entries cannot be removed or replaced (resolver has no removal mechanism).
doc_standards = [
"skill:bmad-editorial-review-structure",
"skill:bmad-editorial-review-prose",
# Each entry is either:
# - a literal sentence, e.g. "All briefs must include a regulatory-risk section."
# - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
# (glob patterns are supported; the file's contents are loaded and treated as facts).
persistent_facts = [
"file:{project-root}/**/project-context.md",
]
# Path to the brief structure template used in Stage 4 drafting.
# Bare paths resolve from the skill root; use `{project-root}/...` to
# point at an org-owned template elsewhere in the repo. Override wins.
brief_template = "resources/brief-template.md"
# Scalar: executed when the workflow reaches its terminal stage, after
# the main output has been delivered. Override wins. Leave empty for
# no custom post-completion behavior.
on_complete = ""

View File

@ -0,0 +1,58 @@
**Language:** Use `{communication_language}` for all output.
**Output Language:** Use `{document_output_language}` for documents.
**Output Location:** `{planning_artifacts}`
**Paths:** Bare paths (e.g. `agents/foo.md`) resolve from the skill root.
# Stage 2: Contextual Discovery
**Goal:** Armed with the user's stated intent, intelligently gather and synthesize all available context — documents, project knowledge, and web research — so later stages work from a rich, relevant foundation.
## Subagent Fan-Out
Now that you know what the brief is about, fan out subagents in parallel to gather context. Each subagent receives the product intent summary so it knows what's relevant.
**Launch in parallel:**
1. **Artifact Analyzer** (`agents/artifact-analyzer.md`) — Scans `{planning_artifacts}` and `{project_knowledge}` for relevant documents. Also scans any specific paths the user provided. Returns structured synthesis of what it found.
2. **Web Researcher** (`agents/web-researcher.md`) — Searches for competitive landscape, market context, trends, and relevant industry data. Returns structured findings scoped to the product domain.
### Graceful Degradation
If subagents are unavailable or fail:
- Read only the most relevant 1-2 documents in the main context and summarize (don't full-read everything — limit context impact in degraded mode)
- Do a few targeted web searches inline
- Never block the workflow because a subagent feature is unavailable
## Synthesis
Once subagent results return (or inline scanning completes):
1. **Merge findings** with what the user already told you
2. **Identify gaps** — what do you still need to know to write a solid brief?
3. **Note surprises** — anything from research that contradicts or enriches the user's assumptions?
## Mode-Specific Behavior
**Guided mode:**
- Present a concise summary of what you found: "Here's what I learned from your documents and web research..."
- Highlight anything surprising or worth discussing
- Share the gaps you've identified
- Ask: "Anything else you'd like to add, or shall we move on to filling in the details?"
- Route to `prompts/guided-elicitation.md`
**Yolo mode:**
- Absorb all findings silently
- Skip directly to `prompts/draft-and-review.md` — you have enough to draft
- The user will refine later
**Headless mode:**
- Absorb all findings
- Skip directly to `prompts/draft-and-review.md`
- No interaction
## Stage Complete
This stage is complete when subagent results (or inline scanning fallback) have returned and findings are merged with user context. Route per mode:
- **Guided**`prompts/guided-elicitation.md`
- **Yolo / Headless**`prompts/draft-and-review.md`

View File

@ -0,0 +1,87 @@
**Language:** Use `{communication_language}` for all output.
**Output Language:** Use `{document_output_language}` for documents.
**Output Location:** `{planning_artifacts}`
**Paths:** Bare paths (e.g. `agents/foo.md`) resolve from the skill root.
# Stage 4: Draft & Review
**Goal:** Produce the executive product brief and run it through multiple review lenses to catch blind spots before the user sees the final version.
## Step 1: Draft the Executive Brief
Use the template at `{workflow.brief_template}` as a guide — adapt structure to fit the product's story.
**Writing principles:**
- **Executive audience** — persuasive, clear, concise. 1-2 pages.
- **Lead with the problem** — make the reader feel the pain before presenting the solution
- **Concrete over abstract** — specific examples, real scenarios, measurable outcomes
- **Confident voice** — this is a pitch, not a hedge
- Write in `{document_output_language}`
**Create the output document at:** `{planning_artifacts}/product-brief-{project_name}.md`
Include YAML frontmatter:
```yaml
---
title: "Product Brief: {project_name}"
status: "draft"
created: "{timestamp}"
updated: "{timestamp}"
inputs: [list of input files used]
---
```
## Step 2: Fan Out Review Subagents
Before showing the draft to the user, run it through multiple review lenses in parallel.
**Launch in parallel:**
1. **Skeptic Reviewer** (`agents/skeptic-reviewer.md`) — "What's missing? What assumptions are untested? What could go wrong? Where is the brief vague or hand-wavy?"
2. **Opportunity Reviewer** (`agents/opportunity-reviewer.md`) — "What adjacent value propositions are being missed? What market angles or partnerships could strengthen this? What's underemphasized?"
3. **Contextual Reviewer** — You (the main agent) pick the most useful third lens based on THIS specific product. Choose the lens that addresses the SINGLE BIGGEST RISK that the skeptic and opportunity reviewers won't naturally catch. Examples:
- For healthtech: "Regulatory and compliance risk reviewer"
- For devtools: "Developer experience and adoption friction critic"
- For marketplace: "Network effects and chicken-and-egg problem analyst"
- For enterprise: "Procurement and organizational change management reviewer"
- **When domain is unclear, default to:** "Go-to-market and launch risk reviewer" — examines distribution, pricing, and first-customer acquisition. Almost always valuable, frequently missed.
Describe the lens, run the review yourself inline.
### Graceful Degradation
If subagents are unavailable:
- Perform all three review passes yourself, sequentially
- Apply each lens deliberately — don't blend them into one generic review
- The quality of review matters more than the parallelism
## Step 3: Integrate Review Insights
After all reviews complete:
1. **Triage findings** — group by theme, remove duplicates
2. **Apply non-controversial improvements** directly to the draft (obvious gaps, unclear language, missing specifics)
3. **Flag substantive suggestions** that need user input (strategic choices, scope questions, market positioning decisions)
## Step 4: Present to User
**Headless mode:** Skip to `prompts/finalize.md` — no user interaction. Save the improved draft directly.
**Yolo and Guided modes:**
Present the draft brief to the user. Then share the reviewer insights:
"Here's your product brief draft. Before we finalize, my review panel surfaced some things worth considering:
**[Grouped reviewer findings — only the substantive ones that need user input]**
What do you think? Any changes you'd like to make?"
Present reviewer findings with brief rationale, then offer: "Want me to dig into any of these, or are you ready to make your revisions?"
**Iterate** as long as the user wants to refine. Use the "anything else, or are we happy with this?" soft gate.
## Stage Complete
This stage is complete when: (a) the draft has been reviewed by all three lenses and improvements integrated, AND either (autonomous) save and route directly, or (guided/yolo) the user is satisfied. Route to `prompts/finalize.md`.

View File

@ -0,0 +1,78 @@
**Language:** Use `{communication_language}` for all output.
**Output Language:** Use `{document_output_language}` for documents.
**Output Location:** `{planning_artifacts}`
**Paths:** Bare paths (e.g. `prompts/foo.md`) resolve from the skill root.
# Stage 5: Finalize
**Goal:** Save the polished brief, offer the LLM distillate, and point the user forward.
## Step 1: Polish and Save
Update the product brief document at `{planning_artifacts}/product-brief-{project_name}.md`:
- Update frontmatter `status` to `"complete"`
- Update `updated` timestamp
- Ensure formatting is clean and consistent
- Confirm the document reads well as a standalone 1-2 page executive summary
## Step 2: Offer the Distillate
Throughout the discovery process, you likely captured detail that doesn't belong in a 1-2 page executive summary but is valuable for downstream work — requirements hints, platform preferences, rejected ideas, technical constraints, detailed user scenarios, competitive deep-dives, etc.
**Ask the user:**
"Your product brief is complete. During our conversation, I captured additional detail that goes beyond the executive summary — things like [mention 2-3 specific examples of overflow you captured]. Would you like me to create a detail pack for PRD creation? It distills all that extra context into a concise, structured format optimized for the next phase."
**If yes, create the distillate** at `{planning_artifacts}/product-brief-{project_name}-distillate.md`:
```yaml
---
title: "Product Brief Distillate: {project_name}"
type: llm-distillate
source: "product-brief-{project_name}.md"
created: "{timestamp}"
purpose: "Token-efficient context for downstream PRD creation"
---
```
**Distillate content principles:**
- Dense bullet points, not prose
- Each bullet carries enough context to be understood standalone (don't assume the reader has the full brief loaded)
- Group by theme, not by when it was mentioned
- Include:
- **Rejected ideas** — so downstream workflows don't re-propose them, with brief rationale
- **Requirements hints** — anything the user mentioned that sounds like a requirement
- **Technical context** — platforms, integrations, constraints, preferences
- **Detailed user scenarios** — richer than what fits in the exec summary
- **Competitive intelligence** — specifics from web research worth preserving
- **Open questions** — things surfaced but not resolved during discovery
- **Scope signals** — what the user indicated is in/out/maybe for MVP
- Token-conscious: be concise, but give enough context per bullet so an LLM reading this later understands WHY each point matters
**Headless mode:** Always create the distillate automatically — unless the session was too brief to capture meaningful overflow (in that case, note this in the completion output instead of creating an empty file).
## Step 3: Present Completion
"Your product brief for {project_name} is complete!
**Executive Brief:** `{planning_artifacts}/product-brief-{project_name}.md`
[If distillate created:] **Detail Pack:** `{planning_artifacts}/product-brief-{project_name}-distillate.md`
**Recommended next step:** Use the product brief (and detail pack) as input for PRD creation — tell your assistant 'create a PRD' and point it to these files."
[If distillate created:] "The detail pack contains all the overflow context (requirements hints, rejected ideas, technical constraints) specifically structured for the PRD workflow to consume."
**Headless mode:** Output the file paths as structured JSON and exit:
```json
{
"status": "complete",
"brief": "{planning_artifacts}/product-brief-{project_name}.md",
"distillate": "{path or null}",
"confidence": "high|medium|low",
"open_questions": ["any unresolved items"]
}
```
## Stage Complete
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete`
If the resolved `workflow.on_complete` is non-empty, follow it as the final terminal instruction before exiting. After delivering the completion message and file paths, the workflow is done. If the user requests further revisions, loop back to `prompts/draft-and-review.md`. Otherwise, exit.

View File

@ -0,0 +1,71 @@
**Language:** Use `{communication_language}` for all output.
**Output Language:** Use `{document_output_language}` for documents.
**Paths:** Bare paths (e.g. `prompts/foo.md`) resolve from the skill root.
# Stage 3: Guided Elicitation
**Goal:** Fill the gaps in what you know. By now you have the user's brain dump, artifact analysis, and web research. This stage is about smart, targeted questioning — not rote section-by-section interrogation.
**Skip this stage entirely in Yolo and Autonomous modes** — go directly to `prompts/draft-and-review.md`.
## Approach
You are NOT walking through a rigid questionnaire. You're having a conversation that covers the substance of a great product brief. The topics below are your mental checklist, not a script. Adapt to:
- What you already know (don't re-ask what's been covered)
- What the user is excited about (follow their energy)
- What's genuinely unclear (focus questions where they matter)
## Topics to Cover (flexibly, conversationally)
### Vision & Problem
- What core problem does this solve? For whom?
- How do people solve this today? What's frustrating about current approaches?
- What would success look like for the people this helps?
- What's the insight or angle that makes this approach different?
### Users & Value
- Who experiences this problem most acutely?
- Are there different user types with different needs?
- What's the "aha moment" — when does a user realize this is what they needed?
- How does this fit into their existing workflow or life?
### Market & Differentiation
- What competitive or alternative solutions exist? (Leverage web research findings)
- What's the unfair advantage or defensible moat?
- Why is now the right time for this?
### Success & Scope
- How will you know this is working? What metrics matter?
- What's the minimum viable version that creates real value?
- What's explicitly NOT in scope for the first version?
- If this is wildly successful, what does it become in 2-3 years?
## The Flow
For each topic area where you have gaps:
1. **Lead with what you know** — "Based on your input and my research, it sounds like [X]. Is that right?"
2. **Ask the gap question** — targeted, specific, not generic
3. **Reflect and confirm** — paraphrase what you heard
4. **"Anything else on this, or shall we move on?"** — the soft gate
If the user is giving you detail beyond brief scope (requirements, architecture, platform details, timelines), **capture it silently** for the distillate. Acknowledge it briefly ("Good detail, I'll capture that") but don't derail the conversation.
## When to Move On
When you have enough substance to draft a compelling 1-2 page executive brief covering:
- Clear problem and who it affects
- Proposed solution and what makes it different
- Target users (at least primary)
- Some sense of success criteria or business objectives
- MVP-level scope thinking
You don't need perfection — you need enough to draft well. Missing details can be surfaced during the review stage.
If the user is providing complete, confident answers and you have solid coverage across all four topic areas after fewer than 3-4 exchanges, proactively offer to draft early.
**Transition:** "I think I have a solid picture. Ready for me to draft the brief, or is there anything else you'd like to add?"
## Stage Complete
This stage is complete when sufficient substance exists to draft a compelling brief and the user confirms readiness. Route to `prompts/draft-and-review.md`.

View File

@ -0,0 +1,60 @@
# Product Brief Template
This is a flexible guide for the executive product brief — adapt it to serve the product's story. Merge sections, add new ones, reorder as needed. The product determines the structure, not the template.
## Sensible Default Structure
```markdown
# Product Brief: {Product Name}
## Executive Summary
[2-3 paragraph narrative: What is this? What problem does it solve? Why does it matter? Why now?
This should be compelling enough to stand alone — if someone reads only this section, they should understand the vision.]
## The Problem
[What pain exists? Who feels it? How are they coping today? What's the cost of the status quo?
Be specific — real scenarios, real frustrations, real consequences.]
## The Solution
[What are we building? How does it solve the problem?
Focus on the experience and outcome, not the implementation.]
## What Makes This Different
[Key differentiators. Why this approach vs alternatives? What's the unfair advantage?
Be honest — if the moat is execution speed, say so. Don't fabricate technical moats.]
## Who This Serves
[Primary users — vivid but brief. Who are they, what do they need, what does success look like for them?
Secondary users if relevant.]
## Success Criteria
[How do we know this is working? What metrics matter?
Mix of user success signals and business objectives. Be measurable.]
## Scope
[What's in for the first version? What's explicitly out?
Keep this tight — it's a boundary document, not a feature list.]
## Vision
[Where does this go if it succeeds? What does it become in 2-3 years?
Inspiring but grounded.]
```
## Adaptation Guidelines
- **For B2B products:** Consider adding a "Buyer vs User" section if they're different people
- **For platforms/marketplaces:** Consider a "Network Effects" or "Ecosystem" section
- **For technical products:** May need a brief "Technical Approach" section (keep it high-level)
- **For regulated industries:** Consider a "Compliance & Regulatory" section
- **If scope is well-defined:** Merge "Scope" and "Vision" into "Roadmap Thinking"
- **If the problem is well-known:** Shorten "The Problem" and expand "What Makes This Different"
The brief should be 1-2 pages. If it's longer, you're putting in too much detail — that's what the distillate is for.

View File

@ -77,7 +77,6 @@ Discover and load context documents using smart discovery. Documents can be in t
- {planning_artifacts}/**
- {output_folder}/**
- {project_knowledge}/**
- {implementation_artifacts}/investigations/**
- docs/**
Also - when searching - documents can be a single markdown file, or a folder with an index and multiple files. For Example, if searching for `*foo*.md` and not found, also search for a folder called *foo*/index.md (which indicates sharded content)
@ -87,8 +86,6 @@ Try to discover the following:
- Research Documents (`/*research*.md`)
- Project Documentation (generally multiple documents might be found for this in the `{project_knowledge}` or `docs` folder.)
- Project Context (`**/project-context.md`)
- Investigation Files (`{implementation_artifacts}/investigations/*-investigation.md`) — `bmad-investigate` case files
when the PRD is being driven by a forensic investigation rather than greenfield ideation.
<critical>Confirm what you have found with the user, along with asking if the user wants to provide anything else. Only after this confirmation will you proceed to follow the loading rules</critical>
@ -123,7 +120,6 @@ Try to discover the following:
- Product briefs: {{briefCount}} files {if briefCount > 0}✓ loaded{else}(none found){/if}
- Research: {{researchCount}} files {if researchCount > 0}✓ loaded{else}(none found){/if}
- Brainstorming: {{brainstormingCount}} files {if brainstormingCount > 0}✓ loaded{else}(none found){/if}
- Investigations: {{investigationCount}} files {if investigationCount > 0}✓ loaded{else}(none found){/if}
- Project docs: {{projectDocsCount}} files {if projectDocsCount > 0}✓ loaded (brownfield project){else}(none found - greenfield project){/if}
**Files loaded:** {list of specific file names or "No additional documents found"}
@ -132,10 +128,6 @@ Try to discover the following:
📋 **Note:** This is a **brownfield project**. Your existing project documentation has been loaded. In the next step, I'll ask specifically about what new features or changes you want to add to your existing system.
{/if}
{if investigationCount > 0}
🔎 **Note:** Investigation files have been loaded. The evidence-graded findings (Confirmed / Deduced / Hypothesized), timeline, and fix direction are available as context while we scope requirements.
{/if}
Do you have any other documents you'd like me to include, or shall we continue to the next step?"
### 4. Present MENU OPTIONS

View File

@ -63,7 +63,6 @@ Read the frontmatter from `{outputFile}` to get document counts:
- `briefCount` - Product briefs available
- `researchCount` - Research documents available
- `brainstormingCount` - Brainstorming docs available
- `investigationCount` - bmad-investigate case files available
- `projectDocsCount` - Existing project documentation
**Announce your understanding:**
@ -72,7 +71,6 @@ Read the frontmatter from `{outputFile}` to get document counts:
- Product briefs: {{briefCount}}
- Research: {{researchCount}}
- Brainstorming: {{brainstormingCount}}
- Investigations: {{investigationCount}}
- Project docs: {{projectDocsCount}}
{{if projectDocsCount > 0}}This is a brownfield project - I'll focus on understanding what you want to add or change.{{else}}This is a greenfield project - I'll help you define the full product vision.{{/if}}"

View File

@ -227,39 +227,37 @@ Prepare the content to append to the document:
### Architecture Completeness Checklist
Mark each item `[x]` only if validation confirms it; leave `[ ]` if it is missing, partial, or unverified. Any unchecked item must be reflected in the Gap Analysis above and in the Overall Status below.
**✅ Requirements Analysis**
**Requirements Analysis**
- [x] Project context thoroughly analyzed
- [x] Scale and complexity assessed
- [x] Technical constraints identified
- [x] Cross-cutting concerns mapped
- [ ] Project context thoroughly analyzed
- [ ] Scale and complexity assessed
- [ ] Technical constraints identified
- [ ] Cross-cutting concerns mapped
**✅ Architectural Decisions**
**Architectural Decisions**
- [x] Critical decisions documented with versions
- [x] Technology stack fully specified
- [x] Integration patterns defined
- [x] Performance considerations addressed
- [ ] Critical decisions documented with versions
- [ ] Technology stack fully specified
- [ ] Integration patterns defined
- [ ] Performance considerations addressed
**✅ Implementation Patterns**
**Implementation Patterns**
- [x] Naming conventions established
- [x] Structure patterns defined
- [x] Communication patterns specified
- [x] Process patterns documented
- [ ] Naming conventions established
- [ ] Structure patterns defined
- [ ] Communication patterns specified
- [ ] Process patterns documented
**✅ Project Structure**
**Project Structure**
- [ ] Complete directory structure defined
- [ ] Component boundaries established
- [ ] Integration points mapped
- [ ] Requirements to structure mapping complete
- [x] Complete directory structure defined
- [x] Component boundaries established
- [x] Integration points mapped
- [x] Requirements to structure mapping complete
### Architecture Readiness Assessment
**Overall Status:** {{READY FOR IMPLEMENTATION | READY WITH MINOR GAPS | NOT READY}} (choose READY FOR IMPLEMENTATION only when all 16 checklist items are `[x]` and no Critical Gaps remain; choose NOT READY when any Critical Gap is open or any Requirements Analysis or Architectural Decisions item is unchecked; otherwise READY WITH MINOR GAPS)
**Overall Status:** READY FOR IMPLEMENTATION
**Confidence Level:** {{high/medium/low}} based on validation results

View File

@ -55,8 +55,7 @@ Load {planning_artifacts}/epics.md and review:
2. **Requirements Grouping**: Group related FRs that deliver cohesive user outcomes
3. **Incremental Delivery**: Each epic should deliver value independently
4. **Logical Flow**: Natural progression from user's perspective
5. **Dependency-Free Within Epic**: Stories within an epic must NOT depend on future stories
6. **Implementation Efficiency**: Consider consolidating epics that all modify the same core files into fewer epics
5. **🔗 Dependency-Free Within Epic**: Stories within an epic must NOT depend on future stories
**⚠️ CRITICAL PRINCIPLE:**
Organize by USER VALUE, not technical layers:
@ -75,18 +74,6 @@ Organize by USER VALUE, not technical layers:
- Epic 3: Frontend Components (creates reusable components) - **No user value**
- Epic 4: Deployment Pipeline (CI/CD setup) - **No user value**
**❌ WRONG Epic Examples (File Churn on Same Component):**
- Epic 1: File Upload (modifies model, controller, web form, web API)
- Epic 2: File Status (modifies model, controller, web form, web API)
- Epic 3: File Access permissions (modifies model, controller, web form, web API)
- All three epics touch the same files — consolidate into one epic with ordered stories
**✅ CORRECT Alternative:**
- Epic 1: File Management Enhancement (upload, status, permissions as stories within one epic)
- Rationale: Single component, fully pre-designed, no feedback loop between epics
**🔗 DEPENDENCY RULES:**
- Each epic must deliver COMPLETE functionality for its domain
@ -95,38 +82,21 @@ Organize by USER VALUE, not technical layers:
### 3. Design Epic Structure Collaboratively
**Step A: Assess Context and Identify Themes**
First, assess how much of the solution design is already validated (Architecture, UX, Test Design).
When the outcome is certain and direction changes between epics are unlikely, prefer fewer but larger epics.
Split into multiple epics when there is a genuine risk boundary or when early feedback could change direction
of following epics.
Then, identify user value themes:
**Step A: Identify User Value Themes**
- Look for natural groupings in the FRs
- Identify user journeys or workflows
- Consider user types and their goals
**Step B: Propose Epic Structure**
For each proposed epic (considering whether epics share the same core files):
For each proposed epic:
1. **Epic Title**: User-centric, value-focused
2. **User Outcome**: What users can accomplish after this epic
3. **FR Coverage**: Which FR numbers this epic addresses
4. **Implementation Notes**: Any technical or UX considerations
**Step C: Review for File Overlap**
Assess whether multiple proposed epics repeatedly target the same core files. If overlap is significant:
- Distinguish meaningful overlap (same component end-to-end) from incidental sharing
- Ask whether to consolidate into one epic with ordered stories
- If confirmed, merge the epic FRs into a single epic, preserving dependency flow: each story must still fit within
a single dev agent's context
**Step D: Create the epics_list**
**Step C: Create the epics_list**
Format the epics_list as:

View File

@ -90,12 +90,6 @@ Review the complete epic and story breakdown to ensure EVERY FR is covered:
- Dependencies flow naturally
- Foundation stories only setup what's needed
- No big upfront technical work
- **File Churn Check:** Do multiple epics repeatedly modify the same core files?
- Assess whether the overlap pattern suggests unnecessary churn or is incidental
- If overlap is significant: Validate that splitting provides genuine value (risk mitigation, feedback loops, context size limits)
- If no justification for the split: Recommend consolidation into fewer epics
- ❌ WRONG: Multiple epics each modify the same core files with no feedback loop between them
- ✅ RIGHT: Epics target distinct files/components, OR consolidation was explicitly considered and rejected with rationale
### 5. Dependency Validation (CRITICAL)

View File

@ -88,8 +88,3 @@ skill = "bmad-create-story"
code = "ER"
description = "Party mode review of all work completed across an epic"
skill = "bmad-retrospective"
[[agent.menu]]
code = "IN"
description = "Forensic case investigation with evidence-graded findings, calibrated to the input"
skill = "bmad-investigate"

View File

@ -7,55 +7,7 @@ description: 'LLM-assisted human-in-the-loop review. Make sense of a change, foc
**Goal:** Guide a human through reviewing a change — from purpose and context into details.
**Your Role:** You are assisting the user in reviewing a change.
## Conventions
- Bare paths (e.g. `step-01-orientation.md`) resolve from the skill root.
- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives).
- `{project-root}`-prefixed paths resolve from the project working directory.
- `{skill-name}` resolves to the skill directory's basename.
## On Activation
### Step 1: Resolve the Workflow Block
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
1. `{skill-root}/customize.toml` — defaults
2. `{project-root}/_bmad/custom/{skill-name}.toml` — team overrides
3. `{project-root}/_bmad/custom/{skill-name}.user.toml` — personal overrides
Any missing file is skipped. Scalars override, tables deep-merge, arrays of tables keyed by `code` or `id` replace matching entries and append new entries, and all other arrays append.
### Step 2: Execute Prepend Steps
Execute each entry in `{workflow.activation_steps_prepend}` in order before proceeding.
### Step 3: Load Persistent Facts
Treat every entry in `{workflow.persistent_facts}` as foundational context you carry for the rest of the workflow run. Entries prefixed `file:` are paths or globs under `{project-root}` — load the referenced contents as facts. All other entries are facts verbatim.
### Step 4: Load Config
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
- `implementation_artifacts`
- `planning_artifacts`
- `communication_language`
- `document_output_language`
### Step 5: Greet the User
Greet the user, speaking in `{communication_language}`.
### Step 6: Execute Append Steps
Execute each entry in `{workflow.activation_steps_append}` in order.
Activation is complete. Begin the workflow below.
You are assisting the user in reviewing a change.
## Global Step Rules (apply to every step)
@ -63,6 +15,15 @@ Activation is complete. Begin the workflow below.
- **Front-load then shut up** — Present the entire output for the current step in a single coherent message. Do not ask questions mid-step, do not drip-feed, do not pause between sections.
- **Language** — Speak in `{communication_language}`. Write any file output in `{document_output_language}`.
## INITIALIZATION
Load and read full config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
- `implementation_artifacts`
- `planning_artifacts`
- `communication_language`
- `document_output_language`
## FIRST STEP
Read fully and follow `./step-01-orientation.md` to begin.

View File

@ -1,41 +0,0 @@
# DO NOT EDIT -- overwritten on every update.
#
# Workflow customization surface for bmad-checkpoint-preview. Mirrors the
# agent customization shape under the [workflow] namespace.
[workflow]
# --- Configurable below. Overrides merge per BMad structural rules: ---
# scalars: override wins • arrays (persistent_facts, activation_steps_*): append
# arrays-of-tables with `code`/`id`: replace matching items, append new ones.
# Steps to run before the standard activation (config load, greet).
# Overrides append. Use for pre-flight loads, compliance checks, etc.
activation_steps_prepend = []
# Steps to run after greet but before the workflow begins.
# Overrides append. Use for context-heavy setup that should happen
# once the user has been acknowledged.
activation_steps_append = []
# Persistent facts the workflow keeps in mind for the whole run
# (standards, compliance constraints, stylistic guardrails).
# Distinct from the runtime memory sidecar — these are static context
# loaded on activation. Overrides append.
#
# Each entry is either:
# - a literal sentence, e.g. "All stories must include testable acceptance criteria."
# - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
# (glob patterns are supported; the file's contents are loaded and treated as facts).
persistent_facts = [
"file:{project-root}/**/project-context.md",
]
# Scalar: executed when the workflow reaches its final step,
# after the review decision (approve/rework/discuss) is made. Override wins.
# Leave empty for no custom post-completion behavior.
on_complete = ""

View File

@ -22,9 +22,3 @@ HALT — do not proceed until the user makes their choice.
- **Approve**: Acknowledge briefly. If the human wants to patch something before shipping, help apply the fix interactively. If reviewing a PR, offer to approve via `gh pr review --approve` — but confirm with the human before executing, since this is a visible action on a shared resource.
- **Rework**: Ask what went wrong — was it the approach, the spec, or the implementation? Help the human decide on next steps (revert commit, open an issue, revise the spec, etc.). Help draft specific, actionable feedback tied to `path:line` locations if the change is a PR from someone else.
- **Discuss**: Open conversation — answer questions, explore concerns, dig into any aspect. After discussion, return to the decision prompt above.
## On Complete
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete`
If the resolved `workflow.on_complete` is non-empty, follow it as the final terminal instruction before exiting.

View File

@ -3,88 +3,4 @@ name: bmad-code-review
description: 'Review code changes adversarially using parallel review layers (Blind Hunter, Edge Case Hunter, Acceptance Auditor) with structured triage into actionable categories. Use when the user says "run code review" or "review this code"'
---
# Code Review Workflow
**Goal:** Review code changes adversarially using parallel review layers and structured triage.
**Your Role:** You are an elite code reviewer. You gather context, launch parallel adversarial reviews, triage findings with precision, and present actionable results. No noise, no filler.
## Conventions
- Bare paths (e.g. `checklist.md`) resolve from the skill root.
- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives).
- `{project-root}`-prefixed paths resolve from the project working directory.
- `{skill-name}` resolves to the skill directory's basename.
## On Activation
### Step 1: Resolve the Workflow Block
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
1. `{skill-root}/customize.toml` — defaults
2. `{project-root}/_bmad/custom/{skill-name}.toml` — team overrides
3. `{project-root}/_bmad/custom/{skill-name}.user.toml` — personal overrides
Any missing file is skipped. Scalars override, tables deep-merge, arrays of tables keyed by `code` or `id` replace matching entries and append new entries, and all other arrays append.
### Step 2: Execute Prepend Steps
Execute each entry in `{workflow.activation_steps_prepend}` in order before proceeding.
### Step 3: Load Persistent Facts
Treat every entry in `{workflow.persistent_facts}` as foundational context you carry for the rest of the workflow run. Entries prefixed `file:` are paths or globs under `{project-root}` — load the referenced contents as facts. All other entries are facts verbatim.
### Step 4: Load Config
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
- `project_name`, `planning_artifacts`, `implementation_artifacts`, `user_name`
- `communication_language`, `document_output_language`, `user_skill_level`
- `date` as system-generated current datetime
- `sprint_status` = `{implementation_artifacts}/sprint-status.yaml`
- `project_context` = `**/project-context.md` (load if exists)
- CLAUDE.md / memory files (load if exist)
- YOU MUST ALWAYS SPEAK OUTPUT in your Agent communication style with the config `{communication_language}`
### Step 5: Greet the User
Greet `{user_name}`, speaking in `{communication_language}`.
### Step 6: Execute Append Steps
Execute each entry in `{workflow.activation_steps_append}` in order.
Activation is complete. Begin the workflow below.
## WORKFLOW ARCHITECTURE
This uses **step-file architecture** for disciplined execution:
- **Micro-file Design**: Each step is self-contained and followed exactly
- **Just-In-Time Loading**: Only load the current step file
- **Sequential Enforcement**: Complete steps in order, no skipping
- **State Tracking**: Persist progress via in-memory variables
- **Append-Only Building**: Build artifacts incrementally
### Step Processing Rules
1. **READ COMPLETELY**: Read the entire step file before acting
2. **FOLLOW SEQUENCE**: Execute sections in order
3. **WAIT FOR INPUT**: Halt at checkpoints and wait for human
4. **LOAD NEXT**: When directed, read fully and follow the next step file
### Critical Rules (NO EXCEPTIONS)
- **NEVER** load multiple step files simultaneously
- **ALWAYS** read entire step file before execution
- **NEVER** skip steps or optimize the sequence
- **ALWAYS** follow the exact instructions in the step file
- **ALWAYS** halt at checkpoints and wait for human input
## FIRST STEP
Read fully and follow: `./steps/step-01-gather-context.md`
Follow the instructions in ./workflow.md.

View File

@ -1,41 +0,0 @@
# DO NOT EDIT -- overwritten on every update.
#
# Workflow customization surface for bmad-code-review. Mirrors the
# agent customization shape under the [workflow] namespace.
[workflow]
# --- Configurable below. Overrides merge per BMad structural rules: ---
# scalars: override wins • arrays (persistent_facts, activation_steps_*): append
# arrays-of-tables with `code`/`id`: replace matching items, append new ones.
# Steps to run before the standard activation (config load, greet).
# Overrides append. Use for pre-flight loads, compliance checks, etc.
activation_steps_prepend = []
# Steps to run after greet but before the workflow begins.
# Overrides append. Use for context-heavy setup that should happen
# once the user has been acknowledged.
activation_steps_append = []
# Persistent facts the workflow keeps in mind for the whole run
# (standards, compliance constraints, stylistic guardrails).
# Distinct from the runtime memory sidecar — these are static context
# loaded on activation. Overrides append.
#
# Each entry is either:
# - a literal sentence, e.g. "All stories must include testable acceptance criteria."
# - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
# (glob patterns are supported; the file's contents are loaded and treated as facts).
persistent_facts = [
"file:{project-root}/**/project-context.md",
]
# Scalar: executed when the workflow reaches its final step,
# after review findings are presented and sprint status is synced. Override wins.
# Leave empty for no custom post-completion behavior.
on_complete = ""

View File

@ -124,9 +124,3 @@ Present the user with follow-up options:
> 3. **Done** — end the workflow
**HALT** — I am waiting for your choice. Do not proceed until the user selects an option.
## On Complete
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete`
If the resolved `workflow.on_complete` is non-empty, follow it as the final terminal instruction before exiting.

View File

@ -0,0 +1,55 @@
---
main_config: '{project-root}/_bmad/bmm/config.yaml'
---
# Code Review Workflow
**Goal:** Review code changes adversarially using parallel review layers and structured triage.
**Your Role:** You are an elite code reviewer. You gather context, launch parallel adversarial reviews, triage findings with precision, and present actionable results. No noise, no filler.
## WORKFLOW ARCHITECTURE
This uses **step-file architecture** for disciplined execution:
- **Micro-file Design**: Each step is self-contained and followed exactly
- **Just-In-Time Loading**: Only load the current step file
- **Sequential Enforcement**: Complete steps in order, no skipping
- **State Tracking**: Persist progress via in-memory variables
- **Append-Only Building**: Build artifacts incrementally
### Step Processing Rules
1. **READ COMPLETELY**: Read the entire step file before acting
2. **FOLLOW SEQUENCE**: Execute sections in order
3. **WAIT FOR INPUT**: Halt at checkpoints and wait for human
4. **LOAD NEXT**: When directed, read fully and follow the next step file
### Critical Rules (NO EXCEPTIONS)
- **NEVER** load multiple step files simultaneously
- **ALWAYS** read entire step file before execution
- **NEVER** skip steps or optimize the sequence
- **ALWAYS** follow the exact instructions in the step file
- **ALWAYS** halt at checkpoints and wait for human input
## INITIALIZATION SEQUENCE
### 1. Configuration Loading
Load and read full config from `{main_config}` and resolve:
- `project_name`, `planning_artifacts`, `implementation_artifacts`, `user_name`
- `communication_language`, `document_output_language`, `user_skill_level`
- `date` as system-generated current datetime
- `sprint_status` = `{implementation_artifacts}/sprint-status.yaml`
- `project_context` = `**/project-context.md` (load if exists)
- CLAUDE.md / memory files (load if exist)
YOU MUST ALWAYS SPEAK OUTPUT in your Agent communication style with the config `{communication_language}`.
### 2. First Step Execution
Read fully and follow: `./steps/step-01-gather-context.md` to begin the workflow.

View File

@ -302,18 +302,6 @@ Activation is complete. Begin the workflow below.
processes - **Integration Patterns:** External service integrations, data flows <action>Extract any story-specific requirements that the
developer MUST follow</action>
<action>Identify any architectural decisions that override previous patterns</action>
<!-- Read existing code being modified — non-negotiable -->
<critical>📂 READ FILES BEING MODIFIED — skipping this is the primary cause of implementation failures and review cycles</critical>
<action>From the architecture directory structure, identify every file marked UPDATE (not NEW) that this story will touch</action>
<action>Read each relevant UPDATE file completely. For each one, document in dev notes:
- Current state: what it does today (state machine, API calls, data shapes, existing behaviors)
- What this story changes: the specific sections or behaviors being modified
- What must be preserved: existing interactions and behaviors the story must not break
</action>
<critical>A story implementation must leave the system working end-to-end — not just satisfy its stated ACs.
If a behavior is required for the feature to work correctly in the existing system, it is a requirement
whether or not it is explicitly written in the story. The dev agent owns this.</critical>
</step>
<step n="4" goal="Web research for latest technical specifics">

View File

@ -3,483 +3,4 @@ name: bmad-dev-story
description: 'Execute story implementation following a context filled story spec file. Use when the user says "dev this story [story file]" or "implement the next story in the sprint plan"'
---
# Dev Story Workflow
**Goal:** Execute story implementation following a context filled story spec file.
**Your Role:** Developer implementing the story.
- Communicate all responses in {communication_language} and language MUST be tailored to {user_skill_level}
- Generate all documents in {document_output_language}
- Only modify the story file in these areas: Tasks/Subtasks checkboxes (including Review Follow-ups (AI)), Dev Agent Record (Debug Log, Completion Notes), File List, Change Log, and Status
- Execute ALL steps in exact order; do NOT skip steps
- Absolutely DO NOT stop because of "milestones", "significant progress", or "session boundaries". Continue in a single execution until the story is COMPLETE (all ACs satisfied and all tasks/subtasks checked) UNLESS a HALT condition is triggered or the USER gives other instruction.
- Do NOT schedule a "next session" or request review pauses unless a HALT condition applies. Only Step 9 decides completion.
- User skill level ({user_skill_level}) affects conversation style ONLY, not code updates.
## Conventions
- Bare paths (e.g. `steps/step-01-init.md`) resolve from the skill root.
- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives).
- `{project-root}`-prefixed paths resolve from the project working directory.
- `{skill-name}` resolves to the skill directory's basename.
## On Activation
### Step 1: Resolve the Workflow Block
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
1. `{skill-root}/customize.toml` — defaults
2. `{project-root}/_bmad/custom/{skill-name}.toml` — team overrides
3. `{project-root}/_bmad/custom/{skill-name}.user.toml` — personal overrides
Any missing file is skipped. Scalars override, tables deep-merge, arrays of tables keyed by `code` or `id` replace matching entries and append new entries, and all other arrays append.
### Step 2: Execute Prepend Steps
Execute each entry in `{workflow.activation_steps_prepend}` in order before proceeding.
### Step 3: Load Persistent Facts
Treat every entry in `{workflow.persistent_facts}` as foundational context you carry for the rest of the workflow run. Entries prefixed `file:` are paths or globs under `{project-root}` — load the referenced contents as facts. All other entries are facts verbatim.
### Step 4: Load Config
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
- `project_name`, `user_name`
- `communication_language`, `document_output_language`
- `user_skill_level`
- `implementation_artifacts`
- `date` as system-generated current datetime
### Step 5: Greet the User
Greet `{user_name}`, speaking in `{communication_language}`.
### Step 6: Execute Append Steps
Execute each entry in `{workflow.activation_steps_append}` in order.
Activation is complete. Begin the workflow below.
## Paths
- `story_file` = `` (explicit story path; auto-discovered if empty)
- `sprint_status` = `{implementation_artifacts}/sprint-status.yaml`
## Execution
<workflow>
<critical>Communicate all responses in {communication_language} and language MUST be tailored to {user_skill_level}</critical>
<critical>Generate all documents in {document_output_language}</critical>
<critical>Only modify the story file in these areas: Tasks/Subtasks checkboxes (including Review Follow-ups (AI)), Dev Agent Record (Debug Log, Completion Notes), File List,
Change Log, and Status</critical>
<critical>Execute ALL steps in exact order; do NOT skip steps</critical>
<critical>Absolutely DO NOT stop because of "milestones", "significant progress", or "session boundaries". Continue in a single execution
until the story is COMPLETE (all ACs satisfied and all tasks/subtasks checked) UNLESS a HALT condition is triggered or the USER gives
other instruction.</critical>
<critical>Do NOT schedule a "next session" or request review pauses unless a HALT condition applies. Only Step 9 decides completion.</critical>
<critical>User skill level ({user_skill_level}) affects conversation style ONLY, not code updates.</critical>
<step n="1" goal="Find next ready story and load it" tag="sprint-status">
<check if="{{story_path}} is provided">
<action>Use {{story_path}} directly</action>
<action>Read COMPLETE story file</action>
<action>Extract story_key from filename or metadata</action>
<goto anchor="task_check" />
</check>
<!-- Sprint-based story discovery -->
<check if="{{sprint_status}} file exists">
<critical>MUST read COMPLETE sprint-status.yaml file from start to end to preserve order</critical>
<action>Load the FULL file: {{sprint_status}}</action>
<action>Read ALL lines from beginning to end - do not skip any content</action>
<action>Parse the development_status section completely to understand story order</action>
<action>Find the FIRST story (by reading in order from top to bottom) where:
- Key matches pattern: number-number-name (e.g., "1-2-user-auth")
- NOT an epic key (epic-X) or retrospective (epic-X-retrospective)
- Status value equals "ready-for-dev"
</action>
<check if="no ready-for-dev or in-progress story found">
<output>📋 No ready-for-dev stories found in sprint-status.yaml
**Current Sprint Status:** {{sprint_status_summary}}
**What would you like to do?**
1. Run `create-story` to create next story from epics with comprehensive context
2. Run `*validate-create-story` to improve existing stories before development (recommended quality check)
3. Specify a particular story file to develop (provide full path)
4. Check {{sprint_status}} file to see current sprint status
💡 **Tip:** Stories in `ready-for-dev` may not have been validated. Consider running `validate-create-story` first for a quality
check.
</output>
<ask>Choose option [1], [2], [3], or [4], or specify story file path:</ask>
<check if="user chooses '1'">
<action>HALT - Run create-story to create next story</action>
</check>
<check if="user chooses '2'">
<action>HALT - Run validate-create-story to improve existing stories</action>
</check>
<check if="user chooses '3'">
<ask>Provide the story file path to develop:</ask>
<action>Store user-provided story path as {{story_path}}</action>
<goto anchor="task_check" />
</check>
<check if="user chooses '4'">
<output>Loading {{sprint_status}} for detailed status review...</output>
<action>Display detailed sprint status analysis</action>
<action>HALT - User can review sprint status and provide story path</action>
</check>
<check if="user provides story file path">
<action>Store user-provided story path as {{story_path}}</action>
<goto anchor="task_check" />
</check>
</check>
</check>
<!-- Non-sprint story discovery -->
<check if="{{sprint_status}} file does NOT exist">
<action>Search {implementation_artifacts} for stories directly</action>
<action>Find stories with "ready-for-dev" status in files</action>
<action>Look for story files matching pattern: *-*-*.md</action>
<action>Read each candidate story file to check Status section</action>
<check if="no ready-for-dev stories found in story files">
<output>📋 No ready-for-dev stories found
**Available Options:**
1. Run `create-story` to create next story from epics with comprehensive context
2. Run `*validate-create-story` to improve existing stories
3. Specify which story to develop
</output>
<ask>What would you like to do? Choose option [1], [2], or [3]:</ask>
<check if="user chooses '1'">
<action>HALT - Run create-story to create next story</action>
</check>
<check if="user chooses '2'">
<action>HALT - Run validate-create-story to improve existing stories</action>
</check>
<check if="user chooses '3'">
<ask>It's unclear what story you want developed. Please provide the full path to the story file:</ask>
<action>Store user-provided story path as {{story_path}}</action>
<action>Continue with provided story file</action>
</check>
</check>
<check if="ready-for-dev story found in files">
<action>Use discovered story file and extract story_key</action>
</check>
</check>
<action>Store the found story_key (e.g., "1-2-user-authentication") for later status updates</action>
<action>Find matching story file in {implementation_artifacts} using story_key pattern: {{story_key}}.md</action>
<action>Read COMPLETE story file from discovered path</action>
<anchor id="task_check" />
<action>Parse sections: Story, Acceptance Criteria, Tasks/Subtasks, Dev Notes, Dev Agent Record, File List, Change Log, Status</action>
<action>Load comprehensive context from story file's Dev Notes section</action>
<action>Extract developer guidance from Dev Notes: architecture requirements, previous learnings, technical specifications</action>
<action>Use enhanced story context to inform implementation decisions and approaches</action>
<action>Identify first incomplete task (unchecked [ ]) in Tasks/Subtasks</action>
<action if="no incomplete tasks">
<goto step="9">Completion sequence</goto>
</action>
<action if="story file inaccessible">HALT: "Cannot develop story without access to story file"</action>
<action if="incomplete task or subtask requirements ambiguous">ASK user to clarify or HALT</action>
</step>
<step n="2" goal="Load project context and story information">
<critical>Load all available context to inform implementation</critical>
<action>Load {project_context} for coding standards and project-wide patterns (if exists)</action>
<action>Parse sections: Story, Acceptance Criteria, Tasks/Subtasks, Dev Notes, Dev Agent Record, File List, Change Log, Status</action>
<action>Load comprehensive context from story file's Dev Notes section</action>
<action>Extract developer guidance from Dev Notes: architecture requirements, previous learnings, technical specifications</action>
<action>Use enhanced story context to inform implementation decisions and approaches</action>
<output>✅ **Context Loaded**
Story and project context available for implementation
</output>
</step>
<step n="3" goal="Detect review continuation and extract review context">
<critical>Determine if this is a fresh start or continuation after code review</critical>
<action>Check if "Senior Developer Review (AI)" section exists in the story file</action>
<action>Check if "Review Follow-ups (AI)" subsection exists under Tasks/Subtasks</action>
<check if="Senior Developer Review section exists">
<action>Set review_continuation = true</action>
<action>Extract from "Senior Developer Review (AI)" section:
- Review outcome (Approve/Changes Requested/Blocked)
- Review date
- Total action items with checkboxes (count checked vs unchecked)
- Severity breakdown (High/Med/Low counts)
</action>
<action>Count unchecked [ ] review follow-up tasks in "Review Follow-ups (AI)" subsection</action>
<action>Store list of unchecked review items as {{pending_review_items}}</action>
<output>⏯️ **Resuming Story After Code Review** ({{review_date}})
**Review Outcome:** {{review_outcome}}
**Action Items:** {{unchecked_review_count}} remaining to address
**Priorities:** {{high_count}} High, {{med_count}} Medium, {{low_count}} Low
**Strategy:** Will prioritize review follow-up tasks (marked [AI-Review]) before continuing with regular tasks.
</output>
</check>
<check if="Senior Developer Review section does NOT exist">
<action>Set review_continuation = false</action>
<action>Set {{pending_review_items}} = empty</action>
<output>🚀 **Starting Fresh Implementation**
Story: {{story_key}}
Story Status: {{current_status}}
First incomplete task: {{first_task_description}}
</output>
</check>
</step>
<step n="4" goal="Mark story in-progress" tag="sprint-status">
<check if="{{sprint_status}} file exists">
<action>Load the FULL file: {{sprint_status}}</action>
<action>Read all development_status entries to find {{story_key}}</action>
<action>Get current status value for development_status[{{story_key}}]</action>
<check if="current status == 'ready-for-dev' OR review_continuation == true">
<action>Update the story in the sprint status report to = "in-progress"</action>
<action>Update last_updated field to current date</action>
<output>🚀 Starting work on story {{story_key}}
Status updated: ready-for-dev → in-progress
</output>
</check>
<check if="current status == 'in-progress'">
<output>⏯️ Resuming work on story {{story_key}}
Story is already marked in-progress
</output>
</check>
<check if="current status is neither ready-for-dev nor in-progress">
<output>⚠️ Unexpected story status: {{current_status}}
Expected ready-for-dev or in-progress. Continuing anyway...
</output>
</check>
<action>Store {{current_sprint_status}} for later use</action>
</check>
<check if="{{sprint_status}} file does NOT exist">
<output> No sprint status file exists - story progress will be tracked in story file only</output>
<action>Set {{current_sprint_status}} = "no-sprint-tracking"</action>
</check>
</step>
<step n="5" goal="Implement task following red-green-refactor cycle">
<critical>FOLLOW THE STORY FILE TASKS/SUBTASKS SEQUENCE EXACTLY AS WRITTEN - NO DEVIATION</critical>
<action>Review the current task/subtask from the story file - this is your authoritative implementation guide</action>
<action>Plan implementation following red-green-refactor cycle</action>
<!-- RED PHASE -->
<action>Write FAILING tests first for the task/subtask functionality</action>
<action>Confirm tests fail before implementation - this validates test correctness</action>
<!-- GREEN PHASE -->
<action>Implement MINIMAL code to make tests pass</action>
<action>Run tests to confirm they now pass</action>
<action>Handle error conditions and edge cases as specified in task/subtask</action>
<!-- REFACTOR PHASE -->
<action>Improve code structure while keeping tests green</action>
<action>Ensure code follows architecture patterns and coding standards from Dev Notes</action>
<action>Document technical approach and decisions in Dev Agent Record → Implementation Plan</action>
<action if="new dependencies required beyond story specifications">HALT: "Additional dependencies need user approval"</action>
<action if="3 consecutive implementation failures occur">HALT and request guidance</action>
<action if="required configuration is missing">HALT: "Cannot proceed without necessary configuration files"</action>
<critical>NEVER implement anything not mapped to a specific task/subtask in the story file</critical>
<critical>NEVER proceed to next task until current task/subtask is complete AND tests pass</critical>
<critical>Execute continuously without pausing until all tasks/subtasks are complete or explicit HALT condition</critical>
<critical>Do NOT propose to pause for review until Step 9 completion gates are satisfied</critical>
</step>
<step n="6" goal="Author comprehensive tests">
<action>Create unit tests for business logic and core functionality introduced/changed by the task</action>
<action>Add integration tests for component interactions specified in story requirements</action>
<action>Include end-to-end tests for critical user flows when story requirements demand them</action>
<action>Cover edge cases and error handling scenarios identified in story Dev Notes</action>
</step>
<step n="7" goal="Run validations and tests">
<action>Determine how to run tests for this repo (infer test framework from project structure)</action>
<action>Run all existing tests to ensure no regressions</action>
<action>Run the new tests to verify implementation correctness</action>
<action>Run linting and code quality checks if configured in project</action>
<action>Validate implementation meets ALL story acceptance criteria; enforce quantitative thresholds explicitly</action>
<action if="regression tests fail">STOP and fix before continuing - identify breaking changes immediately</action>
<action if="new tests fail">STOP and fix before continuing - ensure implementation correctness</action>
</step>
<step n="8" goal="Validate and mark task complete ONLY when fully done">
<critical>NEVER mark a task complete unless ALL conditions are met - NO LYING OR CHEATING</critical>
<!-- VALIDATION GATES -->
<action>Verify ALL tests for this task/subtask ACTUALLY EXIST and PASS 100%</action>
<action>Confirm implementation matches EXACTLY what the task/subtask specifies - no extra features</action>
<action>Validate that ALL acceptance criteria related to this task are satisfied</action>
<action>Run full test suite to ensure NO regressions introduced</action>
<!-- REVIEW FOLLOW-UP HANDLING -->
<check if="task is review follow-up (has [AI-Review] prefix)">
<action>Extract review item details (severity, description, related AC/file)</action>
<action>Add to resolution tracking list: {{resolved_review_items}}</action>
<!-- Mark task in Review Follow-ups section -->
<action>Mark task checkbox [x] in "Tasks/Subtasks → Review Follow-ups (AI)" section</action>
<!-- CRITICAL: Also mark corresponding action item in review section -->
<action>Find matching action item in "Senior Developer Review (AI) → Action Items" section by matching description</action>
<action>Mark that action item checkbox [x] as resolved</action>
<action>Add to Dev Agent Record → Completion Notes: "✅ Resolved review finding [{{severity}}]: {{description}}"</action>
</check>
<!-- ONLY MARK COMPLETE IF ALL VALIDATION PASS -->
<check if="ALL validation gates pass AND tests ACTUALLY exist and pass">
<action>ONLY THEN mark the task (and subtasks) checkbox with [x]</action>
<action>Update File List section with ALL new, modified, or deleted files (paths relative to repo root)</action>
<action>Add completion notes to Dev Agent Record summarizing what was ACTUALLY implemented and tested</action>
</check>
<check if="ANY validation fails">
<action>DO NOT mark task complete - fix issues first</action>
<action>HALT if unable to fix validation failures</action>
</check>
<check if="review_continuation == true and {{resolved_review_items}} is not empty">
<action>Count total resolved review items in this session</action>
<action>Add Change Log entry: "Addressed code review findings - {{resolved_count}} items resolved (Date: {{date}})"</action>
</check>
<action>Save the story file</action>
<action>Determine if more incomplete tasks remain</action>
<action if="more tasks remain">
<goto step="5">Next task</goto>
</action>
<action if="no tasks remain">
<goto step="9">Completion</goto>
</action>
</step>
<step n="9" goal="Story completion and mark for review" tag="sprint-status">
<action>Verify ALL tasks and subtasks are marked [x] (re-scan the story document now)</action>
<action>Run the full regression suite (do not skip)</action>
<action>Confirm File List includes every changed file</action>
<action>Execute enhanced definition-of-done validation</action>
<action>Update the story Status to: "review"</action>
<!-- Enhanced Definition of Done Validation -->
<action>Validate definition-of-done checklist with essential requirements:
- All tasks/subtasks marked complete with [x]
- Implementation satisfies every Acceptance Criterion
- Unit tests for core functionality added/updated
- Integration tests for component interactions added when required
- End-to-end tests for critical flows added when story demands them
- All tests pass (no regressions, new tests successful)
- Code quality checks pass (linting, static analysis if configured)
- File List includes every new/modified/deleted file (relative paths)
- Dev Agent Record contains implementation notes
- Change Log includes summary of changes
- Only permitted story sections were modified
</action>
<!-- Mark story ready for review - sprint status conditional -->
<check if="{sprint_status} file exists AND {{current_sprint_status}} != 'no-sprint-tracking'">
<action>Load the FULL file: {sprint_status}</action>
<action>Find development_status key matching {{story_key}}</action>
<action>Verify current status is "in-progress" (expected previous state)</action>
<action>Update development_status[{{story_key}}] = "review"</action>
<action>Update last_updated field to current date</action>
<action>Save file, preserving ALL comments and structure including STATUS DEFINITIONS</action>
<output>✅ Story status updated to "review" in sprint-status.yaml</output>
</check>
<check if="{sprint_status} file does NOT exist OR {{current_sprint_status}} == 'no-sprint-tracking'">
<output> Story status updated to "review" in story file (no sprint tracking configured)</output>
</check>
<check if="story key not found in sprint status">
<output>⚠️ Story file updated, but sprint-status update failed: {{story_key}} not found
Story status is set to "review" in file, but sprint-status.yaml may be out of sync.
</output>
</check>
<!-- Final validation gates -->
<action if="any task is incomplete">HALT - Complete remaining tasks before marking ready for review</action>
<action if="regression failures exist">HALT - Fix regression issues before completing</action>
<action if="File List is incomplete">HALT - Update File List with all changed files</action>
<action if="definition-of-done validation fails">HALT - Address DoD failures before completing</action>
</step>
<step n="10" goal="Completion communication and user support">
<action>Execute the enhanced definition-of-done checklist using the validation framework</action>
<action>Prepare a concise summary in Dev Agent Record → Completion Notes</action>
<action>Communicate to {user_name} that story implementation is complete and ready for review</action>
<action>Summarize key accomplishments: story ID, story key, title, key changes made, tests added, files modified</action>
<action>Provide the story file path and current status (now "review")</action>
<action>Based on {user_skill_level}, ask if user needs any explanations about:
- What was implemented and how it works
- Why certain technical decisions were made
- How to test or verify the changes
- Any patterns, libraries, or approaches used
- Anything else they'd like clarified
</action>
<check if="user asks for explanations">
<action>Provide clear, contextual explanations tailored to {user_skill_level}</action>
<action>Use examples and references to specific code when helpful</action>
</check>
<action>Once explanations are complete (or user indicates no questions), suggest logical next steps</action>
<action>Recommended next steps (flexible based on project setup):
- Review the implemented story and test the changes
- Verify all acceptance criteria are met
- Ensure deployment readiness if applicable
- Run `code-review` workflow for peer review
- Optional: If Test Architect module installed, run `/bmad:tea:automate` to expand guardrail tests
</action>
<output>💡 **Tip:** For best results, run `code-review` using a **different** LLM than the one that implemented this story.</output>
<check if="{sprint_status} file exists">
<action>Suggest checking {sprint_status} to see project progress</action>
</check>
<action>Remain flexible - allow user to choose their own path or ask for other assistance</action>
<action>Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.</action>
</step>
</workflow>
Follow the instructions in ./workflow.md.

View File

@ -1,41 +0,0 @@
# DO NOT EDIT -- overwritten on every update.
#
# Workflow customization surface for bmad-dev-story. Mirrors the
# agent customization shape under the [workflow] namespace.
[workflow]
# --- Configurable below. Overrides merge per BMad structural rules: ---
# scalars: override wins • arrays (persistent_facts, activation_steps_*): append
# arrays-of-tables with `code`/`id`: replace matching items, append new ones.
# Steps to run before the standard activation (config load, greet).
# Overrides append. Use for pre-flight loads, compliance checks, etc.
activation_steps_prepend = []
# Steps to run after greet but before the workflow begins.
# Overrides append. Use for context-heavy setup that should happen
# once the user has been acknowledged.
activation_steps_append = []
# Persistent facts the workflow keeps in mind for the whole run
# (standards, compliance constraints, stylistic guardrails).
# Distinct from the runtime memory sidecar — these are static context
# loaded on activation. Overrides append.
#
# Each entry is either:
# - a literal sentence, e.g. "All stories must include testable acceptance criteria."
# - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
# (glob patterns are supported; the file's contents are loaded and treated as facts).
persistent_facts = [
"file:{project-root}/**/project-context.md",
]
# Scalar: executed when the workflow reaches its final step,
# after the story implementation is complete and status is updated. Override wins.
# Leave empty for no custom post-completion behavior.
on_complete = ""

View File

@ -0,0 +1,450 @@
# Dev Story Workflow
**Goal:** Execute story implementation following a context filled story spec file.
**Your Role:** Developer implementing the story.
- Communicate all responses in {communication_language} and language MUST be tailored to {user_skill_level}
- Generate all documents in {document_output_language}
- Only modify the story file in these areas: Tasks/Subtasks checkboxes (including Review Follow-ups (AI)), Dev Agent Record (Debug Log, Completion Notes), File List, Change Log, and Status
- Execute ALL steps in exact order; do NOT skip steps
- Absolutely DO NOT stop because of "milestones", "significant progress", or "session boundaries". Continue in a single execution until the story is COMPLETE (all ACs satisfied and all tasks/subtasks checked) UNLESS a HALT condition is triggered or the USER gives other instruction.
- Do NOT schedule a "next session" or request review pauses unless a HALT condition applies. Only Step 8 decides completion.
- User skill level ({user_skill_level}) affects conversation style ONLY, not code updates.
---
## INITIALIZATION
### Configuration Loading
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
- `project_name`, `user_name`
- `communication_language`, `document_output_language`
- `user_skill_level`
- `implementation_artifacts`
- `date` as system-generated current datetime
### Paths
- `story_file` = `` (explicit story path; auto-discovered if empty)
- `sprint_status` = `{implementation_artifacts}/sprint-status.yaml`
### Context
- `project_context` = `**/project-context.md` (load if exists)
---
## EXECUTION
<workflow>
<critical>Communicate all responses in {communication_language} and language MUST be tailored to {user_skill_level}</critical>
<critical>Generate all documents in {document_output_language}</critical>
<critical>Only modify the story file in these areas: Tasks/Subtasks checkboxes, Dev Agent Record (Debug Log, Completion Notes), File List,
Change Log, and Status</critical>
<critical>Execute ALL steps in exact order; do NOT skip steps</critical>
<critical>Absolutely DO NOT stop because of "milestones", "significant progress", or "session boundaries". Continue in a single execution
until the story is COMPLETE (all ACs satisfied and all tasks/subtasks checked) UNLESS a HALT condition is triggered or the USER gives
other instruction.</critical>
<critical>Do NOT schedule a "next session" or request review pauses unless a HALT condition applies. Only Step 8 decides completion.</critical>
<critical>User skill level ({user_skill_level}) affects conversation style ONLY, not code updates.</critical>
<step n="1" goal="Find next ready story and load it" tag="sprint-status">
<check if="{{story_path}} is provided">
<action>Use {{story_path}} directly</action>
<action>Read COMPLETE story file</action>
<action>Extract story_key from filename or metadata</action>
<goto anchor="task_check" />
</check>
<!-- Sprint-based story discovery -->
<check if="{{sprint_status}} file exists">
<critical>MUST read COMPLETE sprint-status.yaml file from start to end to preserve order</critical>
<action>Load the FULL file: {{sprint_status}}</action>
<action>Read ALL lines from beginning to end - do not skip any content</action>
<action>Parse the development_status section completely to understand story order</action>
<action>Find the FIRST story (by reading in order from top to bottom) where:
- Key matches pattern: number-number-name (e.g., "1-2-user-auth")
- NOT an epic key (epic-X) or retrospective (epic-X-retrospective)
- Status value equals "ready-for-dev"
</action>
<check if="no ready-for-dev or in-progress story found">
<output>📋 No ready-for-dev stories found in sprint-status.yaml
**Current Sprint Status:** {{sprint_status_summary}}
**What would you like to do?**
1. Run `create-story` to create next story from epics with comprehensive context
2. Run `*validate-create-story` to improve existing stories before development (recommended quality check)
3. Specify a particular story file to develop (provide full path)
4. Check {{sprint_status}} file to see current sprint status
💡 **Tip:** Stories in `ready-for-dev` may not have been validated. Consider running `validate-create-story` first for a quality
check.
</output>
<ask>Choose option [1], [2], [3], or [4], or specify story file path:</ask>
<check if="user chooses '1'">
<action>HALT - Run create-story to create next story</action>
</check>
<check if="user chooses '2'">
<action>HALT - Run validate-create-story to improve existing stories</action>
</check>
<check if="user chooses '3'">
<ask>Provide the story file path to develop:</ask>
<action>Store user-provided story path as {{story_path}}</action>
<goto anchor="task_check" />
</check>
<check if="user chooses '4'">
<output>Loading {{sprint_status}} for detailed status review...</output>
<action>Display detailed sprint status analysis</action>
<action>HALT - User can review sprint status and provide story path</action>
</check>
<check if="user provides story file path">
<action>Store user-provided story path as {{story_path}}</action>
<goto anchor="task_check" />
</check>
</check>
</check>
<!-- Non-sprint story discovery -->
<check if="{{sprint_status}} file does NOT exist">
<action>Search {implementation_artifacts} for stories directly</action>
<action>Find stories with "ready-for-dev" status in files</action>
<action>Look for story files matching pattern: *-*-*.md</action>
<action>Read each candidate story file to check Status section</action>
<check if="no ready-for-dev stories found in story files">
<output>📋 No ready-for-dev stories found
**Available Options:**
1. Run `create-story` to create next story from epics with comprehensive context
2. Run `*validate-create-story` to improve existing stories
3. Specify which story to develop
</output>
<ask>What would you like to do? Choose option [1], [2], or [3]:</ask>
<check if="user chooses '1'">
<action>HALT - Run create-story to create next story</action>
</check>
<check if="user chooses '2'">
<action>HALT - Run validate-create-story to improve existing stories</action>
</check>
<check if="user chooses '3'">
<ask>It's unclear what story you want developed. Please provide the full path to the story file:</ask>
<action>Store user-provided story path as {{story_path}}</action>
<action>Continue with provided story file</action>
</check>
</check>
<check if="ready-for-dev story found in files">
<action>Use discovered story file and extract story_key</action>
</check>
</check>
<action>Store the found story_key (e.g., "1-2-user-authentication") for later status updates</action>
<action>Find matching story file in {implementation_artifacts} using story_key pattern: {{story_key}}.md</action>
<action>Read COMPLETE story file from discovered path</action>
<anchor id="task_check" />
<action>Parse sections: Story, Acceptance Criteria, Tasks/Subtasks, Dev Notes, Dev Agent Record, File List, Change Log, Status</action>
<action>Load comprehensive context from story file's Dev Notes section</action>
<action>Extract developer guidance from Dev Notes: architecture requirements, previous learnings, technical specifications</action>
<action>Use enhanced story context to inform implementation decisions and approaches</action>
<action>Identify first incomplete task (unchecked [ ]) in Tasks/Subtasks</action>
<action if="no incomplete tasks">
<goto step="6">Completion sequence</goto>
</action>
<action if="story file inaccessible">HALT: "Cannot develop story without access to story file"</action>
<action if="incomplete task or subtask requirements ambiguous">ASK user to clarify or HALT</action>
</step>
<step n="2" goal="Load project context and story information">
<critical>Load all available context to inform implementation</critical>
<action>Load {project_context} for coding standards and project-wide patterns (if exists)</action>
<action>Parse sections: Story, Acceptance Criteria, Tasks/Subtasks, Dev Notes, Dev Agent Record, File List, Change Log, Status</action>
<action>Load comprehensive context from story file's Dev Notes section</action>
<action>Extract developer guidance from Dev Notes: architecture requirements, previous learnings, technical specifications</action>
<action>Use enhanced story context to inform implementation decisions and approaches</action>
<output>✅ **Context Loaded**
Story and project context available for implementation
</output>
</step>
<step n="3" goal="Detect review continuation and extract review context">
<critical>Determine if this is a fresh start or continuation after code review</critical>
<action>Check if "Senior Developer Review (AI)" section exists in the story file</action>
<action>Check if "Review Follow-ups (AI)" subsection exists under Tasks/Subtasks</action>
<check if="Senior Developer Review section exists">
<action>Set review_continuation = true</action>
<action>Extract from "Senior Developer Review (AI)" section:
- Review outcome (Approve/Changes Requested/Blocked)
- Review date
- Total action items with checkboxes (count checked vs unchecked)
- Severity breakdown (High/Med/Low counts)
</action>
<action>Count unchecked [ ] review follow-up tasks in "Review Follow-ups (AI)" subsection</action>
<action>Store list of unchecked review items as {{pending_review_items}}</action>
<output>⏯️ **Resuming Story After Code Review** ({{review_date}})
**Review Outcome:** {{review_outcome}}
**Action Items:** {{unchecked_review_count}} remaining to address
**Priorities:** {{high_count}} High, {{med_count}} Medium, {{low_count}} Low
**Strategy:** Will prioritize review follow-up tasks (marked [AI-Review]) before continuing with regular tasks.
</output>
</check>
<check if="Senior Developer Review section does NOT exist">
<action>Set review_continuation = false</action>
<action>Set {{pending_review_items}} = empty</action>
<output>🚀 **Starting Fresh Implementation**
Story: {{story_key}}
Story Status: {{current_status}}
First incomplete task: {{first_task_description}}
</output>
</check>
</step>
<step n="4" goal="Mark story in-progress" tag="sprint-status">
<check if="{{sprint_status}} file exists">
<action>Load the FULL file: {{sprint_status}}</action>
<action>Read all development_status entries to find {{story_key}}</action>
<action>Get current status value for development_status[{{story_key}}]</action>
<check if="current status == 'ready-for-dev' OR review_continuation == true">
<action>Update the story in the sprint status report to = "in-progress"</action>
<action>Update last_updated field to current date</action>
<output>🚀 Starting work on story {{story_key}}
Status updated: ready-for-dev → in-progress
</output>
</check>
<check if="current status == 'in-progress'">
<output>⏯️ Resuming work on story {{story_key}}
Story is already marked in-progress
</output>
</check>
<check if="current status is neither ready-for-dev nor in-progress">
<output>⚠️ Unexpected story status: {{current_status}}
Expected ready-for-dev or in-progress. Continuing anyway...
</output>
</check>
<action>Store {{current_sprint_status}} for later use</action>
</check>
<check if="{{sprint_status}} file does NOT exist">
<output> No sprint status file exists - story progress will be tracked in story file only</output>
<action>Set {{current_sprint_status}} = "no-sprint-tracking"</action>
</check>
</step>
<step n="5" goal="Implement task following red-green-refactor cycle">
<critical>FOLLOW THE STORY FILE TASKS/SUBTASKS SEQUENCE EXACTLY AS WRITTEN - NO DEVIATION</critical>
<action>Review the current task/subtask from the story file - this is your authoritative implementation guide</action>
<action>Plan implementation following red-green-refactor cycle</action>
<!-- RED PHASE -->
<action>Write FAILING tests first for the task/subtask functionality</action>
<action>Confirm tests fail before implementation - this validates test correctness</action>
<!-- GREEN PHASE -->
<action>Implement MINIMAL code to make tests pass</action>
<action>Run tests to confirm they now pass</action>
<action>Handle error conditions and edge cases as specified in task/subtask</action>
<!-- REFACTOR PHASE -->
<action>Improve code structure while keeping tests green</action>
<action>Ensure code follows architecture patterns and coding standards from Dev Notes</action>
<action>Document technical approach and decisions in Dev Agent Record → Implementation Plan</action>
<action if="new dependencies required beyond story specifications">HALT: "Additional dependencies need user approval"</action>
<action if="3 consecutive implementation failures occur">HALT and request guidance</action>
<action if="required configuration is missing">HALT: "Cannot proceed without necessary configuration files"</action>
<critical>NEVER implement anything not mapped to a specific task/subtask in the story file</critical>
<critical>NEVER proceed to next task until current task/subtask is complete AND tests pass</critical>
<critical>Execute continuously without pausing until all tasks/subtasks are complete or explicit HALT condition</critical>
<critical>Do NOT propose to pause for review until Step 9 completion gates are satisfied</critical>
</step>
<step n="6" goal="Author comprehensive tests">
<action>Create unit tests for business logic and core functionality introduced/changed by the task</action>
<action>Add integration tests for component interactions specified in story requirements</action>
<action>Include end-to-end tests for critical user flows when story requirements demand them</action>
<action>Cover edge cases and error handling scenarios identified in story Dev Notes</action>
</step>
<step n="7" goal="Run validations and tests">
<action>Determine how to run tests for this repo (infer test framework from project structure)</action>
<action>Run all existing tests to ensure no regressions</action>
<action>Run the new tests to verify implementation correctness</action>
<action>Run linting and code quality checks if configured in project</action>
<action>Validate implementation meets ALL story acceptance criteria; enforce quantitative thresholds explicitly</action>
<action if="regression tests fail">STOP and fix before continuing - identify breaking changes immediately</action>
<action if="new tests fail">STOP and fix before continuing - ensure implementation correctness</action>
</step>
<step n="8" goal="Validate and mark task complete ONLY when fully done">
<critical>NEVER mark a task complete unless ALL conditions are met - NO LYING OR CHEATING</critical>
<!-- VALIDATION GATES -->
<action>Verify ALL tests for this task/subtask ACTUALLY EXIST and PASS 100%</action>
<action>Confirm implementation matches EXACTLY what the task/subtask specifies - no extra features</action>
<action>Validate that ALL acceptance criteria related to this task are satisfied</action>
<action>Run full test suite to ensure NO regressions introduced</action>
<!-- REVIEW FOLLOW-UP HANDLING -->
<check if="task is review follow-up (has [AI-Review] prefix)">
<action>Extract review item details (severity, description, related AC/file)</action>
<action>Add to resolution tracking list: {{resolved_review_items}}</action>
<!-- Mark task in Review Follow-ups section -->
<action>Mark task checkbox [x] in "Tasks/Subtasks → Review Follow-ups (AI)" section</action>
<!-- CRITICAL: Also mark corresponding action item in review section -->
<action>Find matching action item in "Senior Developer Review (AI) → Action Items" section by matching description</action>
<action>Mark that action item checkbox [x] as resolved</action>
<action>Add to Dev Agent Record → Completion Notes: "✅ Resolved review finding [{{severity}}]: {{description}}"</action>
</check>
<!-- ONLY MARK COMPLETE IF ALL VALIDATION PASS -->
<check if="ALL validation gates pass AND tests ACTUALLY exist and pass">
<action>ONLY THEN mark the task (and subtasks) checkbox with [x]</action>
<action>Update File List section with ALL new, modified, or deleted files (paths relative to repo root)</action>
<action>Add completion notes to Dev Agent Record summarizing what was ACTUALLY implemented and tested</action>
</check>
<check if="ANY validation fails">
<action>DO NOT mark task complete - fix issues first</action>
<action>HALT if unable to fix validation failures</action>
</check>
<check if="review_continuation == true and {{resolved_review_items}} is not empty">
<action>Count total resolved review items in this session</action>
<action>Add Change Log entry: "Addressed code review findings - {{resolved_count}} items resolved (Date: {{date}})"</action>
</check>
<action>Save the story file</action>
<action>Determine if more incomplete tasks remain</action>
<action if="more tasks remain">
<goto step="5">Next task</goto>
</action>
<action if="no tasks remain">
<goto step="9">Completion</goto>
</action>
</step>
<step n="9" goal="Story completion and mark for review" tag="sprint-status">
<action>Verify ALL tasks and subtasks are marked [x] (re-scan the story document now)</action>
<action>Run the full regression suite (do not skip)</action>
<action>Confirm File List includes every changed file</action>
<action>Execute enhanced definition-of-done validation</action>
<action>Update the story Status to: "review"</action>
<!-- Enhanced Definition of Done Validation -->
<action>Validate definition-of-done checklist with essential requirements:
- All tasks/subtasks marked complete with [x]
- Implementation satisfies every Acceptance Criterion
- Unit tests for core functionality added/updated
- Integration tests for component interactions added when required
- End-to-end tests for critical flows added when story demands them
- All tests pass (no regressions, new tests successful)
- Code quality checks pass (linting, static analysis if configured)
- File List includes every new/modified/deleted file (relative paths)
- Dev Agent Record contains implementation notes
- Change Log includes summary of changes
- Only permitted story sections were modified
</action>
<!-- Mark story ready for review - sprint status conditional -->
<check if="{sprint_status} file exists AND {{current_sprint_status}} != 'no-sprint-tracking'">
<action>Load the FULL file: {sprint_status}</action>
<action>Find development_status key matching {{story_key}}</action>
<action>Verify current status is "in-progress" (expected previous state)</action>
<action>Update development_status[{{story_key}}] = "review"</action>
<action>Update last_updated field to current date</action>
<action>Save file, preserving ALL comments and structure including STATUS DEFINITIONS</action>
<output>✅ Story status updated to "review" in sprint-status.yaml</output>
</check>
<check if="{sprint_status} file does NOT exist OR {{current_sprint_status}} == 'no-sprint-tracking'">
<output> Story status updated to "review" in story file (no sprint tracking configured)</output>
</check>
<check if="story key not found in sprint status">
<output>⚠️ Story file updated, but sprint-status update failed: {{story_key}} not found
Story status is set to "review" in file, but sprint-status.yaml may be out of sync.
</output>
</check>
<!-- Final validation gates -->
<action if="any task is incomplete">HALT - Complete remaining tasks before marking ready for review</action>
<action if="regression failures exist">HALT - Fix regression issues before completing</action>
<action if="File List is incomplete">HALT - Update File List with all changed files</action>
<action if="definition-of-done validation fails">HALT - Address DoD failures before completing</action>
</step>
<step n="10" goal="Completion communication and user support">
<action>Execute the enhanced definition-of-done checklist using the validation framework</action>
<action>Prepare a concise summary in Dev Agent Record → Completion Notes</action>
<action>Communicate to {user_name} that story implementation is complete and ready for review</action>
<action>Summarize key accomplishments: story ID, story key, title, key changes made, tests added, files modified</action>
<action>Provide the story file path and current status (now "review")</action>
<action>Based on {user_skill_level}, ask if user needs any explanations about:
- What was implemented and how it works
- Why certain technical decisions were made
- How to test or verify the changes
- Any patterns, libraries, or approaches used
- Anything else they'd like clarified
</action>
<check if="user asks for explanations">
<action>Provide clear, contextual explanations tailored to {user_skill_level}</action>
<action>Use examples and references to specific code when helpful</action>
</check>
<action>Once explanations are complete (or user indicates no questions), suggest logical next steps</action>
<action>Recommended next steps (flexible based on project setup):
- Review the implemented story and test the changes
- Verify all acceptance criteria are met
- Ensure deployment readiness if applicable
- Run `code-review` workflow for peer review
- Optional: If Test Architect module installed, run `/bmad:tea:automate` to expand guardrail tests
</action>
<output>💡 **Tip:** For best results, run `code-review` using a **different** LLM than the one that implemented this story.</output>
<check if="{sprint_status} file exists">
<action>Suggest checking {sprint_status} to see project progress</action>
</check>
<action>Remain flexible - allow user to choose their own path or ask for other assistance</action>
</step>
</workflow>

View File

@ -1,194 +0,0 @@
---
name: bmad-investigate
description: Forensic case investigation with evidence-graded findings, calibrated to the input. Use when the user asks to investigate a bug, trace what caused an incident, walk through unfamiliar code, or build a mental model of a code area before working on it.
---
# Investigate
## Overview
Reconstruct what's happening, or what an unfamiliar area does, from the available evidence. Produce a structured case
file another engineer can pick up cold. Calibrate continuously between defect-chasing (symptom-driven) and
area-exploration (no symptom); the same discipline applies on both ends.
**Args:** A ticket ID, log file path, diagnostic archive, error message, code area name, problem description, or a path
to an existing case file. The last form resumes a prior investigation; everything else opens a new case.
**Output:** `{implementation_artifacts}/{workflow.case_file_subdir}/{workflow.case_file_filename}`. Reference inputs
are recorded; raw content is not read into the parent context until an outcome calls for it.
`{slug}` is the ticket ID when one is provided, otherwise a short descriptive name agreed with the user, sanitized to
lowercase alphanumeric with hyphens. On collision with an existing case file at the resolved path, ask whether to
rename to `slug-YYYY-MM-DD.md` or resume the existing file (resuming routes to Outcome 0).
After every outcome, present what was learned and pause for the user before continuing.
## Principles
- **Evidence grading.**
- **Confirmed.** Directly observed; cite `path:line`, log timestamp, or commit hash.
- **Deduced.** Logically follows from Confirmed evidence; show the chain.
- **Hypothesized.** Plausible but unconfirmed; state what would confirm or refute it.
- **Stronghold first.** Anchor in one Confirmed piece of evidence and expand outward. Never start from a theory and
hunt for support. When evidence is sparse, switch to evidence-light mode (Outcome 1 branch).
- **Challenge the premise.** The user's description is a hypothesis, not a fact. Verify independently; if evidence
contradicts, say so.
- **Follow the evidence, not the narrative.** When evidence contradicts the working theory, update the theory — never
the other way around. Resist confirmation bias even when the user is convinced.
- **Hypotheses are never deleted.** Update Status (Open / Confirmed / Refuted) and add a Resolution. Wrong turns are
part of the deliverable.
- **Missing evidence is itself a finding.** Document the gap, what it would resolve, and how to obtain it.
- **Write it down early.** Initialize the case file as soon as the slug is agreed; it is the persistent state across
interruptions.
- **Path:line citations** use CWD-relative format, no leading `/`, so they're clickable in IDE-embedded terminals.
- **Delegation discipline.** When a step requires reading 5+ files or any file >10K tokens, delegate to a subagent
that returns structured JSON only. Cite `path:line` from the result; don't re-read in the parent.
- **Issue independent operations in parallel** (multi-grep, multi-read, parallel inventories) — one message, multiple
tool calls.
- **Communication.** Evidence-first language ("the evidence shows", "unconfirmed, requires X to verify"). No hedging,
no narrative.
## On Activation
### Step 1: Resolve the workflow block
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
If the script fails, stop and surface the error.
### Step 2: Execute prepend steps
Run each entry in `{workflow.activation_steps_prepend}` in order.
### Step 3: Load persistent facts
Treat each entry in `{workflow.persistent_facts}` as foundational context. `file:` prefixes are paths or globs under
`{project-root}` (load contents); other entries are facts verbatim.
### Step 4: Load config
Load `{project-root}/_bmad/bmm/config.yaml` and resolve `{user_name}`, `{communication_language}`,
`{document_output_language}`, `{implementation_artifacts}`, `{project_knowledge}`. If `{implementation_artifacts}` is
unresolved, fall back to `./investigations/` and surface the fallback before initializing.
### Step 5: Greet
Greet `{user_name}` in `{communication_language}`.
### Step 6: Execute append steps
Run each entry in `{workflow.activation_steps_append}` in order.
### Step 7: Acknowledge and route
Acknowledge the input as a reference (record paths and IDs; don't read raw content). Path to an existing case file →
Outcome 0. Otherwise → Outcome 1.
## Procedure
### Outcome 0: Existing case is loaded and surfaced
Read the case file. Surface, in order: open hypotheses (Status = Open) with their confirm/refute criteria; open
backlog (Status ≠ Done); missing-evidence rows; last Conclusion with confidence. Ask which thread to pull. New
evidence opens a new `## Follow-up: {YYYY-MM-DD}` block (append `#2`, `#3` on same-day reentry). Pause for user with the recap above; wait for direction.
### Outcome 1: Scope and stronghold are established
Acknowledge each input shape — record location, scope, time window only; bulk reads happen in Outcome 2.
- **Issue tracker ticket.** Fetch full details via available MCP tools.
- **Diagnostic archive.** Record path, file count, time window.
- **Log file or stack trace.** Record path and time window; only the stack frame already in the user's message is in
scope here.
- **Free-text description.** Capture verbatim; treat as hypothesis.
- **Code area name** (no symptom). Record entry point.
- **Recent commit area.** Record commit range.
If the user arrived with a hypothesis, register it as Hypothesis #1. Find the stronghold *independently*; the user's
hypothesis is one of the things the stronghold validates or refutes.
Find a stronghold: a Confirmed piece of evidence (error message, function name, HTTP route, config parameter, test
case). Anchor here.
**Initialize `{case_file}` before branching.** The path is
`{implementation_artifacts}/{workflow.case_file_subdir}/{workflow.case_file_filename}` with `{slug}` substituted (slug
and collision rules in Overview). Create the file from `{workflow.case_file_template}` and fill Hand-off Brief
(rough), Case Info, Problem Statement, initial Evidence Inventory.
**Evidence-light branch.** When no Confirmed evidence is reachable: mark the case evidence-light in the Hand-off
Brief; populate the Investigation Backlog with prioritized data-collection items; record "to make progress, I need one
of: …"; pause for the user to provide evidence or authorize Outcome 2 to scan more broadly.
Otherwise present scope, stronghold, file path, proposed approach. Pause for user with the recap above; wait for direction.
### Outcome 2: Evidence perimeter is mapped
Survey the scene: inventory available evidence in parallel across these independent categories: diagnostic archives;
issue tracker; version control; test results; static analysis; source code. For any category exceeding ~10K tokens,
delegate to a subagent that returns a JSON manifest (paths, sizes, time windows, key fragments cited as `path:line`).
Classify each Available, Partial, or Missing — Missing is itself a finding. Update Evidence Inventory and Investigation
Backlog. Pause for user with the recap above; wait for direction.
### Outcome 3: Cause is reasoned about with discipline
- **Trace causality.** Symptom-driven: trace backward from the symptom to producing conditions and the state that
emerged. Exploration: trace backward from outputs (returns, side effects, messages sent) to producing conditions.
Same technique, different anchor.
- **Reconstruct the timeline** by cross-referencing logs, system events, version control, user observations.
- **Form and test hypotheses.** State, identify confirming/refuting evidence, search, grade
(Confirmed / Refuted / Open). Update Status. Never delete.
- **Refutation pass.** Each time a hypothesis transitions toward Confirmed, actively look for refuting evidence first.
Record the attempt in Resolution.
- **Verify the user's premise.** If evidence contradicts, say so explicitly.
- **Add discovered paths to the backlog.** Stay focused on the current thread.
Update Confirmed Findings, Deduced Conclusions, Hypothesized Paths, Backlog, Timeline. Highlight contradictions to the
original premise. Pause for user with the recap above; wait for direction.
### Outcome 4: Source has been traced where it matters
Issue these first-pass scans as parallel tool calls in one message: grep for exact error strings; glob the affected
directory for parallel implementations; `git log` for recent changes.
Then sequentially: read the surrounding code; follow the caller chain; watch for language and process boundary
crossings (compiled→scripts, IPC, host→device, configuration flow).
Lean by case type:
- **Exploration:** I/O mapping (triggers, outputs, dependencies); frequent-terms scan; control-flow filtering
(branches, loops, error handling, state-machine transitions).
- **Symptom-driven:** depth assessment — is the root cause reachable from local context, or is a broader area model
required? Surface escalations; never silently expand scope. Trivial-fix assessment — off-by-one, missing null check,
swapped argument → one-line code suggestion or draft diff in the report; non-trivial → stop at the root cause area.
Investigation stops at the diagnosis; implementation is out of scope. Update Source Code Trace (Error origin, Trigger,
Condition, Related files; area model when broader). Pause for user with the recap above; wait for direction.
### Outcome 5: Report is finalized and the hand-off is clean
Update `{case_file}`:
- **Hand-off Brief** rewritten to final form (3 sentences, 15-second read).
- **Final Conclusion** with confidence: **High** (Confirmed root cause, deterministic repro), **Medium** (Deduced;
minor uncertainty), **Low** (Hypothesized; clear data gap).
- **Fix direction** when applicable (categorize by mechanism if multiple combine).
- **Diagnostic steps** if uncertainty remains.
- **Reproduction Plan** when applicable, or a verification plan for exploration cases.
- **Status:** Active / Concluded / Blocked on evidence.
Present the conclusion, then a concrete next-steps menu: trivial fix → `bmad-quick-dev`; scope/plan adjustment →
`bmad-correct-course`; tracked story → `bmad-create-story`; fresh review → `bmad-code-review`. Recommend the
highest-value action. Mitigations and workarounds are generated only on explicit request — investigation stops at the
diagnosis. Execute `{workflow.on_complete}` if non-empty. Pause for user with the recap above; wait for direction.
## Follow-up Iterations
Continue work by appending to `{case_file}` under a new `## Follow-up: {YYYY-MM-DD}` block (`#2`, `#3` on same-day
reentry). The investigation is complete when:
- Root cause is Confirmed.
- Root cause is Hypothesized with a clear data gap.
- The mental model is sufficient for the user's stated goal (exploration cases).
- The backlog contains only items requiring unavailable evidence.
- The user explicitly concludes.

View File

@ -1,62 +0,0 @@
# DO NOT EDIT -- overwritten on every update.
#
# Workflow customization surface for bmad-investigate. Mirrors the
# agent customization shape under the [workflow] namespace.
[workflow]
# --- Configurable below. Overrides merge per BMad structural rules: ---
# scalars: override wins • arrays (persistent_facts, activation_steps_*): append
# arrays-of-tables with `code`/`id`: replace matching items, append new ones.
# Steps to run before the standard activation (config load, greet).
# Overrides append. Use for pre-flight loads, compliance checks, etc.
activation_steps_prepend = []
# Steps to run after greet but before the workflow begins.
# Overrides append. Use for context-heavy setup that should happen
# once the user has been acknowledged.
activation_steps_append = []
# Persistent facts the workflow keeps in mind for the whole run.
# Use for citation conventions (path:line vs path#L42), grading-scale
# overrides (ITIL severity 1-5 instead of High/Medium/Low), tone
# directives (engineering vs exec-facing), or compliance constraints
# the case file must respect.
# Distinct from the runtime memory sidecar — these are static context
# loaded on activation. Overrides append.
#
# Each entry is either:
# - a literal sentence, e.g. "Use ITIL severity 1-5 instead of High/Medium/Low for confidence."
# - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
# (glob patterns are supported; the file's contents are loaded and treated as facts).
persistent_facts = [
"file:{project-root}/**/project-context.md",
]
# Scalar: path to the case-file template, resolved from the skill root.
# Override to point at an org-shaped template (compliance sections,
# SLA fields, post-mortem hooks, ITIL fields).
case_file_template = "references/case-file-template.md"
# Scalar: subdirectory under {implementation_artifacts} where case files land.
# Override for org taxonomies (forensics/, cases/, incidents/, bug-bash/).
case_file_subdir = "investigations"
# Scalar: filename pattern for new case files. {slug} expands to the
# ticket ID or a short user-agreed name.
case_file_filename = "{slug}-investigation.md"
# Scalar: executed when the workflow finalizes the case file at Outcome 5,
# after the conclusion is presented. Override wins. Use for post-case
# automation: post the case to Slack/Teams, push fields back to ticketing,
# link the case to a sprint, trigger a follow-up retro.
# Leave empty for no custom post-completion behavior.
on_complete = ""

View File

@ -1,127 +0,0 @@
# Investigation: {title}
## Hand-off Brief
1. **What happened.** {one-sentence problem statement, evidence-graded}
2. **Where the case stands.** {status, last finding, what would unblock progress}
3. **What's needed next.** {single recommended action with rationale}
## Case Info
| Field | Value |
| ---------------- | -------------------------------------------------------------------------- |
| Ticket | {ticket-id or "N/A"} |
| Date opened | {date} |
| Status | Active |
| System | {OS, version, relevant environment details} |
| Evidence sources | {diagnostic archive, logs, crash dump, code, version control, etc.} |
## Problem Statement
{User-reported description; the initial claim. May be refined or contradicted by evidence.}
## Evidence Inventory
| Source | Status | Notes |
| -------- | ------------------------------- | --------- |
| {source} | {Available / Partial / Missing} | {details} |
## Investigation Backlog
| # | Path to Explore | Priority | Status | Notes |
| - | --------------- | --------------------- | ------------------------------------- | --------- |
| 1 | {description} | {High / Medium / Low} | {Open / In Progress / Done / Blocked} | {context} |
## Timeline of Events
| Time | Event | Source | Confidence |
| ----------- | ------------------- | --------------------- | --------------------- |
| {timestamp} | {event description} | {log file, commit, …} | {Confirmed / Deduced} |
## Confirmed Findings
### Finding 1: {title}
**Evidence:** {citation — `path:line`, log timestamp, or commit hash}
**Detail:** {description}
## Deduced Conclusions
### Deduction 1: {title}
**Based on:** {which Confirmed Findings}
**Reasoning:** {logical chain}
**Conclusion:** {what follows}
## Hypothesized Paths
### Hypothesis 1: {title}
**Status:** {Open / Confirmed / Refuted}
**Theory:** {description}
**Supporting indicators:** {what makes this plausible}
**Would confirm:** {specific evidence that would prove this}
**Would refute:** {specific evidence that would disprove this}
**Resolution:** {when Status changes from Open, what evidence settled it}
## Missing Evidence
| Gap | Impact | How to Obtain |
| ---------------- | ------------------------------------ | --------------- |
| {what's missing} | {what it would confirm or eliminate} | {how to get it} |
## Source Code Trace
| Element | Detail |
| ------------- | ------------------------------------------- |
| Error origin | {file:line, function name} |
| Trigger | {what causes this code to execute} |
| Condition | {what state produces the observed behavior} |
| Related files | {other files in the same code path} |
## Conclusion
**Confidence:** {High / Medium / Low}
{Summary stating what is Confirmed vs. what remains Hypothesized. If a root cause is identified, state it; otherwise
name the most promising hypothesized paths and what would resolve the remaining uncertainty.}
## Recommended Next Steps
### Fix direction
{What needs to change and why. Categorize by mechanism when multiple issues combine.}
### Diagnostic
{Steps to confirm the root cause: additional logging, targeted tests, data to collect.}
## Reproduction Plan
{Setup, trigger, expected results. Scale from isolated proof to full system reproduction.}
## Side Findings
Tangential observations surfaced during the investigation, evidence-graded, with citation when applicable.
- {observation}
## Follow-up: {date}
### New Evidence
### Additional Findings
### Updated Hypotheses
### Backlog Changes
### Updated Conclusion

View File

@ -3,109 +3,4 @@ name: bmad-quick-dev
description: 'Implements any user intent, requirement, story, bug fix or change request by producing clean working code artifacts that follow the project''s existing architecture, patterns and conventions. Use when the user wants to build, fix, tweak, refactor, add or modify any code, component or feature.'
---
# Quick Dev New Preview Workflow
**Goal:** Turn user intent into a hardened, reviewable artifact.
**CRITICAL:** If a step says "read fully and follow step-XX", you read and follow step-XX. No exceptions.
## READY FOR DEVELOPMENT STANDARD
A specification is "Ready for Development" when:
- **Actionable**: Every task has a file path and specific action.
- **Logical**: Tasks ordered by dependency.
- **Testable**: All ACs use Given/When/Then.
- **Complete**: No placeholders or TBDs.
## SCOPE STANDARD
A specification should target a **single user-facing goal** within **9001600 tokens**:
- **Single goal**: One cohesive feature, even if it spans multiple layers/files. Multi-goal means >=2 **top-level independent shippable deliverables** — each could be reviewed, tested, and merged as a separate PR without breaking the others. Never count surface verbs, "and" conjunctions, or noun phrases. Never split cross-layer implementation details inside one user goal.
- Split: "add dark mode toggle AND refactor auth to JWT AND build admin dashboard"
- Don't split: "add validation and display errors" / "support drag-and-drop AND paste AND retry"
- **9001600 tokens**: Optimal range for LLM consumption. Below 900 risks ambiguity; above 1600 risks context-rot in implementation agents.
- **Neither limit is a gate.** Both are proposals with user override.
## Conventions
- Bare paths (e.g. `step-01-clarify-and-route.md`) resolve from the skill root.
- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives).
- `{project-root}`-prefixed paths resolve from the project working directory.
- `{skill-name}` resolves to the skill directory's basename.
## On Activation
### Step 1: Resolve the Workflow Block
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
1. `{skill-root}/customize.toml` — defaults
2. `{project-root}/_bmad/custom/{skill-name}.toml` — team overrides
3. `{project-root}/_bmad/custom/{skill-name}.user.toml` — personal overrides
Any missing file is skipped. Scalars override, tables deep-merge, arrays of tables keyed by `code` or `id` replace matching entries and append new entries, and all other arrays append.
### Step 2: Execute Prepend Steps
Execute each entry in `{workflow.activation_steps_prepend}` in order before proceeding.
### Step 3: Load Persistent Facts
Treat every entry in `{workflow.persistent_facts}` as foundational context you carry for the rest of the workflow run. Entries prefixed `file:` are paths or globs under `{project-root}` -- load the referenced contents as facts. All other entries are facts verbatim.
### Step 4: Load Config
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
- `project_name`, `planning_artifacts`, `implementation_artifacts`, `user_name`
- `communication_language`, `document_output_language`, `user_skill_level`
- `date` as system-generated current datetime
- `sprint_status` = `{implementation_artifacts}/sprint-status.yaml`
- `project_context` = `**/project-context.md` (load if exists)
- CLAUDE.md / memory files (load if exist)
- YOU MUST ALWAYS SPEAK OUTPUT in your Agent communication style with the config `{communication_language}`
- Language MUST be tailored to `{user_skill_level}`
- Generate all documents in `{document_output_language}`
### Step 5: Greet the User
Greet `{user_name}`, speaking in `{communication_language}`.
### Step 6: Execute Append Steps
Execute each entry in `{workflow.activation_steps_append}` in order.
Activation is complete. Begin the workflow below.
## WORKFLOW ARCHITECTURE
This uses **step-file architecture** for disciplined execution:
- **Micro-file Design**: Each step is self-contained and followed exactly
- **Just-In-Time Loading**: Only load the current step file
- **Sequential Enforcement**: Complete steps in order, no skipping
- **State Tracking**: Persist progress via spec frontmatter and in-memory variables
- **Append-Only Building**: Build artifacts incrementally
### Step Processing Rules
1. **READ COMPLETELY**: Read the entire step file before acting
2. **FOLLOW SEQUENCE**: Execute sections in order
3. **WAIT FOR INPUT**: Halt at checkpoints and wait for human
4. **LOAD NEXT**: When directed, read fully and follow the next step file
### Critical Rules (NO EXCEPTIONS)
- **NEVER** load multiple step files simultaneously
- **ALWAYS** read entire step file before execution
- **NEVER** skip steps or optimize the sequence
- **ALWAYS** follow the exact instructions in the step file
- **ALWAYS** halt at checkpoints and wait for human input
## FIRST STEP
Read fully and follow: `./step-01-clarify-and-route.md` to begin the workflow.
Follow the instructions in ./workflow.md.

View File

@ -1,41 +0,0 @@
# DO NOT EDIT -- overwritten on every update.
#
# Workflow customization surface for bmad-quick-dev. Mirrors the
# agent customization shape under the [workflow] namespace.
[workflow]
# --- Configurable below. Overrides merge per BMad structural rules: ---
# scalars: override wins • arrays (persistent_facts, activation_steps_*): append
# arrays-of-tables with `code`/`id`: replace matching items, append new ones.
# Steps to run before the standard activation (config load, greet).
# Overrides append. Use for pre-flight loads, compliance checks, etc.
activation_steps_prepend = []
# Steps to run after greet but before the workflow begins.
# Overrides append. Use for context-heavy setup that should happen
# once the user has been acknowledged.
activation_steps_append = []
# Persistent facts the workflow keeps in mind for the whole run
# (standards, compliance constraints, stylistic guardrails).
# Distinct from the runtime memory sidecar — these are static context
# loaded on activation. Overrides append.
#
# Each entry is either:
# - a literal sentence, e.g. "All stories must include testable acceptance criteria."
# - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
# (glob patterns are supported; the file's contents are loaded and treated as facts).
persistent_facts = [
"file:{project-root}/**/project-context.md",
]
# Scalar: executed when the workflow reaches its final step,
# after implementation is complete and explanations are provided. Override wins.
# Leave empty for no custom post-completion behavior.
on_complete = ""

View File

@ -70,9 +70,3 @@ Display summary of your work to the user, including the commit hash if one was c
- Offer to push and/or create a pull request.
Workflow complete.
## On Complete
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete`
If the resolved `workflow.on_complete` is non-empty, follow it as the final terminal instruction before exiting.

View File

@ -63,9 +63,3 @@ If version control is available and the tree is dirty, create a local commit wit
HALT and wait for human input.
Workflow complete.
## On Complete
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete`
If the resolved `workflow.on_complete` is non-empty, follow it as the final terminal instruction before exiting.

View File

@ -0,0 +1,76 @@
---
main_config: '{project-root}/_bmad/bmm/config.yaml'
---
# Quick Dev New Preview Workflow
**Goal:** Turn user intent into a hardened, reviewable artifact.
**CRITICAL:** If a step says "read fully and follow step-XX", you read and follow step-XX. No exceptions.
## READY FOR DEVELOPMENT STANDARD
A specification is "Ready for Development" when:
- **Actionable**: Every task has a file path and specific action.
- **Logical**: Tasks ordered by dependency.
- **Testable**: All ACs use Given/When/Then.
- **Complete**: No placeholders or TBDs.
## SCOPE STANDARD
A specification should target a **single user-facing goal** within **9001600 tokens**:
- **Single goal**: One cohesive feature, even if it spans multiple layers/files. Multi-goal means >=2 **top-level independent shippable deliverables** — each could be reviewed, tested, and merged as a separate PR without breaking the others. Never count surface verbs, "and" conjunctions, or noun phrases. Never split cross-layer implementation details inside one user goal.
- Split: "add dark mode toggle AND refactor auth to JWT AND build admin dashboard"
- Don't split: "add validation and display errors" / "support drag-and-drop AND paste AND retry"
- **9001600 tokens**: Optimal range for LLM consumption. Below 900 risks ambiguity; above 1600 risks context-rot in implementation agents.
- **Neither limit is a gate.** Both are proposals with user override.
## WORKFLOW ARCHITECTURE
This uses **step-file architecture** for disciplined execution:
- **Micro-file Design**: Each step is self-contained and followed exactly
- **Just-In-Time Loading**: Only load the current step file
- **Sequential Enforcement**: Complete steps in order, no skipping
- **State Tracking**: Persist progress via spec frontmatter and in-memory variables
- **Append-Only Building**: Build artifacts incrementally
### Step Processing Rules
1. **READ COMPLETELY**: Read the entire step file before acting
2. **FOLLOW SEQUENCE**: Execute sections in order
3. **WAIT FOR INPUT**: Halt at checkpoints and wait for human
4. **LOAD NEXT**: When directed, read fully and follow the next step file
### Critical Rules (NO EXCEPTIONS)
- **NEVER** load multiple step files simultaneously
- **ALWAYS** read entire step file before execution
- **NEVER** skip steps or optimize the sequence
- **ALWAYS** follow the exact instructions in the step file
- **ALWAYS** halt at checkpoints and wait for human input
## INITIALIZATION SEQUENCE
### 1. Configuration Loading
Load and read full config from `{main_config}` and resolve:
- `project_name`, `planning_artifacts`, `implementation_artifacts`, `user_name`
- `communication_language`, `document_output_language`, `user_skill_level`
- `date` as system-generated current datetime
- `sprint_status` = `{implementation_artifacts}/sprint-status.yaml`
- `project_context` = `**/project-context.md` (load if exists)
- CLAUDE.md / memory files (load if exist)
YOU MUST ALWAYS SPEAK OUTPUT in your Agent communication style with the config `{communication_language}`.
### 2. First Step Execution
Read fully and follow: `./step-01-clarify-and-route.md` to begin the workflow.

View File

@ -3,297 +3,4 @@ name: bmad-sprint-planning
description: 'Generate sprint status tracking from epics. Use when the user says "run sprint planning" or "generate sprint plan"'
---
# Sprint Planning Workflow
**Goal:** Generate sprint status tracking from epics, detecting current story statuses and building a complete sprint-status.yaml file.
**Your Role:** You are a Developer generating and maintaining sprint tracking. Parse epic files, detect story statuses, and produce a structured sprint-status.yaml.
## Conventions
- Bare paths (e.g. `checklist.md`) resolve from the skill root.
- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives).
- `{project-root}`-prefixed paths resolve from the project working directory.
- `{skill-name}` resolves to the skill directory's basename.
## On Activation
### Step 1: Resolve the Workflow Block
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
1. `{skill-root}/customize.toml` — defaults
2. `{project-root}/_bmad/custom/{skill-name}.toml` — team overrides
3. `{project-root}/_bmad/custom/{skill-name}.user.toml` — personal overrides
Any missing file is skipped. Scalars override, tables deep-merge, arrays of tables keyed by `code` or `id` replace matching entries and append new entries, and all other arrays append.
### Step 2: Execute Prepend Steps
Execute each entry in `{workflow.activation_steps_prepend}` in order before proceeding.
### Step 3: Load Persistent Facts
Treat every entry in `{workflow.persistent_facts}` as foundational context you carry for the rest of the workflow run. Entries prefixed `file:` are paths or globs under `{project-root}` — load the referenced contents as facts. All other entries are facts verbatim.
### Step 4: Load Config
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
- `project_name`, `user_name`
- `communication_language`, `document_output_language`
- `implementation_artifacts`
- `planning_artifacts`
- `date` as system-generated current datetime
- YOU MUST ALWAYS SPEAK OUTPUT in your Agent communication style with the config `{communication_language}`
- Generate all documents in `{document_output_language}`
### Step 5: Greet the User
Greet `{user_name}`, speaking in `{communication_language}`.
### Step 6: Execute Append Steps
Execute each entry in `{workflow.activation_steps_append}` in order.
Activation is complete. Begin the workflow below.
## Paths
- `tracking_system` = `file-system`
- `project_key` = `NOKEY`
- `story_location` = `{implementation_artifacts}`
- `story_location_absolute` = `{implementation_artifacts}`
- `epics_location` = `{planning_artifacts}`
- `epics_pattern` = `*epic*.md`
- `status_file` = `{implementation_artifacts}/sprint-status.yaml`
## Input Files
| Input | Path | Load Strategy |
|-------|------|---------------|
| Epics | `{planning_artifacts}/*epic*.md` (whole) or `{planning_artifacts}/*epic*/*.md` (sharded) | FULL_LOAD |
## Execution
### Document Discovery - Full Epic Loading
**Strategy**: Sprint planning needs ALL epics and stories to build complete status tracking.
**Epic Discovery Process:**
1. **Search for whole document first** - Look for `epics.md`, `bmm-epics.md`, or any `*epic*.md` file
2. **Check for sharded version** - If whole document not found, look for `epics/index.md`
3. **If sharded version found**:
- Read `index.md` to understand the document structure
- Read ALL epic section files listed in the index (e.g., `epic-1.md`, `epic-2.md`, etc.)
- Process all epics and their stories from the combined content
- This ensures complete sprint status coverage
4. **Priority**: If both whole and sharded versions exist, use the whole document
**Fuzzy matching**: Be flexible with document names - users may use variations like `epics.md`, `bmm-epics.md`, `user-stories.md`, etc.
<workflow>
<step n="1" goal="Parse epic files and extract all work items">
<action>Load {project_context} for project-wide patterns and conventions (if exists)</action>
<action>Communicate in {communication_language} with {user_name}</action>
<action>Look for all files matching `{epics_pattern}` in {epics_location}</action>
<action>Could be a single `epics.md` file or multiple `epic-1.md`, `epic-2.md` files</action>
<action>For each epic file found, extract:</action>
- Epic numbers from headers like `## Epic 1:` or `## Epic 2:`
- Story IDs and titles from patterns like `### Story 1.1: User Authentication`
- Convert story format from `Epic.Story: Title` to kebab-case key: `epic-story-title`
**Story ID Conversion Rules:**
- Original: `### Story 1.1: User Authentication`
- Replace period with dash: `1-1`
- Convert title to kebab-case: `user-authentication`
- Final key: `1-1-user-authentication`
<action>Build complete inventory of all epics and stories from all epic files</action>
</step>
<step n="2" goal="Build sprint status structure">
<action>For each epic found, create entries in this order:</action>
1. **Epic entry** - Key: `epic-{num}`, Default status: `backlog`
2. **Story entries** - Key: `{epic}-{story}-{title}`, Default status: `backlog`
3. **Retrospective entry** - Key: `epic-{num}-retrospective`, Default status: `optional`
**Example structure:**
```yaml
development_status:
epic-1: backlog
1-1-user-authentication: backlog
1-2-account-management: backlog
epic-1-retrospective: optional
```
</step>
<step n="3" goal="Apply intelligent status detection">
<action>For each story, detect current status by checking files:</action>
**Story file detection:**
- Check: `{story_location_absolute}/{story-key}.md` (e.g., `stories/1-1-user-authentication.md`)
- If exists → upgrade status to at least `ready-for-dev`
**Preservation rule:**
- If existing `{status_file}` exists and has more advanced status, preserve it
- Never downgrade status (e.g., don't change `done` to `ready-for-dev`)
**Status Flow Reference:**
- Epic: `backlog``in-progress``done`
- Story: `backlog``ready-for-dev``in-progress``review``done`
- Retrospective: `optional``done`
</step>
<step n="4" goal="Generate sprint status file">
<action>Create or update {status_file} with:</action>
**File Structure:**
```yaml
# generated: {date}
# last_updated: {date}
# project: {project_name}
# project_key: {project_key}
# tracking_system: {tracking_system}
# story_location: {story_location}
# STATUS DEFINITIONS:
# ==================
# Epic Status:
# - backlog: Epic not yet started
# - in-progress: Epic actively being worked on
# - done: All stories in epic completed
#
# Epic Status Transitions:
# - backlog → in-progress: Automatically when first story is created (via create-story)
# - in-progress → done: Manually when all stories reach 'done' status
#
# Story Status:
# - backlog: Story only exists in epic file
# - ready-for-dev: Story file created in stories folder
# - in-progress: Developer actively working on implementation
# - review: Ready for code review (via Dev's code-review workflow)
# - done: Story completed
#
# Retrospective Status:
# - optional: Can be completed but not required
# - done: Retrospective has been completed
#
# WORKFLOW NOTES:
# ===============
# - Epic transitions to 'in-progress' automatically when first story is created
# - Stories can be worked in parallel if team capacity allows
# - Developer typically creates next story after previous one is 'done' to incorporate learnings
# - Dev moves story to 'review', then runs code-review (fresh context, different LLM recommended)
generated: { date }
last_updated: { date }
project: { project_name }
project_key: { project_key }
tracking_system: { tracking_system }
story_location: { story_location }
development_status:
# All epics, stories, and retrospectives in order
```
<action>Write the complete sprint status YAML to {status_file}</action>
<action>CRITICAL: Metadata appears TWICE - once as comments (#) for documentation, once as YAML key:value fields for parsing</action>
<action>Ensure all items are ordered: epic, its stories, its retrospective, next epic...</action>
</step>
<step n="5" goal="Validate and report">
<action>Perform validation checks:</action>
- [ ] Every epic in epic files appears in {status_file}
- [ ] Every story in epic files appears in {status_file}
- [ ] Every epic has a corresponding retrospective entry
- [ ] No items in {status_file} that don't exist in epic files
- [ ] All status values are legal (match state machine definitions)
- [ ] File is valid YAML syntax
<action>Count totals:</action>
- Total epics: {{epic_count}}
- Total stories: {{story_count}}
- Epics in-progress: {{in_progress_count}}
- Stories done: {{done_count}}
<action>Display completion summary to {user_name} in {communication_language}:</action>
**Sprint Status Generated Successfully**
- **File Location:** {status_file}
- **Total Epics:** {{epic_count}}
- **Total Stories:** {{story_count}}
- **Epics In Progress:** {{in_progress_count}}
- **Stories Completed:** {{done_count}}
**Next Steps:**
1. Review the generated {status_file}
2. Use this file to track development progress
3. Agents will update statuses as they work
4. Re-run this workflow to refresh auto-detected statuses
<action>Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.</action>
</step>
</workflow>
## Additional Documentation
### Status State Machine
**Epic Status Flow:**
```
backlog → in-progress → done
```
- **backlog**: Epic not yet started
- **in-progress**: Epic actively being worked on (stories being created/implemented)
- **done**: All stories in epic completed
**Story Status Flow:**
```
backlog → ready-for-dev → in-progress → review → done
```
- **backlog**: Story only exists in epic file
- **ready-for-dev**: Story file created (e.g., `stories/1-3-plant-naming.md`)
- **in-progress**: Developer actively working
- **review**: Ready for code review (via Dev's code-review workflow)
- **done**: Completed
**Retrospective Status:**
```
optional ↔ done
```
- **optional**: Ready to be conducted but not required
- **done**: Finished
### Guidelines
1. **Epic Activation**: Mark epic as `in-progress` when starting work on its first story
2. **Sequential Default**: Stories are typically worked in order, but parallel work is supported
3. **Parallel Work Supported**: Multiple stories can be `in-progress` if team capacity allows
4. **Review Before Done**: Stories should pass through `review` before `done`
5. **Learning Transfer**: Developer typically creates next story after previous one is `done` to incorporate learnings
Follow the instructions in ./workflow.md.

View File

@ -1,41 +0,0 @@
# DO NOT EDIT -- overwritten on every update.
#
# Workflow customization surface for bmad-sprint-planning. Mirrors the
# agent customization shape under the [workflow] namespace.
[workflow]
# --- Configurable below. Overrides merge per BMad structural rules: ---
# scalars: override wins • arrays (persistent_facts, activation_steps_*): append
# arrays-of-tables with `code`/`id`: replace matching items, append new ones.
# Steps to run before the standard activation (config load, greet).
# Overrides append. Use for pre-flight loads, compliance checks, etc.
activation_steps_prepend = []
# Steps to run after greet but before the workflow begins.
# Overrides append. Use for context-heavy setup that should happen
# once the user has been acknowledged.
activation_steps_append = []
# Persistent facts the workflow keeps in mind for the whole run
# (standards, compliance constraints, stylistic guardrails).
# Distinct from the runtime memory sidecar — these are static context
# loaded on activation. Overrides append.
#
# Each entry is either:
# - a literal sentence, e.g. "All stories must include testable acceptance criteria."
# - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
# (glob patterns are supported; the file's contents are loaded and treated as facts).
persistent_facts = [
"file:{project-root}/**/project-context.md",
]
# Scalar: executed when the workflow reaches its final step,
# after sprint-status.yaml is generated and validated. Override wins.
# Leave empty for no custom post-completion behavior.
on_complete = ""

View File

@ -0,0 +1,263 @@
# Sprint Planning Workflow
**Goal:** Generate sprint status tracking from epics, detecting current story statuses and building a complete sprint-status.yaml file.
**Your Role:** You are a Developer generating and maintaining sprint tracking. Parse epic files, detect story statuses, and produce a structured sprint-status.yaml.
---
## INITIALIZATION
### Configuration Loading
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
- `project_name`, `user_name`
- `communication_language`, `document_output_language`
- `implementation_artifacts`
- `planning_artifacts`
- `date` as system-generated current datetime
- YOU MUST ALWAYS SPEAK OUTPUT in your Agent communication style with the config `{communication_language}`
### Paths
- `tracking_system` = `file-system`
- `project_key` = `NOKEY`
- `story_location` = `{implementation_artifacts}`
- `story_location_absolute` = `{implementation_artifacts}`
- `epics_location` = `{planning_artifacts}`
- `epics_pattern` = `*epic*.md`
- `status_file` = `{implementation_artifacts}/sprint-status.yaml`
### Input Files
| Input | Path | Load Strategy |
|-------|------|---------------|
| Epics | `{planning_artifacts}/*epic*.md` (whole) or `{planning_artifacts}/*epic*/*.md` (sharded) | FULL_LOAD |
### Context
- `project_context` = `**/project-context.md` (load if exists)
---
## EXECUTION
### Document Discovery - Full Epic Loading
**Strategy**: Sprint planning needs ALL epics and stories to build complete status tracking.
**Epic Discovery Process:**
1. **Search for whole document first** - Look for `epics.md`, `bmm-epics.md`, or any `*epic*.md` file
2. **Check for sharded version** - If whole document not found, look for `epics/index.md`
3. **If sharded version found**:
- Read `index.md` to understand the document structure
- Read ALL epic section files listed in the index (e.g., `epic-1.md`, `epic-2.md`, etc.)
- Process all epics and their stories from the combined content
- This ensures complete sprint status coverage
4. **Priority**: If both whole and sharded versions exist, use the whole document
**Fuzzy matching**: Be flexible with document names - users may use variations like `epics.md`, `bmm-epics.md`, `user-stories.md`, etc.
<workflow>
<step n="1" goal="Parse epic files and extract all work items">
<action>Load {project_context} for project-wide patterns and conventions (if exists)</action>
<action>Communicate in {communication_language} with {user_name}</action>
<action>Look for all files matching `{epics_pattern}` in {epics_location}</action>
<action>Could be a single `epics.md` file or multiple `epic-1.md`, `epic-2.md` files</action>
<action>For each epic file found, extract:</action>
- Epic numbers from headers like `## Epic 1:` or `## Epic 2:`
- Story IDs and titles from patterns like `### Story 1.1: User Authentication`
- Convert story format from `Epic.Story: Title` to kebab-case key: `epic-story-title`
**Story ID Conversion Rules:**
- Original: `### Story 1.1: User Authentication`
- Replace period with dash: `1-1`
- Convert title to kebab-case: `user-authentication`
- Final key: `1-1-user-authentication`
<action>Build complete inventory of all epics and stories from all epic files</action>
</step>
<step n="2" goal="Build sprint status structure">
<action>For each epic found, create entries in this order:</action>
1. **Epic entry** - Key: `epic-{num}`, Default status: `backlog`
2. **Story entries** - Key: `{epic}-{story}-{title}`, Default status: `backlog`
3. **Retrospective entry** - Key: `epic-{num}-retrospective`, Default status: `optional`
**Example structure:**
```yaml
development_status:
epic-1: backlog
1-1-user-authentication: backlog
1-2-account-management: backlog
epic-1-retrospective: optional
```
</step>
<step n="3" goal="Apply intelligent status detection">
<action>For each story, detect current status by checking files:</action>
**Story file detection:**
- Check: `{story_location_absolute}/{story-key}.md` (e.g., `stories/1-1-user-authentication.md`)
- If exists → upgrade status to at least `ready-for-dev`
**Preservation rule:**
- If existing `{status_file}` exists and has more advanced status, preserve it
- Never downgrade status (e.g., don't change `done` to `ready-for-dev`)
**Status Flow Reference:**
- Epic: `backlog``in-progress``done`
- Story: `backlog``ready-for-dev``in-progress``review``done`
- Retrospective: `optional``done`
</step>
<step n="4" goal="Generate sprint status file">
<action>Create or update {status_file} with:</action>
**File Structure:**
```yaml
# generated: {date}
# last_updated: {date}
# project: {project_name}
# project_key: {project_key}
# tracking_system: {tracking_system}
# story_location: {story_location}
# STATUS DEFINITIONS:
# ==================
# Epic Status:
# - backlog: Epic not yet started
# - in-progress: Epic actively being worked on
# - done: All stories in epic completed
#
# Epic Status Transitions:
# - backlog → in-progress: Automatically when first story is created (via create-story)
# - in-progress → done: Manually when all stories reach 'done' status
#
# Story Status:
# - backlog: Story only exists in epic file
# - ready-for-dev: Story file created in stories folder
# - in-progress: Developer actively working on implementation
# - review: Ready for code review (via Dev's code-review workflow)
# - done: Story completed
#
# Retrospective Status:
# - optional: Can be completed but not required
# - done: Retrospective has been completed
#
# WORKFLOW NOTES:
# ===============
# - Epic transitions to 'in-progress' automatically when first story is created
# - Stories can be worked in parallel if team capacity allows
# - Developer typically creates next story after previous one is 'done' to incorporate learnings
# - Dev moves story to 'review', then runs code-review (fresh context, different LLM recommended)
generated: { date }
last_updated: { date }
project: { project_name }
project_key: { project_key }
tracking_system: { tracking_system }
story_location: { story_location }
development_status:
# All epics, stories, and retrospectives in order
```
<action>Write the complete sprint status YAML to {status_file}</action>
<action>CRITICAL: Metadata appears TWICE - once as comments (#) for documentation, once as YAML key:value fields for parsing</action>
<action>Ensure all items are ordered: epic, its stories, its retrospective, next epic...</action>
</step>
<step n="5" goal="Validate and report">
<action>Perform validation checks:</action>
- [ ] Every epic in epic files appears in {status_file}
- [ ] Every story in epic files appears in {status_file}
- [ ] Every epic has a corresponding retrospective entry
- [ ] No items in {status_file} that don't exist in epic files
- [ ] All status values are legal (match state machine definitions)
- [ ] File is valid YAML syntax
<action>Count totals:</action>
- Total epics: {{epic_count}}
- Total stories: {{story_count}}
- Epics in-progress: {{in_progress_count}}
- Stories done: {{done_count}}
<action>Display completion summary to {user_name} in {communication_language}:</action>
**Sprint Status Generated Successfully**
- **File Location:** {status_file}
- **Total Epics:** {{epic_count}}
- **Total Stories:** {{story_count}}
- **Epics In Progress:** {{in_progress_count}}
- **Stories Completed:** {{done_count}}
**Next Steps:**
1. Review the generated {status_file}
2. Use this file to track development progress
3. Agents will update statuses as they work
4. Re-run this workflow to refresh auto-detected statuses
</step>
</workflow>
## Additional Documentation
### Status State Machine
**Epic Status Flow:**
```
backlog → in-progress → done
```
- **backlog**: Epic not yet started
- **in-progress**: Epic actively being worked on (stories being created/implemented)
- **done**: All stories in epic completed
**Story Status Flow:**
```
backlog → ready-for-dev → in-progress → review → done
```
- **backlog**: Story only exists in epic file
- **ready-for-dev**: Story file created (e.g., `stories/1-3-plant-naming.md`)
- **in-progress**: Developer actively working
- **review**: Ready for code review (via Dev's code-review workflow)
- **done**: Completed
**Retrospective Status:**
```
optional ↔ done
```
- **optional**: Ready to be conducted but not required
- **done**: Finished
### Guidelines
1. **Epic Activation**: Mark epic as `in-progress` when starting work on its first story
2. **Sequential Default**: Stories are typically worked in order, but parallel work is supported
3. **Parallel Work Supported**: Multiple stories can be `in-progress` if team capacity allows
4. **Review Before Done**: Stories should pass through `review` before `done`
5. **Learning Transfer**: Developer typically creates next story after previous one is `done` to incorporate learnings

View File

@ -3,295 +3,4 @@ name: bmad-sprint-status
description: 'Summarize sprint status and surface risks. Use when the user says "check sprint status" or "show sprint status"'
---
# Sprint Status Workflow
**Goal:** Summarize sprint status, surface risks, and recommend the next workflow action.
**Your Role:** You are a Developer providing clear, actionable sprint visibility. No time estimates — focus on status, risks, and next steps.
## Conventions
- Bare paths (e.g. `checklist.md`) resolve from the skill root.
- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives).
- `{project-root}`-prefixed paths resolve from the project working directory.
- `{skill-name}` resolves to the skill directory's basename.
## On Activation
### Step 1: Resolve the Workflow Block
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
1. `{skill-root}/customize.toml` — defaults
2. `{project-root}/_bmad/custom/{skill-name}.toml` — team overrides
3. `{project-root}/_bmad/custom/{skill-name}.user.toml` — personal overrides
Any missing file is skipped. Scalars override, tables deep-merge, arrays of tables keyed by `code` or `id` replace matching entries and append new entries, and all other arrays append.
### Step 2: Execute Prepend Steps
Execute each entry in `{workflow.activation_steps_prepend}` in order before proceeding.
### Step 3: Load Persistent Facts
Treat every entry in `{workflow.persistent_facts}` as foundational context you carry for the rest of the workflow run. Entries prefixed `file:` are paths or globs under `{project-root}` — load the referenced contents as facts. All other entries are facts verbatim.
### Step 4: Load Config
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
- `project_name`, `user_name`
- `communication_language`, `document_output_language`
- `implementation_artifacts`
- `date` as system-generated current datetime
- YOU MUST ALWAYS SPEAK OUTPUT in your Agent communication style with the config `{communication_language}`
### Step 5: Greet the User
Greet `{user_name}`, speaking in `{communication_language}`.
### Step 6: Execute Append Steps
Execute each entry in `{workflow.activation_steps_append}` in order.
Activation is complete. Begin the workflow below.
## Paths
- `sprint_status_file` = `{implementation_artifacts}/sprint-status.yaml`
## Input Files
| Input | Path | Load Strategy |
|-------|------|---------------|
| Sprint status | `{sprint_status_file}` | FULL_LOAD |
## Execution
<workflow>
<step n="0" goal="Determine execution mode">
<action>Set mode = {{mode}} if provided by caller; otherwise mode = "interactive"</action>
<check if="mode == data">
<action>Jump to Step 20</action>
</check>
<check if="mode == validate">
<action>Jump to Step 30</action>
</check>
<check if="mode == interactive">
<action>Continue to Step 1</action>
</check>
</step>
<step n="1" goal="Locate sprint status file">
<action>Load {project_context} for project-wide patterns and conventions (if exists)</action>
<action>Try {sprint_status_file}</action>
<check if="file not found">
<output>sprint-status.yaml not found.
Run `/bmad:bmm:workflows:sprint-planning` to generate it, then rerun sprint-status.</output>
<action>Exit workflow</action>
</check>
<action>Continue to Step 2</action>
</step>
<step n="2" goal="Read and parse sprint-status.yaml">
<action>Read the FULL file: {sprint_status_file}</action>
<action>Parse fields: generated, last_updated, project, project_key, tracking_system, story_location</action>
<action>Parse development_status map. Classify keys:</action>
- Epics: keys starting with "epic-" (and not ending with "-retrospective")
- Retrospectives: keys ending with "-retrospective"
- Stories: everything else (e.g., 1-2-login-form)
<action>Map legacy story status "drafted" → "ready-for-dev"</action>
<action>Count story statuses: backlog, ready-for-dev, in-progress, review, done</action>
<action>Map legacy epic status "contexted" → "in-progress"</action>
<action>Count epic statuses: backlog, in-progress, done</action>
<action>Count retrospective statuses: optional, done</action>
<action>Validate all statuses against known values:</action>
- Valid story statuses: backlog, ready-for-dev, in-progress, review, done, drafted (legacy)
- Valid epic statuses: backlog, in-progress, done, contexted (legacy)
- Valid retrospective statuses: optional, done
<check if="any status is unrecognized">
<output>
**Unknown status detected:**
{{#each invalid_entries}}
- `{{key}}`: "{{status}}" (not recognized)
{{/each}}
**Valid statuses:**
- Stories: backlog, ready-for-dev, in-progress, review, done
- Epics: backlog, in-progress, done
- Retrospectives: optional, done
</output>
<ask>How should these be corrected?
{{#each invalid_entries}}
{{@index}}. {{key}}: "{{status}}" → [select valid status]
{{/each}}
Enter corrections (e.g., "1=in-progress, 2=backlog") or "skip" to continue without fixing:</ask>
<check if="user provided corrections">
<action>Update sprint-status.yaml with corrected values</action>
<action>Re-parse the file with corrected statuses</action>
</check>
</check>
<action>Detect risks:</action>
- IF any story has status "review": suggest `/bmad:bmm:workflows:code-review`
- IF any story has status "in-progress" AND no stories have status "ready-for-dev": recommend staying focused on active story
- IF all epics have status "backlog" AND no stories have status "ready-for-dev": prompt `/bmad:bmm:workflows:create-story`
- IF `last_updated` timestamp is more than 7 days old (or `last_updated` is missing, fall back to `generated`): warn "sprint-status.yaml may be stale"
- IF any story key doesn't match an epic pattern (e.g., story "5-1-..." but no "epic-5"): warn "orphaned story detected"
- IF any epic has status in-progress but has no associated stories: warn "in-progress epic has no stories"
</step>
<step n="3" goal="Select next action recommendation">
<action>Pick the next recommended workflow using priority:</action>
<note>When selecting "first" story: sort by epic number, then story number (e.g., 1-1 before 1-2 before 2-1)</note>
1. If any story status == in-progress → recommend `dev-story` for the first in-progress story
2. Else if any story status == review → recommend `code-review` for the first review story
3. Else if any story status == ready-for-dev → recommend `dev-story`
4. Else if any story status == backlog → recommend `create-story`
5. Else if any retrospective status == optional → recommend `retrospective`
6. Else → All implementation items done; congratulate the user - you both did amazing work together!
<action>Store selected recommendation as: next_story_id, next_workflow_id, next_agent (DEV)</action>
</step>
<step n="4" goal="Display summary">
<output>
## Sprint Status
- Project: {{project}} ({{project_key}})
- Tracking: {{tracking_system}}
- Status file: {sprint_status_file}
**Stories:** backlog {{count_backlog}}, ready-for-dev {{count_ready}}, in-progress {{count_in_progress}}, review {{count_review}}, done {{count_done}}
**Epics:** backlog {{epic_backlog}}, in-progress {{epic_in_progress}}, done {{epic_done}}
**Next Recommendation:** /bmad:bmm:workflows:{{next_workflow_id}} ({{next_story_id}})
{{#if risks}}
**Risks:**
{{#each risks}}
- {{this}}
{{/each}}
{{/if}}
</output>
</step>
<step n="5" goal="Offer actions">
<ask>Pick an option:
1) Run recommended workflow now
2) Show all stories grouped by status
3) Show raw sprint-status.yaml
4) Exit
Choice:</ask>
<check if="choice == 1">
<output>Run `/bmad:bmm:workflows:{{next_workflow_id}}`.
If the command targets a story, set `story_key={{next_story_id}}` when prompted.</output>
</check>
<check if="choice == 2">
<output>
### Stories by Status
- In Progress: {{stories_in_progress}}
- Review: {{stories_in_review}}
- Ready for Dev: {{stories_ready_for_dev}}
- Backlog: {{stories_backlog}}
- Done: {{stories_done}}
</output>
</check>
<check if="choice == 3">
<action>Display the full contents of {sprint_status_file}</action>
</check>
<check if="choice == 4">
<action>Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.</action>
<action>Exit workflow</action>
</check>
</step>
<!-- ========================= -->
<!-- Data mode for other flows -->
<!-- ========================= -->
<step n="20" goal="Data mode output">
<action>Load and parse {sprint_status_file} same as Step 2</action>
<action>Compute recommendation same as Step 3</action>
<template-output>next_workflow_id = {{next_workflow_id}}</template-output>
<template-output>next_story_id = {{next_story_id}}</template-output>
<template-output>count_backlog = {{count_backlog}}</template-output>
<template-output>count_ready = {{count_ready}}</template-output>
<template-output>count_in_progress = {{count_in_progress}}</template-output>
<template-output>count_review = {{count_review}}</template-output>
<template-output>count_done = {{count_done}}</template-output>
<template-output>epic_backlog = {{epic_backlog}}</template-output>
<template-output>epic_in_progress = {{epic_in_progress}}</template-output>
<template-output>epic_done = {{epic_done}}</template-output>
<template-output>risks = {{risks}}</template-output>
<action>Return to caller</action>
</step>
<!-- ========================= -->
<!-- Validate mode -->
<!-- ========================= -->
<step n="30" goal="Validate sprint-status file">
<action>Check that {sprint_status_file} exists</action>
<check if="missing">
<template-output>is_valid = false</template-output>
<template-output>error = "sprint-status.yaml missing"</template-output>
<template-output>suggestion = "Run sprint-planning to create it"</template-output>
<action>Return</action>
</check>
<action>Read and parse {sprint_status_file}</action>
<action>Validate required metadata fields exist: generated, project, project_key, tracking_system, story_location (last_updated is optional for backward compatibility)</action>
<check if="any required field missing">
<template-output>is_valid = false</template-output>
<template-output>error = "Missing required field(s): {{missing_fields}}"</template-output>
<template-output>suggestion = "Re-run sprint-planning or add missing fields manually"</template-output>
<action>Return</action>
</check>
<action>Verify development_status section exists with at least one entry</action>
<check if="development_status missing or empty">
<template-output>is_valid = false</template-output>
<template-output>error = "development_status missing or empty"</template-output>
<template-output>suggestion = "Re-run sprint-planning or repair the file manually"</template-output>
<action>Return</action>
</check>
<action>Validate all status values against known valid statuses:</action>
- Stories: backlog, ready-for-dev, in-progress, review, done (legacy: drafted)
- Epics: backlog, in-progress, done (legacy: contexted)
- Retrospectives: optional, done
<check if="any invalid status found">
<template-output>is_valid = false</template-output>
<template-output>error = "Invalid status values: {{invalid_entries}}"</template-output>
<template-output>suggestion = "Fix invalid statuses in sprint-status.yaml"</template-output>
<action>Return</action>
</check>
<template-output>is_valid = true</template-output>
<template-output>message = "sprint-status.yaml valid: metadata complete, all statuses recognized"</template-output>
<action>Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.</action>
</step>
</workflow>
Follow the instructions in ./workflow.md.

View File

@ -1,41 +0,0 @@
# DO NOT EDIT -- overwritten on every update.
#
# Workflow customization surface for bmad-sprint-status. Mirrors the
# agent customization shape under the [workflow] namespace.
[workflow]
# --- Configurable below. Overrides merge per BMad structural rules: ---
# scalars: override wins • arrays (persistent_facts, activation_steps_*): append
# arrays-of-tables with `code`/`id`: replace matching items, append new ones.
# Steps to run before the standard activation (config load, greet).
# Overrides append. Use for pre-flight loads, compliance checks, etc.
activation_steps_prepend = []
# Steps to run after greet but before the workflow begins.
# Overrides append. Use for context-heavy setup that should happen
# once the user has been acknowledged.
activation_steps_append = []
# Persistent facts the workflow keeps in mind for the whole run
# (standards, compliance constraints, stylistic guardrails).
# Distinct from the runtime memory sidecar — these are static context
# loaded on activation. Overrides append.
#
# Each entry is either:
# - a literal sentence, e.g. "All stories must include testable acceptance criteria."
# - a file reference prefixed with `file:`, e.g. "file:{project-root}/docs/standards.md"
# (glob patterns are supported; the file's contents are loaded and treated as facts).
persistent_facts = [
"file:{project-root}/**/project-context.md",
]
# Scalar: executed when the workflow reaches its final step,
# after sprint status is summarized and risks are surfaced. Override wins.
# Leave empty for no custom post-completion behavior.
on_complete = ""

View File

@ -0,0 +1,261 @@
# Sprint Status Workflow
**Goal:** Summarize sprint status, surface risks, and recommend the next workflow action.
**Your Role:** You are a Developer providing clear, actionable sprint visibility. No time estimates — focus on status, risks, and next steps.
---
## INITIALIZATION
### Configuration Loading
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
- `project_name`, `user_name`
- `communication_language`, `document_output_language`
- `implementation_artifacts`
- `date` as system-generated current datetime
- YOU MUST ALWAYS SPEAK OUTPUT in your Agent communication style with the config `{communication_language}`
### Paths
- `sprint_status_file` = `{implementation_artifacts}/sprint-status.yaml`
### Input Files
| Input | Path | Load Strategy |
|-------|------|---------------|
| Sprint status | `{sprint_status_file}` | FULL_LOAD |
### Context
- `project_context` = `**/project-context.md` (load if exists)
---
## EXECUTION
<workflow>
<step n="0" goal="Determine execution mode">
<action>Set mode = {{mode}} if provided by caller; otherwise mode = "interactive"</action>
<check if="mode == data">
<action>Jump to Step 20</action>
</check>
<check if="mode == validate">
<action>Jump to Step 30</action>
</check>
<check if="mode == interactive">
<action>Continue to Step 1</action>
</check>
</step>
<step n="1" goal="Locate sprint status file">
<action>Load {project_context} for project-wide patterns and conventions (if exists)</action>
<action>Try {sprint_status_file}</action>
<check if="file not found">
<output>❌ sprint-status.yaml not found.
Run `/bmad:bmm:workflows:sprint-planning` to generate it, then rerun sprint-status.</output>
<action>Exit workflow</action>
</check>
<action>Continue to Step 2</action>
</step>
<step n="2" goal="Read and parse sprint-status.yaml">
<action>Read the FULL file: {sprint_status_file}</action>
<action>Parse fields: generated, last_updated, project, project_key, tracking_system, story_location</action>
<action>Parse development_status map. Classify keys:</action>
- Epics: keys starting with "epic-" (and not ending with "-retrospective")
- Retrospectives: keys ending with "-retrospective"
- Stories: everything else (e.g., 1-2-login-form)
<action>Map legacy story status "drafted" → "ready-for-dev"</action>
<action>Count story statuses: backlog, ready-for-dev, in-progress, review, done</action>
<action>Map legacy epic status "contexted" → "in-progress"</action>
<action>Count epic statuses: backlog, in-progress, done</action>
<action>Count retrospective statuses: optional, done</action>
<action>Validate all statuses against known values:</action>
- Valid story statuses: backlog, ready-for-dev, in-progress, review, done, drafted (legacy)
- Valid epic statuses: backlog, in-progress, done, contexted (legacy)
- Valid retrospective statuses: optional, done
<check if="any status is unrecognized">
<output>
⚠️ **Unknown status detected:**
{{#each invalid_entries}}
- `{{key}}`: "{{status}}" (not recognized)
{{/each}}
**Valid statuses:**
- Stories: backlog, ready-for-dev, in-progress, review, done
- Epics: backlog, in-progress, done
- Retrospectives: optional, done
</output>
<ask>How should these be corrected?
{{#each invalid_entries}}
{{@index}}. {{key}}: "{{status}}" → [select valid status]
{{/each}}
Enter corrections (e.g., "1=in-progress, 2=backlog") or "skip" to continue without fixing:</ask>
<check if="user provided corrections">
<action>Update sprint-status.yaml with corrected values</action>
<action>Re-parse the file with corrected statuses</action>
</check>
</check>
<action>Detect risks:</action>
- IF any story has status "review": suggest `/bmad:bmm:workflows:code-review`
- IF any story has status "in-progress" AND no stories have status "ready-for-dev": recommend staying focused on active story
- IF all epics have status "backlog" AND no stories have status "ready-for-dev": prompt `/bmad:bmm:workflows:create-story`
- IF `last_updated` timestamp is more than 7 days old (or `last_updated` is missing, fall back to `generated`): warn "sprint-status.yaml may be stale"
- IF any story key doesn't match an epic pattern (e.g., story "5-1-..." but no "epic-5"): warn "orphaned story detected"
- IF any epic has status in-progress but has no associated stories: warn "in-progress epic has no stories"
</step>
<step n="3" goal="Select next action recommendation">
<action>Pick the next recommended workflow using priority:</action>
<note>When selecting "first" story: sort by epic number, then story number (e.g., 1-1 before 1-2 before 2-1)</note>
1. If any story status == in-progress → recommend `dev-story` for the first in-progress story
2. Else if any story status == review → recommend `code-review` for the first review story
3. Else if any story status == ready-for-dev → recommend `dev-story`
4. Else if any story status == backlog → recommend `create-story`
5. Else if any retrospective status == optional → recommend `retrospective`
6. Else → All implementation items done; congratulate the user - you both did amazing work together!
<action>Store selected recommendation as: next_story_id, next_workflow_id, next_agent (DEV)</action>
</step>
<step n="4" goal="Display summary">
<output>
## 📊 Sprint Status
- Project: {{project}} ({{project_key}})
- Tracking: {{tracking_system}}
- Status file: {sprint_status_file}
**Stories:** backlog {{count_backlog}}, ready-for-dev {{count_ready}}, in-progress {{count_in_progress}}, review {{count_review}}, done {{count_done}}
**Epics:** backlog {{epic_backlog}}, in-progress {{epic_in_progress}}, done {{epic_done}}
**Next Recommendation:** /bmad:bmm:workflows:{{next_workflow_id}} ({{next_story_id}})
{{#if risks}}
**Risks:**
{{#each risks}}
- {{this}}
{{/each}}
{{/if}}
</output>
</step>
<step n="5" goal="Offer actions">
<ask>Pick an option:
1) Run recommended workflow now
2) Show all stories grouped by status
3) Show raw sprint-status.yaml
4) Exit
Choice:</ask>
<check if="choice == 1">
<output>Run `/bmad:bmm:workflows:{{next_workflow_id}}`.
If the command targets a story, set `story_key={{next_story_id}}` when prompted.</output>
</check>
<check if="choice == 2">
<output>
### Stories by Status
- In Progress: {{stories_in_progress}}
- Review: {{stories_in_review}}
- Ready for Dev: {{stories_ready_for_dev}}
- Backlog: {{stories_backlog}}
- Done: {{stories_done}}
</output>
</check>
<check if="choice == 3">
<action>Display the full contents of {sprint_status_file}</action>
</check>
<check if="choice == 4">
<action>Exit workflow</action>
</check>
</step>
<!-- ========================= -->
<!-- Data mode for other flows -->
<!-- ========================= -->
<step n="20" goal="Data mode output">
<action>Load and parse {sprint_status_file} same as Step 2</action>
<action>Compute recommendation same as Step 3</action>
<template-output>next_workflow_id = {{next_workflow_id}}</template-output>
<template-output>next_story_id = {{next_story_id}}</template-output>
<template-output>count_backlog = {{count_backlog}}</template-output>
<template-output>count_ready = {{count_ready}}</template-output>
<template-output>count_in_progress = {{count_in_progress}}</template-output>
<template-output>count_review = {{count_review}}</template-output>
<template-output>count_done = {{count_done}}</template-output>
<template-output>epic_backlog = {{epic_backlog}}</template-output>
<template-output>epic_in_progress = {{epic_in_progress}}</template-output>
<template-output>epic_done = {{epic_done}}</template-output>
<template-output>risks = {{risks}}</template-output>
<action>Return to caller</action>
</step>
<!-- ========================= -->
<!-- Validate mode -->
<!-- ========================= -->
<step n="30" goal="Validate sprint-status file">
<action>Check that {sprint_status_file} exists</action>
<check if="missing">
<template-output>is_valid = false</template-output>
<template-output>error = "sprint-status.yaml missing"</template-output>
<template-output>suggestion = "Run sprint-planning to create it"</template-output>
<action>Return</action>
</check>
<action>Read and parse {sprint_status_file}</action>
<action>Validate required metadata fields exist: generated, project, project_key, tracking_system, story_location (last_updated is optional for backward compatibility)</action>
<check if="any required field missing">
<template-output>is_valid = false</template-output>
<template-output>error = "Missing required field(s): {{missing_fields}}"</template-output>
<template-output>suggestion = "Re-run sprint-planning or add missing fields manually"</template-output>
<action>Return</action>
</check>
<action>Verify development_status section exists with at least one entry</action>
<check if="development_status missing or empty">
<template-output>is_valid = false</template-output>
<template-output>error = "development_status missing or empty"</template-output>
<template-output>suggestion = "Re-run sprint-planning or repair the file manually"</template-output>
<action>Return</action>
</check>
<action>Validate all status values against known valid statuses:</action>
- Stories: backlog, ready-for-dev, in-progress, review, done (legacy: drafted)
- Epics: backlog, in-progress, done (legacy: contexted)
- Retrospectives: optional, done
<check if="any invalid status found">
<template-output>is_valid = false</template-output>
<template-output>error = "Invalid status values: {{invalid_entries}}"</template-output>
<template-output>suggestion = "Fix invalid statuses in sprint-status.yaml"</template-output>
<action>Return</action>
</check>
<template-output>is_valid = true</template-output>
<template-output>message = "sprint-status.yaml valid: metadata complete, all statuses recognized"</template-output>
</step>
</workflow>

View File

@ -1,34 +1,33 @@
module,skill,display-name,menu-code,description,action,args,phase,preceded-by,followed-by,required,output-location,outputs
module,skill,display-name,menu-code,description,action,args,phase,after,before,required,output-location,outputs
BMad Method,_meta,,,,,,,,,false,https://docs.bmad-method.org/llms.txt,
BMad Method,bmad-document-project,Document Project,DP,Analyze an existing project to produce useful documentation.,,,anytime,,,false,project-knowledge,*
BMad Method,bmad-generate-project-context,Generate Project Context,GPC,Scan existing codebase to generate a lean LLM-optimized project-context.md. Essential for brownfield projects.,,,anytime,,,false,output_folder,project context
BMad Method,bmad-quick-dev,Quick Dev,QQ,Unified intent-in code-out workflow: clarify plan implement review and present.,,,anytime,,,false,implementation_artifacts,spec and project implementation
BMad Method,bmad-correct-course,Correct Course,CC,Navigate significant changes. May recommend start over update PRD redo architecture sprint planning or correct epics and stories.,,,anytime,,,false,planning_artifacts,change proposal
BMad Method,bmad-document-project,Document Project,DP,Analyze an existing project to produce useful documentation.,,anytime,,,false,project-knowledge,*
BMad Method,bmad-generate-project-context,Generate Project Context,GPC,Scan existing codebase to generate a lean LLM-optimized project-context.md. Essential for brownfield projects.,,anytime,,,false,output_folder,project context
BMad Method,bmad-quick-dev,Quick Dev,QQ,Unified intent-in code-out workflow: clarify plan implement review and present.,,anytime,,,false,implementation_artifacts,spec and project implementation
BMad Method,bmad-correct-course,Correct Course,CC,Navigate significant changes. May recommend start over update PRD redo architecture sprint planning or correct epics and stories.,,anytime,,,false,planning_artifacts,change proposal
BMad Method,bmad-agent-tech-writer,Write Document,WD,"Describe in detail what you want, and the agent will follow documentation best practices. Multi-turn conversation with subprocess for research/review.",write,,anytime,,,false,project-knowledge,document
BMad Method,bmad-agent-tech-writer,Update Standards,US,Update agent memory documentation-standards.md with your specific preferences if you discover missing document conventions.,update-standards,,anytime,,,false,_bmad/_memory/tech-writer-sidecar,standards
BMad Method,bmad-agent-tech-writer,Mermaid Generate,MG,Create a Mermaid diagram based on user description. Will suggest diagram types if not specified.,mermaid,,anytime,,,false,planning_artifacts,mermaid diagram
BMad Method,bmad-agent-tech-writer,Validate Document,VD,Review the specified document against documentation standards and best practices. Returns specific actionable improvement suggestions organized by priority.,validate,[path],anytime,,,false,planning_artifacts,validation report
BMad Method,bmad-agent-tech-writer,Explain Concept,EC,Create clear technical explanations with examples and diagrams for complex concepts.,explain,[topic],anytime,,,false,project_knowledge,explanation
BMad Method,bmad-brainstorming,Brainstorm Project,BP,Expert guided facilitation through a single or multiple techniques.,,,1-analysis,,,false,planning_artifacts,brainstorming session
BMad Method,bmad-market-research,Market Research,MR,Market analysis competitive landscape customer needs and trends.,,,1-analysis,,,false,planning_artifacts|project-knowledge,research documents
BMad Method,bmad-domain-research,Domain Research,DR,Industry domain deep dive subject matter expertise and terminology.,,,1-analysis,,,false,planning_artifacts|project_knowledge,research documents
BMad Method,bmad-technical-research,Technical Research,TR,Technical feasibility architecture options and implementation approaches.,,,1-analysis,,,false,planning_artifacts|project_knowledge,research documents
BMad Method,bmad-brainstorming,Brainstorm Project,BP,Expert guided facilitation through a single or multiple techniques.,,1-analysis,,,false,planning_artifacts,brainstorming session
BMad Method,bmad-market-research,Market Research,MR,"Market analysis competitive landscape customer needs and trends.",,1-analysis,,,false,"planning_artifacts|project-knowledge",research documents
BMad Method,bmad-domain-research,Domain Research,DR,Industry domain deep dive subject matter expertise and terminology.,,1-analysis,,,false,"planning_artifacts|project_knowledge",research documents
BMad Method,bmad-technical-research,Technical Research,TR,Technical feasibility architecture options and implementation approaches.,,1-analysis,,,false,"planning_artifacts|project_knowledge",research documents
BMad Method,bmad-product-brief,Create Brief,CB,An expert guided experience to nail down your product idea in a brief. a gentler approach than PRFAQ when you are already sure of your concept and nothing will sway you.,,-A,1-analysis,,,false,planning_artifacts,product brief
BMad Method,bmad-prfaq,PRFAQ Challenge,WB,Working Backwards guided experience to forge and stress-test your product concept to ensure you have a great product that users will love and need through the PRFAQ gauntlet to determine feasibility and alignment with user needs. alternative to product brief.,,-H,1-analysis,,,false,planning_artifacts,prfaq document
BMad Method,bmad-create-prd,Create PRD,CP,Expert led facilitation to produce your Product Requirements Document.,,,2-planning,,,true,planning_artifacts,prd
BMad Method,bmad-create-prd,Create PRD,CP,Expert led facilitation to produce your Product Requirements Document.,,2-planning,,,true,planning_artifacts,prd
BMad Method,bmad-validate-prd,Validate PRD,VP,,,[path],2-planning,bmad-create-prd,,false,planning_artifacts,prd validation report
BMad Method,bmad-edit-prd,Edit PRD,EP,,,[path],2-planning,bmad-validate-prd,,false,planning_artifacts,updated prd
BMad Method,bmad-create-ux-design,Create UX,CU,"Guidance through realizing the plan for your UX, strongly recommended if a UI is a primary piece of the proposed project.",,,2-planning,bmad-create-prd,,false,planning_artifacts,ux design
BMad Method,bmad-create-architecture,Create Architecture,CA,Guided workflow to document technical decisions.,,,3-solutioning,,,true,planning_artifacts,architecture
BMad Method,bmad-create-epics-and-stories,Create Epics and Stories,CE,,,,3-solutioning,bmad-create-architecture,,true,planning_artifacts,epics and stories
BMad Method,bmad-check-implementation-readiness,Check Implementation Readiness,IR,Ensure PRD UX Architecture and Epics Stories are aligned.,,,3-solutioning,bmad-create-epics-and-stories,,true,planning_artifacts,readiness report
BMad Method,bmad-sprint-planning,Sprint Planning,SP,Kicks off implementation by producing a plan the implementation agents will follow in sequence for every story.,,,4-implementation,,,true,implementation_artifacts,sprint status
BMad Method,bmad-sprint-status,Sprint Status,SS,Anytime: Summarize sprint status and route to next workflow.,,,4-implementation,bmad-sprint-planning,,false,,
BMad Method,bmad-create-story,Create Story,CS,Story cycle start: Prepare first found story in the sprint plan that is next or a specific epic/story designation.,create,,4-implementation,bmad-sprint-planning,bmad-create-story:validate,true,implementation_artifacts,story
BMad Method,bmad-create-ux-design,Create UX,CU,"Guidance through realizing the plan for your UX, strongly recommended if a UI is a primary piece of the proposed project.",,2-planning,bmad-create-prd,,false,planning_artifacts,ux design
BMad Method,bmad-create-architecture,Create Architecture,CA,Guided workflow to document technical decisions.,,3-solutioning,,,true,planning_artifacts,architecture
BMad Method,bmad-create-epics-and-stories,Create Epics and Stories,CE,,,3-solutioning,bmad-create-architecture,,true,planning_artifacts,epics and stories
BMad Method,bmad-check-implementation-readiness,Check Implementation Readiness,IR,Ensure PRD UX Architecture and Epics Stories are aligned.,,3-solutioning,bmad-create-epics-and-stories,,true,planning_artifacts,readiness report
BMad Method,bmad-sprint-planning,Sprint Planning,SP,Kicks off implementation by producing a plan the implementation agents will follow in sequence for every story.,,4-implementation,,,true,implementation_artifacts,sprint status
BMad Method,bmad-sprint-status,Sprint Status,SS,Anytime: Summarize sprint status and route to next workflow.,,4-implementation,bmad-sprint-planning,,false,,
BMad Method,bmad-create-story,Create Story,CS,"Story cycle start: Prepare first found story in the sprint plan that is next or a specific epic/story designation.",create,,4-implementation,bmad-sprint-planning,bmad-create-story:validate,true,implementation_artifacts,story
BMad Method,bmad-create-story,Validate Story,VS,Validates story readiness and completeness before development work begins.,validate,,4-implementation,bmad-create-story:create,bmad-dev-story,false,implementation_artifacts,story validation report
BMad Method,bmad-dev-story,Dev Story,DS,Story cycle: Execute story implementation tasks and tests then CR then back to DS if fixes needed.,,,4-implementation,bmad-create-story:validate,,true,,
BMad Method,bmad-code-review,Code Review,CR,Story cycle: If issues back to DS if approved then next CS or ER if epic complete.,,,4-implementation,bmad-dev-story,,false,,
BMad Method,bmad-checkpoint-preview,Checkpoint,CK,Guided walkthrough of a change from purpose and context into details. Use for human review of commits branches or PRs.,,,4-implementation,,,false,,
BMad Method,bmad-qa-generate-e2e-tests,QA Automation Test,QA,Generate automated API and E2E tests for implemented code. NOT for code review or story validation — use CR for that.,,,4-implementation,bmad-dev-story,,false,implementation_artifacts,test suite
BMad Method,bmad-retrospective,Retrospective,ER,Optional at epic end: Review completed work lessons learned and next epic or if major issues consider CC.,,,4-implementation,bmad-code-review,,false,implementation_artifacts,retrospective
BMad Method,bmad-investigate,Investigate,IN,Forensic case investigation calibrated to the input. Evidence-graded analysis with hypothesis tracking. Produces a structured case file.,,4-implementation,,,false,implementation_artifacts,investigation report
BMad Method,bmad-dev-story,Dev Story,DS,Story cycle: Execute story implementation tasks and tests then CR then back to DS if fixes needed.,,4-implementation,bmad-create-story:validate,,true,,
BMad Method,bmad-code-review,Code Review,CR,Story cycle: If issues back to DS if approved then next CS or ER if epic complete.,,4-implementation,bmad-dev-story,,false,,
BMad Method,bmad-checkpoint-preview,Checkpoint,CK,Guided walkthrough of a change from purpose and context into details. Use for human review of commits branches or PRs.,,4-implementation,,,false,,
BMad Method,bmad-qa-generate-e2e-tests,QA Automation Test,QA,Generate automated API and E2E tests for implemented code. NOT for code review or story validation — use CR for that.,,4-implementation,bmad-dev-story,,false,implementation_artifacts,test suite
BMad Method,bmad-retrospective,Retrospective,ER,Optional at epic end: Review completed work lessons learned and next epic or if major issues consider CC.,,4-implementation,bmad-code-review,,false,implementation_artifacts,retrospective

Can't render this file because it has a wrong number of fields in line 3.

View File

@ -5,11 +5,15 @@ default_selected: true # This module will be selected by default for new install
# Variables from Core Config inserted:
## user_name
## project_name
## communication_language
## document_output_language
## output_folder
project_name:
prompt: "What is your project called?"
default: "{directory_name}"
result: "{value}"
user_skill_level:
prompt:
- "What is your development experience level?"

View File

@ -139,7 +139,7 @@ parts: 1
## Solution Architecture
- Plugins: skill bundles with Anthropic plugin standard as base format + bmad-manifest.json extending for BMAD-specific metadata (installer options, capabilities, help integration, phase ordering, dependencies)
- Existing manifest example: `{"module-code":"bmm","replaces-skill":"bmad-create-product-brief","capabilities":[{"name":"create-brief","menu-code":"CB","supports-headless":true,"phase-name":"1-analysis","preceded-by":["brainstorming"],"followed-by":["create-prd"],"is-required":true}]}`
- Existing manifest example: `{"module-code":"bmm","replaces-skill":"bmad-create-product-brief","capabilities":[{"name":"create-brief","menu-code":"CB","supports-headless":true,"phase-name":"1-analysis","after":["brainstorming"],"before":["create-prd"],"is-required":true}]}`
- Vercel skills CLI handles platform translation; integration pattern (wrap/fork/call) is PRD decision
- bmad-setup: global skill scanning installed bmad-manifest.json files, registering capabilities, configuring project settings; always included as base skill in every bundle (solves bootstrapping)
- bmad-update: plugin update path without full reinstall; technical approach (diff/replace/preserve customizations) is PRD decision

View File

@ -33,16 +33,16 @@ When this skill completes, the user should:
The catalog uses this format:
```
module,skill,display-name,menu-code,description,action,args,phase,preceded-by,followed-by,required,output-location,outputs
module,skill,display-name,menu-code,description,action,args,phase,after,before,required,output-location,outputs
```
**Phases** determine the high-level flow:
- `anytime` — available regardless of workflow state
- Numbered phases (`1-analysis`, `2-planning`, etc.) flow in order; naming varies by module
**Sequencing** determines recommended ordering within and across phases (these are soft suggestions, not hard gates — see `required` for gating):
- `preceded-by` — skills that should ideally complete before this one
- `followed-by` — skills that should ideally run after this one
**Dependencies** determine ordering within and across phases:
- `after` — skills that should ideally complete before this one
- `before` — skills that should run after this one
- Format: `skill-name` for single-action skills, `skill-name:action` for multi-action skills
**Required gates**:

View File

@ -1,13 +1,13 @@
module,skill,display-name,menu-code,description,action,args,phase,preceded-by,followed-by,required,output-location,outputs
module,skill,display-name,menu-code,description,action,args,phase,after,before,required,output-location,outputs
Core,_meta,,,,,,,,,false,https://docs.bmad-method.org/llms.txt,
Core,bmad-brainstorming,Brainstorming,BSP,Use early in ideation or when stuck generating ideas.,,,anytime,,,false,{output_folder}/brainstorming,brainstorming session
Core,bmad-party-mode,Party Mode,PM,Orchestrate multi-agent discussions when you need multiple perspectives or want agents to collaborate.,,,anytime,,,false,,
Core,bmad-help,BMad Help,BH,,,,anytime,,,false,,
Core,bmad-index-docs,Index Docs,ID,Use when LLM needs to understand available docs without loading everything.,,,anytime,,,false,,
Core,bmad-shard-doc,Shard Document,SD,Use when doc becomes too large (>500 lines) to manage effectively.,,[path],anytime,,,false,,
Core,bmad-editorial-review-prose,Editorial Review - Prose,EP,Use after drafting to polish written content.,,[path],anytime,,,false,report located with target document,three-column markdown table with suggested fixes
Core,bmad-editorial-review-structure,Editorial Review - Structure,ES,Use when doc produced from multiple subprocesses or needs structural improvement.,,[path],anytime,,,false,report located with target document,
Core,bmad-review-adversarial-general,Adversarial Review,AR,"Use for quality assurance or before finalizing deliverables. Code Review in other modules runs this automatically, but also useful for document reviews.",,[path],anytime,,,false,,
Core,bmad-review-edge-case-hunter,Edge Case Hunter Review,ECH,Use alongside adversarial review for orthogonal coverage — method-driven not attitude-driven.,,[path],anytime,,,false,,
Core,bmad-distillator,Distillator,DG,Use when you need token-efficient distillates that preserve all information for downstream LLM consumption.,,[path],anytime,,,false,adjacent to source document or specified output_path,distillate markdown file(s)
Core,bmad-customize,BMad Customize,BC,"Use when you want to change how an agent or workflow behaves — add persistent facts, swap templates, insert activation hooks, or customize menus. Scans what's customizable, picks the right scope (agent vs workflow), writes the override to _bmad/custom/, and verifies the merge. No TOML hand-authoring required.",,,anytime,,,false,{project-root}/_bmad/custom,TOML override files
Core,bmad-brainstorming,Brainstorming,BSP,Use early in ideation or when stuck generating ideas.,,anytime,,,false,{output_folder}/brainstorming,brainstorming session
Core,bmad-party-mode,Party Mode,PM,Orchestrate multi-agent discussions when you need multiple perspectives or want agents to collaborate.,,anytime,,,false,,
Core,bmad-help,BMad Help,BH,,,anytime,,,false,,
Core,bmad-index-docs,Index Docs,ID,Use when LLM needs to understand available docs without loading everything.,,anytime,,,false,,
Core,bmad-shard-doc,Shard Document,SD,Use when doc becomes too large (>500 lines) to manage effectively.,[path],anytime,,,false,,
Core,bmad-editorial-review-prose,Editorial Review - Prose,EP,Use after drafting to polish written content.,[path],anytime,,,false,report located with target document,three-column markdown table with suggested fixes
Core,bmad-editorial-review-structure,Editorial Review - Structure,ES,Use when doc produced from multiple subprocesses or needs structural improvement.,[path],anytime,,,false,report located with target document,
Core,bmad-review-adversarial-general,Adversarial Review,AR,"Use for quality assurance or before finalizing deliverables. Code Review in other modules runs this automatically, but also useful for document reviews.",[path],anytime,,,false,,
Core,bmad-review-edge-case-hunter,Edge Case Hunter Review,ECH,Use alongside adversarial review for orthogonal coverage — method-driven not attitude-driven.,[path],anytime,,,false,,
Core,bmad-distillator,Distillator,DG,Use when you need token-efficient distillates that preserve all information for downstream LLM consumption.,[path],anytime,,,false,adjacent to source document or specified output_path,distillate markdown file(s)
Core,bmad-customize,BMad Customize,BC,"Use when you want to change how an agent or workflow behaves — add persistent facts, swap templates, insert activation hooks, or customize menus. Scans what's customizable, picks the right scope (agent vs workflow), writes the override to _bmad/custom/, and verifies the merge. No TOML hand-authoring required.",,anytime,,,false,{project-root}/_bmad/custom,TOML override files

Can't render this file because it has a wrong number of fields in line 3.

View File

@ -11,11 +11,6 @@ user_name:
default: "BMad"
result: "{value}"
project_name:
prompt: "What is your project called?"
default: "{directory_name}"
result: "{value}"
communication_language:
prompt: "What language should agents use when chatting with you?"
scope: user

File diff suppressed because it is too large Load Diff

View File

@ -1,294 +0,0 @@
/**
* parseSource() URL parsing tests
*
* Verifies that CustomModuleManager.parseSource() correctly handles Git URLs
* across arbitrary hosts and path shapes (deep paths, nested groups, browse
* links, repo names containing dots, etc.) using host-agnostic rules.
*
* Usage: node test/test-parse-source-urls.js
*/
const { CustomModuleManager } = require('../tools/installer/modules/custom-module-manager');
// ANSI colors
const colors = {
reset: '\u001B[0m',
green: '\u001B[32m',
red: '\u001B[31m',
cyan: '\u001B[36m',
dim: '\u001B[2m',
};
let passed = 0;
let failed = 0;
function assert(condition, testName, errorMessage = '') {
if (condition) {
console.log(`${colors.green}${colors.reset} ${testName}`);
passed++;
} else {
console.log(`${colors.red}${colors.reset} ${testName}`);
if (errorMessage) {
console.log(` ${colors.dim}${errorMessage}${colors.reset}`);
}
failed++;
}
}
const manager = new CustomModuleManager();
// ─── Deep path shapes (4+ segments) ─────────────────────────────────────────
console.log(`\n${colors.cyan}Deep path shapes${colors.reset}\n`);
{
// Hosts that expose the repo at a nested path like /<org>/<project>/<marker>/<repo>.
// The parser must preserve the full path (no stripping of intermediate segments).
const result = manager.parseSource('https://git.example.com/myorg/MyProject/_git/my-module');
assert(result.isValid === true, 'nested-path URL is valid');
assert(result.type === 'url', 'nested-path type is url');
assert(
result.cloneUrl === 'https://git.example.com/myorg/MyProject/_git/my-module',
'nested-path cloneUrl preserves full path',
`Got: ${result.cloneUrl}`,
);
assert(result.subdir === null, 'nested-path URL has no subdir');
assert(
result.cacheKey === 'git.example.com/myorg/MyProject/_git/my-module',
'nested-path cacheKey includes full repo path',
`Got: ${result.cacheKey}`,
);
assert(result.displayName === '_git/my-module', 'nested-path displayName uses last two segments', `Got: ${result.displayName}`);
}
{
const result = manager.parseSource('https://git.example.com/myorg/MyProject/_git/my-module.git');
assert(result.isValid === true, 'nested-path URL with .git suffix is valid');
assert(
result.cloneUrl === 'https://git.example.com/myorg/MyProject/_git/my-module',
'nested-path .git suffix stripped from cloneUrl',
`Got: ${result.cloneUrl}`,
);
}
{
// Browse links that use ?path=/... to point at a subdirectory.
const result = manager.parseSource('https://git.example.com/myorg/MyProject/_git/my-module?path=/path/to/subdir');
assert(result.isValid === true, 'URL with ?path= is valid');
assert(
result.cloneUrl === 'https://git.example.com/myorg/MyProject/_git/my-module',
'?path= cloneUrl excludes subdir',
`Got: ${result.cloneUrl}`,
);
assert(result.subdir === 'path/to/subdir', '?path= subdir correctly extracted', `Got: ${result.subdir}`);
}
// ─── Azure DevOps URLs (Issue #2268) ────────────────────────────────────────
console.log(`\n${colors.cyan}Azure DevOps URLs (Issue #2268)${colors.reset}\n`);
{
// Modern dev.azure.com format — the exact URL from the bug report.
const result = manager.parseSource('https://dev.azure.com/myorg/MyProject/_git/my-module');
assert(result.isValid === true, 'ADO modern URL is valid');
assert(result.type === 'url', 'ADO modern type is url');
assert(
result.cloneUrl === 'https://dev.azure.com/myorg/MyProject/_git/my-module',
'ADO modern cloneUrl preserves full _git path',
`Got: ${result.cloneUrl}`,
);
assert(
result.cacheKey === 'dev.azure.com/myorg/MyProject/_git/my-module',
'ADO modern cacheKey includes full path',
`Got: ${result.cacheKey}`,
);
assert(result.subdir === null, 'ADO modern URL has no subdir');
}
{
// Modern format with .git suffix
const result = manager.parseSource('https://dev.azure.com/myorg/MyProject/_git/my-module.git');
assert(result.isValid === true, 'ADO modern .git suffix is valid');
assert(
result.cloneUrl === 'https://dev.azure.com/myorg/MyProject/_git/my-module',
'ADO modern .git suffix stripped from cloneUrl',
`Got: ${result.cloneUrl}`,
);
}
{
// Modern format with ?path= subdir (browse link)
const result = manager.parseSource('https://dev.azure.com/myorg/MyProject/_git/my-module?path=/src/skills');
assert(result.isValid === true, 'ADO modern ?path= is valid');
assert(
result.cloneUrl === 'https://dev.azure.com/myorg/MyProject/_git/my-module',
'ADO modern ?path= cloneUrl excludes subdir',
`Got: ${result.cloneUrl}`,
);
assert(result.subdir === 'src/skills', 'ADO modern ?path= subdir extracted', `Got: ${result.subdir}`);
}
{
// Legacy visualstudio.com format
const result = manager.parseSource('https://myorg.visualstudio.com/MyProject/_git/my-module');
assert(result.isValid === true, 'ADO legacy URL is valid');
assert(
result.cloneUrl === 'https://myorg.visualstudio.com/MyProject/_git/my-module',
'ADO legacy cloneUrl preserves full path',
`Got: ${result.cloneUrl}`,
);
assert(
result.cacheKey === 'myorg.visualstudio.com/MyProject/_git/my-module',
'ADO legacy cacheKey includes full path',
`Got: ${result.cacheKey}`,
);
}
{
// Legacy format with .git suffix
const result = manager.parseSource('https://myorg.visualstudio.com/MyProject/_git/my-module.git');
assert(result.isValid === true, 'ADO legacy .git suffix is valid');
assert(
result.cloneUrl === 'https://myorg.visualstudio.com/MyProject/_git/my-module',
'ADO legacy .git suffix stripped from cloneUrl',
`Got: ${result.cloneUrl}`,
);
}
{
// Legacy format with ?path= subdir
const result = manager.parseSource('https://myorg.visualstudio.com/MyProject/_git/my-module?path=/src');
assert(result.isValid === true, 'ADO legacy ?path= is valid');
assert(
result.cloneUrl === 'https://myorg.visualstudio.com/MyProject/_git/my-module',
'ADO legacy ?path= cloneUrl excludes subdir',
`Got: ${result.cloneUrl}`,
);
assert(result.subdir === 'src', 'ADO legacy ?path= subdir extracted', `Got: ${result.subdir}`);
}
// ─── Subdomain hosts ────────────────────────────────────────────────────────
console.log(`\n${colors.cyan}Subdomain hosts${colors.reset}\n`);
{
const result = manager.parseSource('https://myorg.example.com/MyProject/_git/my-module');
assert(result.isValid === true, 'subdomain URL is valid');
assert(result.type === 'url', 'subdomain type is url');
assert(
result.cloneUrl === 'https://myorg.example.com/MyProject/_git/my-module',
'subdomain cloneUrl preserves full path',
`Got: ${result.cloneUrl}`,
);
assert(result.subdir === null, 'subdomain URL has no subdir');
assert(
result.cacheKey === 'myorg.example.com/MyProject/_git/my-module',
'subdomain cacheKey includes full repo path',
`Got: ${result.cacheKey}`,
);
}
// ─── Simple owner/repo URLs (regression) ────────────────────────────────────
console.log(`\n${colors.cyan}Simple owner/repo URLs (regression check)${colors.reset}\n`);
{
const result = manager.parseSource('https://github.com/owner/repo');
assert(result.isValid === true, 'GitHub basic URL still valid');
assert(result.cloneUrl === 'https://github.com/owner/repo', 'GitHub cloneUrl unchanged', `Got: ${result.cloneUrl}`);
assert(result.cacheKey === 'github.com/owner/repo', 'GitHub cacheKey unchanged', `Got: ${result.cacheKey}`);
}
{
const result = manager.parseSource('https://github.com/owner/repo/tree/main/subdir');
assert(result.isValid === true, 'GitHub URL with tree path still valid');
assert(result.cloneUrl === 'https://github.com/owner/repo', 'GitHub tree URL cloneUrl correct', `Got: ${result.cloneUrl}`);
assert(result.subdir === 'subdir', 'GitHub tree subdir still extracted', `Got: ${result.subdir}`);
}
{
const result = manager.parseSource('git@github.com:owner/repo.git');
assert(result.isValid === true, 'SSH URL still valid');
assert(result.cloneUrl === 'git@github.com:owner/repo.git', 'SSH cloneUrl unchanged', `Got: ${result.cloneUrl}`);
}
// ─── Generic URL handling (any host, any path depth) ────────────────────────
console.log(`\n${colors.cyan}Generic URL handling${colors.reset}\n`);
{
// GitLab nested groups — the old 2-segment regex would have failed this.
const result = manager.parseSource('https://gitlab.com/group/subgroup/repo');
assert(result.isValid === true, 'GitLab nested-group URL is valid');
assert(
result.cloneUrl === 'https://gitlab.com/group/subgroup/repo',
'GitLab nested-group cloneUrl preserves full path',
`Got: ${result.cloneUrl}`,
);
assert(
result.cacheKey === 'gitlab.com/group/subgroup/repo',
'GitLab nested-group cacheKey includes full path',
`Got: ${result.cacheKey}`,
);
assert(result.displayName === 'subgroup/repo', 'GitLab nested-group displayName uses last two segments', `Got: ${result.displayName}`);
}
{
const result = manager.parseSource('https://gitlab.com/group/subgroup/repo/-/tree/main/src/module');
assert(result.isValid === true, 'GitLab nested-group tree URL is valid');
assert(
result.cloneUrl === 'https://gitlab.com/group/subgroup/repo',
'GitLab nested-group tree cloneUrl excludes subdir',
`Got: ${result.cloneUrl}`,
);
assert(result.subdir === 'src/module', 'GitLab nested-group tree subdir extracted', `Got: ${result.subdir}`);
}
{
// Self-hosted host with a repo name containing dots — the old regex
// explicitly excluded dots from the repo segment.
const result = manager.parseSource('https://git.example.com/owner/my.repo.name');
assert(result.isValid === true, 'repo name with dots is valid');
assert(
result.cloneUrl === 'https://git.example.com/owner/my.repo.name',
'repo name with dots preserved in cloneUrl',
`Got: ${result.cloneUrl}`,
);
assert(result.displayName === 'owner/my.repo.name', 'repo name with dots preserved in displayName', `Got: ${result.displayName}`);
}
{
// Browser URL pointing at a ref with NO trailing subdir must still strip
// the /tree/<ref> segment from the clone URL.
const result = manager.parseSource('https://github.com/owner/repo/tree/main');
assert(result.isValid === true, 'tree URL without subdir is valid');
assert(
result.cloneUrl === 'https://github.com/owner/repo',
'tree URL without subdir strips ref from cloneUrl',
`Got: ${result.cloneUrl}`,
);
assert(result.subdir === null, 'tree URL without subdir yields null subdir', `Got: ${result.subdir}`);
assert(result.displayName === 'owner/repo', 'tree URL without subdir displayName is owner/repo', `Got: ${result.displayName}`);
}
{
// Same shape for GitLab's /-/tree form and Gitea's /src/branch form.
const gitlab = manager.parseSource('https://gitlab.com/group/repo/-/tree/main');
assert(
gitlab.cloneUrl === 'https://gitlab.com/group/repo' && gitlab.subdir === null,
'GitLab /-/tree/<ref> without subdir strips ref',
`Got: ${gitlab.cloneUrl} subdir=${gitlab.subdir}`,
);
const gitea = manager.parseSource('https://gitea.example.com/owner/repo/src/branch/main');
assert(
gitea.cloneUrl === 'https://gitea.example.com/owner/repo' && gitea.subdir === null,
'Gitea /src/branch/<ref> without subdir strips ref',
`Got: ${gitea.cloneUrl} subdir=${gitea.subdir}`,
);
}
// ─── Summary ────────────────────────────────────────────────────────────────
console.log(`\n${colors.cyan}Results: ${passed} passed, ${failed} failed${colors.reset}\n`);
process.exit(failed > 0 ? 1 : 0);

View File

@ -222,6 +222,7 @@ Support assumption: full Agent Skills support. Gemini CLI docs confirm workspace
- [x] Confirm Gemini CLI native skills path is `.gemini/skills/{skill-name}/SKILL.md` (per [geminicli.com/docs/cli/skills](https://geminicli.com/docs/cli/skills/))
- [x] Implement native skills output — target_dir `.gemini/skills`, skill_format true, template_type default (replaces TOML templates)
- [x] Add legacy cleanup for `.gemini/commands` (via `legacy_targets`)
- [x] Test fresh install — skills written to `.gemini/skills/bmad-master/SKILL.md` with correct frontmatter
- [x] Test reinstall/upgrade from legacy TOML command output — legacy dir removed, skills installed
- [x] Confirm no ancestor conflict protection is needed — Gemini CLI uses workspace > user > extension precedence, no ancestor directory inheritance
@ -235,6 +236,7 @@ Support assumption: full Agent Skills support. iFlow docs confirm workspace skil
- [x] Confirm iFlow native skills path is `.iflow/skills/{skill-name}/SKILL.md`
- [x] Implement native skills output — target_dir `.iflow/skills`, skill_format true, template_type default
- [x] Add legacy cleanup for `.iflow/commands` (via `legacy_targets`)
- [x] Test fresh install — skills written to `.iflow/skills/bmad-master/SKILL.md`
- [x] Test legacy cleanup — legacy commands dir removed
- [x] Implement/extend automated tests — 6 assertions in test suite 24
@ -247,6 +249,7 @@ Support assumption: full Agent Skills support. Qwen Code supports workspace skil
- [x] Confirm QwenCoder native skills path is `.qwen/skills/{skill-name}/SKILL.md`
- [x] Implement native skills output — target_dir `.qwen/skills`, skill_format true, template_type default
- [x] Add legacy cleanup for `.qwen/commands` (via `legacy_targets`)
- [x] Test fresh install — skills written to `.qwen/skills/bmad-master/SKILL.md`
- [x] Test legacy cleanup — legacy commands dir removed
- [x] Implement/extend automated tests — 6 assertions in test suite 25
@ -259,6 +262,7 @@ Support assumption: full Agent Skills support. Rovo Dev now supports workspace s
- [x] Confirm Rovo Dev native skills path is `.rovodev/skills/{skill-name}/SKILL.md` (per Atlassian blog)
- [x] Replace 257-line custom `rovodev.js` with config-driven entry in `platform-codes.yaml`
- [x] Add legacy cleanup for `.rovodev/workflows` (via `legacy_targets`) and BMAD entries in `prompts.yml` (via `cleanupRovoDevPrompts()` in `_config-driven.js`)
- [x] Test fresh install — skills written to `.rovodev/skills/bmad-master/SKILL.md`
- [x] Test legacy cleanup — legacy workflows dir removed, `prompts.yml` BMAD entries stripped while preserving user entries
- [x] Implement/extend automated tests — 8 assertions in test suite 26

View File

@ -23,10 +23,13 @@ checkForUpdate().catch(() => {
async function checkForUpdate() {
try {
// Prereleases (e.g. 6.5.1-next.0) live on the `next` dist-tag; stable
// releases live on `latest`. semver.prerelease() returns null for stable,
// so this correctly routes pre-1.0-next/rc/etc. without string matching.
const tag = semver.prerelease(packageJson.version) ? 'next' : 'latest';
// For beta versions, check the beta tag; otherwise check latest
const isBeta =
packageJson.version.includes('Beta') ||
packageJson.version.includes('beta') ||
packageJson.version.includes('alpha') ||
packageJson.version.includes('rc');
const tag = isBeta ? 'beta' : 'latest';
const result = execSync(`npm view ${packageName}@${tag} version`, {
encoding: 'utf8',

View File

@ -15,18 +15,7 @@ module.exports = {
['--modules <modules>', 'Comma-separated list of module IDs to install (e.g., "bmm,bmb")'],
[
'--tools <tools>',
'Comma-separated list of tool/IDE IDs to configure (e.g., "claude-code,cursor"). Required for fresh non-interactive (--yes) installs. Run with --list-tools to see all valid IDs.',
],
['--list-tools', 'Print all supported tool/IDE IDs (with target directories) and exit.'],
[
'--set <spec>',
'Set a module config option non-interactively. Spec format: <module>.<key>=<value> (e.g. bmm.project_knowledge=research). Repeatable. Run --list-options to see available keys.',
(value, prev) => [...(prev || []), value],
[],
],
[
'--list-options [module]',
'List available --set keys for all locally-known official modules, or for a single module by code, then exit.',
'Comma-separated list of tool/IDE IDs to configure (e.g., "claude-code,cursor"). Use "none" to skip tool configuration.',
],
['--action <type>', 'Action type for existing installations: install, update, or quick-update'],
['--user-name <name>', 'Name for agents to use (default: system username)'],
@ -51,49 +40,12 @@ module.exports = {
],
action: async (options) => {
try {
if (options.listTools) {
const { formatPlatformList } = require('../ide/platform-codes');
process.stdout.write((await formatPlatformList()) + '\n');
process.exit(0);
}
if (options.listOptions !== undefined) {
const { formatOptionsList } = require('../list-options');
const moduleArg = options.listOptions === true ? null : options.listOptions;
const { text, ok } = await formatOptionsList(moduleArg);
const stream = ok ? process.stdout : process.stderr;
// process.exit() forces immediate termination and can truncate the
// buffered write when stdout/stderr is piped or captured by CI. Wait
// for the write to flush, then set process.exitCode and return so the
// event loop drains naturally. Non-zero exit when a single-module
// lookup misses so a CI typo like `--list-options bmn` doesn't look
// successful in scripts.
await new Promise((resolve, reject) => {
stream.write(text + '\n', (error) => (error ? reject(error) : resolve()));
});
process.exitCode = ok ? 0 : 1;
return;
}
// Set debug flag as environment variable for all components
if (options.debug) {
process.env.BMAD_DEBUG_MANIFEST = 'true';
await prompts.log.info('Debug mode enabled');
}
// Validate --set syntax up-front so malformed entries fail fast,
// before we touch the network or filesystem. Parsed entries are
// re-derived inside ui.js where overrides are seeded.
if (options.set && options.set.length > 0) {
const { parseSetEntries } = require('../set-overrides');
try {
parseSetEntries(options.set);
} catch (error) {
await prompts.log.error(error.message);
process.exit(1);
}
}
const config = await ui.promptInstall(options);
// Handle cancel
@ -102,13 +54,8 @@ module.exports = {
process.exit(0);
}
// Handle quick update separately. --set is a post-install TOML patch so
// it works the same way for quick-update as for a regular install — the
// installer runs, then `applySetOverrides` patches the central config
// files. Pass the parsed overrides through.
// Handle quick update separately
if (config.actionType === 'quick-update') {
const { parseSetEntries } = require('../set-overrides');
config.setOverrides = parseSetEntries(options.set || []);
const result = await installer.quickUpdate(config);
await prompts.log.success('Quick update complete!');
await prompts.log.info(`Updated ${result.moduleCount} modules with preserved settings (${result.modules.join(', ')})`);
@ -134,7 +81,7 @@ module.exports = {
} else {
await prompts.log.error(`Installation failed: ${error.message}`);
}
if (error.stack && !error.expected) {
if (error.stack) {
await prompts.log.message(error.stack);
}
} catch {

View File

@ -3,19 +3,7 @@
* User input comes from either UI answers or headless CLI flags.
*/
class Config {
constructor({
directory,
modules,
ides,
skipPrompts,
verbose,
actionType,
coreConfig,
moduleConfigs,
quickUpdate,
channelOptions,
setOverrides,
}) {
constructor({ directory, modules, ides, skipPrompts, verbose, actionType, coreConfig, moduleConfigs, quickUpdate, channelOptions }) {
this.directory = directory;
this.modules = Object.freeze([...modules]);
this.ides = Object.freeze([...ides]);
@ -27,11 +15,6 @@ class Config {
this._quickUpdate = quickUpdate;
// channelOptions carry a Map + Set; don't deep-freeze.
this.channelOptions = channelOptions || null;
// Parsed `--set <module>.<key>=<value>` overrides, applied as a TOML
// patch AFTER the install finishes. Shape: { moduleCode: { key: value } }.
// Intentionally NOT integrated with the prompt/template/schema flow; see
// `tools/installer/set-overrides.js` for the rationale and tradeoffs.
this.setOverrides = setOverrides || {};
Object.freeze(this);
}
@ -57,7 +40,6 @@ class Config {
moduleConfigs: userInput.moduleConfigs || null,
quickUpdate: userInput._quickUpdate || false,
channelOptions: userInput.channelOptions || null,
setOverrides: userInput.setOverrides || {},
});
}

View File

@ -12,10 +12,8 @@ const { BMAD_FOLDER_NAME } = require('../ide/shared/path-utils');
const { InstallPaths } = require('./install-paths');
const { ExternalModuleManager } = require('../modules/external-manager');
const { resolveModuleVersion } = require('../modules/version-resolver');
const { MODULE_HELP_CSV_HEADER } = require('../modules/module-help-schema');
const { ExistingInstall } = require('./existing-install');
const { warnPreNativeSkillsLegacy } = require('./legacy-warnings');
class Installer {
constructor() {
@ -43,16 +41,6 @@ class Installer {
const officialModules = await OfficialModules.build(config, paths);
const existingInstall = await ExistingInstall.detect(paths.bmadDir);
try {
await warnPreNativeSkillsLegacy({
projectRoot: paths.projectRoot,
existingVersion: existingInstall.installed ? existingInstall.version : null,
});
} catch (error) {
// Legacy-dir scan is informational; never let it abort install.
await prompts.log.warn(`Warning: Could not check for legacy BMAD entries: ${error.message}`);
}
if (existingInstall.installed) {
await this._removeDeselectedModules(existingInstall, config, paths);
updateState = await this._prepareUpdateState(paths, config, existingInstall, officialModules);
@ -195,16 +183,15 @@ class Installer {
if (toRemove.length === 0) return;
// Pass the newly-selected list as remainingIdes so cleanupByList skips
// target_dir wipes for IDEs whose directory is still owned by a peer
// (e.g. removing 'cursor' while 'gemini' remains — both share .agents/skills).
const results = await this.ideManager.cleanupByList(paths.projectRoot, toRemove, {
remainingIdes: [...newlySelected],
});
for (const result of results || []) {
if (result && result.success === false) {
await prompts.log.warn(`Warning: Failed to remove ${result.ide}: ${result.error || 'unknown error'}`);
await this.ideManager.ensureInitialized();
for (const ide of toRemove) {
try {
const handler = this.ideManager.handlers.get(ide);
if (handler) {
await handler.cleanup(paths.projectRoot);
}
} catch (error) {
await prompts.log.warn(`Warning: Failed to remove ${ide}: ${error.message}`);
}
}
}
@ -311,19 +298,6 @@ class Installer {
moduleConfigs,
});
// Apply post-install --set TOML patches. Runs after writeCentralConfig
// (inside generateManifests above) so the patch operates on the
// freshly written `_bmad/config.toml` / `_bmad/config.user.toml`.
// See `tools/installer/set-overrides.js` for routing rules.
if (config.setOverrides && Object.keys(config.setOverrides).length > 0) {
const { applySetOverrides } = require('../set-overrides');
const applied = await applySetOverrides(config.setOverrides, paths.bmadDir);
if (applied.length > 0) {
const summary = applied.map((a) => `${a.module}.${a.key}${a.file}`).join(', ');
await prompts.log.info(`Applied --set overrides: ${summary}`);
}
}
message('Generating help catalog...');
await this.mergeModuleHelpCatalogs(paths.bmadDir, manifestGen.agents);
addResult('Help catalog', 'ok');
@ -368,14 +342,13 @@ class Installer {
return;
}
const setupResults = await this.ideManager.setupBatch(validIdes, paths.projectRoot, paths.bmadDir, {
selectedModules: allModules || [],
verbose: config.verbose,
previousSkillIds,
});
for (const ide of validIdes) {
const setupResult = await this.ideManager.setup(ide, paths.projectRoot, paths.bmadDir, {
selectedModules: allModules || [],
verbose: config.verbose,
previousSkillIds,
});
for (const setupResult of setupResults) {
const ide = setupResult.ide;
if (setupResult.success) {
addResult(ide, 'ok', setupResult.detail || '');
} else {
@ -937,15 +910,29 @@ class Installer {
/**
* Merge all module-help.csv files into a single bmad-help.csv.
* Scans all installed modules for module-help.csv and merges them.
* Output preserves the source schema verbatim see schema below.
* Enriches agent info from the in-memory agent list produced by ManifestGenerator.
* Output is written to _bmad/_config/bmad-help.csv.
* @param {string} bmadDir - BMAD installation directory
* @param {Array<Object>} _agentEntries - Unused; retained for call-site compatibility
* @param {Array<Object>} agentEntries - Agents collected from module.yaml (code, name, title, icon, module, ...)
*/
async mergeModuleHelpCatalogs(bmadDir, _agentEntries = []) {
async mergeModuleHelpCatalogs(bmadDir, agentEntries = []) {
const allRows = [];
const headerRow = MODULE_HELP_CSV_HEADER;
const COLUMN_COUNT = 13;
const PHASE_INDEX = 7;
const headerRow =
'module,phase,name,code,sequence,workflow-file,command,required,agent-name,agent-command,agent-display-name,agent-title,options,description,output-location,outputs';
// Build agent lookup from the in-memory list (agent code → command + display fields).
const agentInfo = new Map();
for (const agent of agentEntries) {
if (!agent || !agent.code) continue;
const agentCommand = agent.module ? `bmad:${agent.module}:agent:${agent.code}` : `bmad:agent:${agent.code}`;
const displayName = agent.name || agent.code;
const titleCombined = agent.icon && agent.title ? `${agent.icon} ${agent.title}` : agent.title || agent.code;
agentInfo.set(agent.code, {
command: agentCommand,
displayName,
title: titleCombined,
});
}
// Get all installed module directories
const entries = await fs.readdir(bmadDir, { withFileTypes: true });
@ -976,37 +963,72 @@ class Installer {
const content = await fs.readFile(helpFilePath, 'utf8');
const lines = content.split('\n').filter((line) => line.trim() && !line.startsWith('#'));
let headerWarned = false;
for (const line of lines) {
// Header row: warn on drift from canonical schema, then skip.
// Data rows are loaded positionally regardless, so the warning
// is advisory — the maintainer should rename their columns.
// Skip header row
if (line.startsWith('module,')) {
if (!headerWarned && line.trim() !== headerRow) {
await prompts.log.warn(
` ${moduleName}/module-help.csv header does not match canonical schema. ` +
`Expected: ${headerRow} | Found: ${line.trim()} | Data loaded positionally.`,
);
headerWarned = true;
}
continue;
}
// Parse the line - handle quoted fields with commas
const columns = this.parseCSVLine(line);
if (columns.length < COLUMN_COUNT - 1) continue;
if (columns.length >= 12) {
// Map old schema to new schema
// Old: module,phase,name,code,sequence,workflow-file,command,required,agent,options,description,output-location,outputs
// New: module,phase,name,code,sequence,workflow-file,command,required,agent-name,agent-command,agent-display-name,agent-title,options,description,output-location,outputs
// Pad short rows; truncate over-long rows
const padded = columns.slice(0, COLUMN_COUNT);
while (padded.length < COLUMN_COUNT) padded.push('');
const [
module,
phase,
name,
code,
sequence,
workflowFile,
command,
required,
agentName,
options,
description,
outputLocation,
outputs,
] = columns;
// If module column is empty, fill with this module's name
// (core stays empty so its rows render as universal tools)
if ((!padded[0] || padded[0].trim() === '') && moduleName !== 'core') {
padded[0] = moduleName;
// Pass through _meta rows as-is (module metadata, not a skill)
if (phase === '_meta') {
const finalModule = (!module || module.trim() === '') && moduleName !== 'core' ? moduleName : module || '';
const metaRow = [finalModule, '_meta', '', '', '', '', '', 'false', '', '', '', '', '', '', outputLocation || '', ''];
allRows.push(metaRow.map((c) => this.escapeCSVField(c)).join(','));
continue;
}
// If module column is empty, set it to this module's name (except for core which stays empty for universal tools)
const finalModule = (!module || module.trim() === '') && moduleName !== 'core' ? moduleName : module || '';
// Lookup agent info
const cleanAgentName = agentName ? agentName.trim() : '';
const agentData = agentInfo.get(cleanAgentName) || { command: '', displayName: '', title: '' };
// Build new row with agent info
const newRow = [
finalModule,
phase || '',
name || '',
code || '',
sequence || '',
workflowFile || '',
command || '',
required || 'false',
cleanAgentName,
agentData.command,
agentData.displayName,
agentData.title,
options || '',
description || '',
outputLocation || '',
outputs || '',
];
allRows.push(newRow.map((c) => this.escapeCSVField(c)).join(','));
}
allRows.push(padded.map((c) => this.escapeCSVField(c)).join(','));
}
if (process.env.BMAD_VERBOSE_INSTALL === 'true') {
@ -1018,34 +1040,44 @@ class Installer {
}
}
// Sort by module, then phase. Stable sort preserves authored order within a phase.
const decorated = allRows.map((row, index) => ({ row, index, cols: this.parseCSVLine(row) }));
decorated.sort((a, b) => {
const moduleA = (a.cols[0] || '').toLowerCase();
const moduleB = (b.cols[0] || '').toLowerCase();
if (moduleA !== moduleB) return moduleA.localeCompare(moduleB);
// Sort by module, then phase, then sequence
allRows.sort((a, b) => {
const colsA = this.parseCSVLine(a);
const colsB = this.parseCSVLine(b);
const phaseA = a.cols[PHASE_INDEX] || '';
const phaseB = b.cols[PHASE_INDEX] || '';
if (phaseA !== phaseB) return phaseA.localeCompare(phaseB);
// Module comparison (empty module/universal tools come first)
const moduleA = (colsA[0] || '').toLowerCase();
const moduleB = (colsB[0] || '').toLowerCase();
if (moduleA !== moduleB) {
return moduleA.localeCompare(moduleB);
}
return a.index - b.index;
// Phase comparison
const phaseA = colsA[1] || '';
const phaseB = colsB[1] || '';
if (phaseA !== phaseB) {
return phaseA.localeCompare(phaseB);
}
// Sequence comparison
const seqA = parseInt(colsA[4] || '0', 10);
const seqB = parseInt(colsB[4] || '0', 10);
return seqA - seqB;
});
const sortedRows = decorated.map((d) => d.row);
// Write merged catalog
const outputDir = path.join(bmadDir, '_config');
await fs.ensureDir(outputDir);
const outputPath = path.join(outputDir, 'bmad-help.csv');
const mergedContent = [headerRow, ...sortedRows].join('\n');
const mergedContent = [headerRow, ...allRows].join('\n');
await fs.writeFile(outputPath, mergedContent, 'utf8');
// Track the installed file
this.installedFiles.add(outputPath);
if (process.env.BMAD_VERBOSE_INSTALL === 'true') {
await prompts.log.message(` Generated bmad-help.csv: ${sortedRows.length} workflows`);
await prompts.log.message(` Generated bmad-help.csv: ${allRows.length} workflows`);
}
}
@ -1307,10 +1339,6 @@ class Installer {
ides: configuredIdes,
coreConfig: quickModules.collectedConfig.core,
moduleConfigs: quickModules.collectedConfig,
// Forward `--set` overrides so the post-install patch step
// (`applySetOverrides`) runs at the end of quick-update too. The
// installer.install path applies them after writeCentralConfig.
setOverrides: config.setOverrides || {},
actionType: 'install',
_quickUpdate: true,
_preserveModules: skippedModules,

View File

@ -1,151 +0,0 @@
const os = require('node:os');
const path = require('node:path');
const semver = require('semver');
const fs = require('../fs-native');
const prompts = require('../prompts');
const { BMAD_FOLDER_NAME } = require('../ide/shared/path-utils');
const { getInstalledCanonicalIds, isBmadOwnedEntry } = require('../ide/shared/installed-skills');
const MIN_NATIVE_SKILLS_VERSION = '6.1.0';
// Pre-v6.1.0 paths: BMAD used to install commands/workflows/etc in tool-specific dirs.
// In v6.1.0 BMAD switched to native SKILL.md format.
const LEGACY_COMMAND_PATHS = [
'.agent/workflows',
'.augment/commands',
'.claude/commands',
'.clinerules/workflows',
'.codex/prompts',
'~/.codex/prompts',
'.codebuddy/commands',
'.crush/commands',
'.cursor/commands',
'.gemini/commands',
'.github/agents',
'.github/prompts',
'.iflow/commands',
'.kilocode/workflows',
'.kiro/steering',
'.opencode/agents',
'.opencode/commands',
'.opencode/agent',
'.opencode/command',
'.qwen/commands',
'.roo/commands',
'.rovodev/workflows',
'.trae/rules',
'.windsurf/workflows',
];
// Skill paths that moved to the cross-tool .agents/skills/ standard.
// Users upgrading from a prior install may have stale BMAD skills here that
// the AI tool will load alongside the new ones, causing duplicates.
const LEGACY_SKILL_PATHS = [
'.augment/skills',
'~/.augment/skills',
'.codex/skills',
'.crush/skills',
'.cursor/skills',
'~/.cursor/skills',
'.gemini/skills',
'~/.gemini/skills',
'.github/skills',
'~/.github/skills',
'.kilocode/skills',
'.kimi/skills',
'~/.kimi/skills',
'.opencode/skills',
'~/.opencode/skills',
'.pi/skills',
'~/.pi/skills',
'.roo/skills',
'~/.roo/skills',
'.rovodev/skills',
'~/.rovodev/skills',
'.windsurf/skills',
'~/.windsurf/skills',
'~/.codeium/windsurf/skills',
];
const LEGACY_PATHS = [...LEGACY_COMMAND_PATHS, ...LEGACY_SKILL_PATHS];
function expandPath(p) {
if (p === '~') return os.homedir();
if (p.startsWith('~/')) return path.join(os.homedir(), p.slice(2));
return p;
}
function resolveLegacyPath(projectRoot, p) {
if (path.isAbsolute(p) || p.startsWith('~')) return expandPath(p);
return path.join(projectRoot, p);
}
async function findStaleLegacyDirs(projectRoot) {
const bmadDir = path.join(projectRoot, BMAD_FOLDER_NAME);
const canonicalIds = await getInstalledCanonicalIds(bmadDir);
const findings = [];
for (const legacyPath of LEGACY_PATHS) {
const resolved = resolveLegacyPath(projectRoot, legacyPath);
if (!(await fs.pathExists(resolved))) continue;
try {
const entries = await fs.readdir(resolved);
const bmadEntries = entries.filter((e) => isBmadOwnedEntry(e, canonicalIds));
if (bmadEntries.length > 0) {
findings.push({ path: resolved, displayPath: legacyPath, count: bmadEntries.length, entries: bmadEntries });
}
} catch {
// Unreadable dir — skip
}
}
return findings;
}
function isPreNativeSkillsVersion(version) {
if (!version) return false;
const coerced = semver.valid(version) || semver.valid(semver.coerce(version));
if (!coerced) return false;
return semver.lt(coerced, MIN_NATIVE_SKILLS_VERSION);
}
async function warnPreNativeSkillsLegacy({ projectRoot, existingVersion } = {}) {
const versionTriggered = isPreNativeSkillsVersion(existingVersion);
const staleDirs = await findStaleLegacyDirs(projectRoot);
if (!versionTriggered && staleDirs.length === 0) return;
if (versionTriggered) {
await prompts.log.warn(
`Detected previous BMAD install v${existingVersion} (pre-${MIN_NATIVE_SKILLS_VERSION}). ` +
`BMAD switched to native skills format in v${MIN_NATIVE_SKILLS_VERSION}; old command/workflow directories from your prior install may still be present.`,
);
}
if (staleDirs.length > 0) {
await prompts.log.warn(
`Found stale BMAD entries in ${staleDirs.length} legacy location(s) that the new installer no longer manages. ` +
`Your AI tool may load these alongside the new skills, causing duplicates. Remove them manually:`,
);
for (const finding of staleDirs) {
// Print each entry by exact name. A `bmad*` glob would (a) miss
// custom-module skills the canonicalId scan now picks up, and
// (b) match bmad-os-* utility skills the user should keep.
const entries = finding.entries || [];
for (const entry of entries) {
await prompts.log.message(` rm -rf "${path.join(finding.path, entry)}"`);
}
}
} else if (versionTriggered) {
await prompts.log.message(
' No stale legacy directories detected, but if your AI tool shows duplicate BMAD commands after install, check for old `bmad-*` entries in tool-specific dirs (e.g. .claude/commands, .cursor/commands).',
);
}
}
module.exports = {
warnPreNativeSkillsLegacy,
findStaleLegacyDirs,
isPreNativeSkillsVersion,
LEGACY_PATHS,
MIN_NATIVE_SKILLS_VERSION,
};

View File

@ -435,9 +435,6 @@ class ManifestGenerator {
// this means user-scoped keys (e.g. user_name) could mis-file into the
// team config, so the operator should notice.
const scopeByModuleKey = {};
// Maps installer moduleName (may be full display name) → module code field
// from module.yaml, so TOML sections use [modules.<code>] not [modules.<name>].
const codeByModuleName = {};
for (const moduleName of this.updatedModules) {
const moduleYamlPath = await resolveInstalledModuleYaml(moduleName);
if (!moduleYamlPath) {
@ -450,7 +447,6 @@ class ManifestGenerator {
try {
const parsed = yaml.parse(await fs.readFile(moduleYamlPath, 'utf8'));
if (!parsed || typeof parsed !== 'object') continue;
if (parsed.code) codeByModuleName[moduleName] = parsed.code;
scopeByModuleKey[moduleName] = {};
for (const [key, value] of Object.entries(parsed)) {
if (value && typeof value === 'object' && 'prompt' in value) {
@ -549,9 +545,6 @@ class ManifestGenerator {
if (moduleName === 'core') continue;
const cfg = moduleConfigs[moduleName];
if (!cfg || Object.keys(cfg).length === 0) continue;
// Use the module's code field from module.yaml as the TOML key so the
// section is [modules.mdo] not [modules.MDO: Maxio DevOps Operations].
const sectionKey = codeByModuleName[moduleName] || moduleName;
// Only filter out spread-from-core pollution when we actually know
// this module's prompt schema. For external/marketplace modules whose
// module.yaml isn't in the src tree, fall through as all-team so we
@ -559,14 +552,14 @@ class ManifestGenerator {
const haveSchema = Object.keys(scopeByModuleKey[moduleName] || {}).length > 0;
const { team: modTeam, user: modUser } = partition(moduleName, cfg, haveSchema);
if (Object.keys(modTeam).length > 0) {
teamLines.push(`[modules.${sectionKey}]`);
teamLines.push(`[modules.${moduleName}]`);
for (const [key, value] of Object.entries(modTeam)) {
teamLines.push(`${key} = ${formatTomlValue(value)}`);
}
teamLines.push('');
}
if (Object.keys(modUser).length > 0) {
userLines.push(`[modules.${sectionKey}]`);
userLines.push(`[modules.${moduleName}]`);
for (const [key, value] of Object.entries(modUser)) {
userLines.push(`${key} = ${formatTomlValue(value)}`);
}

View File

@ -1,20 +1,9 @@
const path = require('node:path');
const https = require('node:https');
const { execFile } = require('node:child_process');
const { promisify } = require('node:util');
const fs = require('../fs-native');
const crypto = require('node:crypto');
const { resolveModuleVersion } = require('../modules/version-resolver');
const prompts = require('../prompts');
const execFileAsync = promisify(execFile);
const NPM_LOOKUP_TIMEOUT_MS = 10_000;
const NPM_PACKAGE_NAME_PATTERN = /^(?:@[a-z0-9][a-z0-9._~-]*\/)?[a-z0-9][a-z0-9._~-]*$/;
function isValidNpmPackageName(packageName) {
return typeof packageName === 'string' && NPM_PACKAGE_NAME_PATTERN.test(packageName);
}
class Manifest {
/**
* Create a new manifest
@ -373,40 +362,35 @@ class Manifest {
* @returns {string|null} Latest version or null
*/
async fetchNpmVersion(packageName) {
if (!isValidNpmPackageName(packageName)) {
return null;
}
try {
const https = require('node:https');
const { execSync } = require('node:child_process');
// Try using npm view first (more reliable)
try {
const { stdout } = await execFileAsync('npm', ['view', packageName, 'version'], {
const result = execSync(`npm view ${packageName} version`, {
encoding: 'utf8',
timeout: NPM_LOOKUP_TIMEOUT_MS,
stdio: 'pipe',
timeout: 10_000,
});
return stdout.trim();
return result.trim();
} catch {
// Fallback to npm registry API
return new Promise((resolve) => {
const request = https.get(`https://registry.npmjs.org/${encodeURIComponent(packageName)}`, (res) => {
let data = '';
res.on('data', (chunk) => (data += chunk));
res.on('end', () => {
try {
const pkg = JSON.parse(data);
resolve(pkg['dist-tags']?.latest || pkg.version || null);
} catch {
resolve(null);
}
});
});
request.setTimeout(NPM_LOOKUP_TIMEOUT_MS, () => {
request.destroy();
resolve(null);
});
request.on('error', () => resolve(null));
return new Promise((resolve, reject) => {
https
.get(`https://registry.npmjs.org/${packageName}`, (res) => {
let data = '';
res.on('data', (chunk) => (data += chunk));
res.on('end', () => {
try {
const pkg = JSON.parse(data);
resolve(pkg['dist-tags']?.latest || pkg.version || null);
} catch {
resolve(null);
}
});
})
.on('error', () => resolve(null));
});
}
} catch {

View File

@ -1,129 +1,10 @@
const os = require('node:os');
const path = require('node:path');
const fs = require('../fs-native');
const yaml = require('yaml');
const prompts = require('../prompts');
const csv = require('csv-parse/sync');
const { BMAD_FOLDER_NAME } = require('./shared/path-utils');
const { getInstalledCanonicalIds, isBmadOwnedEntry } = require('./shared/installed-skills');
// Reserved OpenCode slash commands. A skill whose canonicalId collides with
// one of these is skipped during command-pointer generation so it doesn't
// shadow a built-in.
const RESERVED_OPENCODE_COMMANDS = new Set([
'review',
'commit',
'init',
'help',
'skills',
'fast',
'compact',
'clear',
'undo',
'redo',
'edit',
'editor',
'exit',
'quit',
'theme',
'config',
'model',
'session',
]);
// Wrap a description for safe insertion into single-line YAML frontmatter.
// Leaves plain values untouched; double-quotes (and escapes) anything that
// could break YAML parsing or span multiple lines.
function yamlSafeSingleLine(value) {
const collapsed = String(value)
.replaceAll(/[\r\n]+/g, ' ')
.trim();
const needsQuoting = /[:#'"\\]/.test(collapsed) || /^[!&*?|>%@`[{]/.test(collapsed);
if (!needsQuoting) return collapsed;
const escaped = collapsed.replaceAll('\\', '\\\\').replaceAll('"', String.raw`\"`);
return `"${escaped}"`;
}
// Validate that a canonicalId is a safe basename — no path separators, no
// parent-dir traversal, no leading dots, only the character set we expect.
// Defense-in-depth: the manifest is trusted today, but the value flows
// directly into a file path and a malformed entry should not write outside
// the commands directory.
function isSafeCanonicalId(value) {
return typeof value === 'string' && /^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(value) && !value.includes('..');
}
// Default body template for command pointer files. Used when a platform's
// installer config doesn't override `commands_body_template`. Matches
// OpenCode's native `@skills/<id>` skill-reference syntax.
const DEFAULT_COMMANDS_BODY_TEMPLATE = '@skills/{canonicalId}';
// Is this skill a persona agent (vs. a workflow/tool/standalone skill)?
// Used by platforms that surface only persona agents (e.g. Copilot's Custom
// Agents picker). Signal: the skill's source `customize.toml` has an
// `[agent]` section. This is the actual configuration source of truth —
// every BMAD persona is configured via [agent] in its customize.toml,
// every workflow uses [workflow], every standalone skill has no
// customize.toml at all. Verified against the full installed manifest:
// catches exactly the 20 description-confirmed personas across BMM, CIS,
// GDS, WDS, TEA, and correctly excludes meta-skills like
// `bmad-agent-builder` (a skill-builder workflow whose canonical id
// contains `-agent-` but which has no [agent] section because it isn't a
// persona itself).
//
// Reading the source toml — at install time the source skill directory
// (resolved from manifest record.path) still exists; cleanup runs later
// in the install flow.
async function isAgentSkill(record, bmadDir) {
if (!record?.path || !bmadDir) return false;
const bmadFolderName = path.basename(bmadDir);
const bmadPrefix = bmadFolderName + '/';
const relativePath = record.path.startsWith(bmadPrefix) ? record.path.slice(bmadPrefix.length) : record.path;
const tomlPath = path.join(bmadDir, path.dirname(relativePath), 'customize.toml');
if (!(await fs.pathExists(tomlPath))) return false;
try {
const content = await fs.readFile(tomlPath, 'utf8');
return /^\[agent\]/m.test(content);
} catch {
return false;
}
}
// Resolve placeholders in a body template. Supported placeholders:
// {canonicalId} — the skill's canonical id
// {target_dir} — the platform's skill install directory (e.g. .agents/skills)
// {project-root} — left as a literal placeholder for the model/tool to expand
// at runtime; consistent with PR #1769's templates.
function expandBodyTemplate(template, { canonicalId, targetDir }) {
return template.replaceAll('{canonicalId}', canonicalId).replaceAll('{target_dir}', targetDir);
}
// The exact body the installer would generate for a given description and
// canonicalId, given the platform's body template. Centralised so both the
// write and the freshness-check paths agree on the canonical form.
function buildCommandPointerBody(description, canonicalId, { template, targetDir }) {
const bodyText = expandBodyTemplate(template, { canonicalId, targetDir });
return `---\ndescription: ${yamlSafeSingleLine(description)}\n---\n\n${bodyText}\n`;
}
// Heuristic: does an existing pointer file look like our generator's output
// (and therefore safe to refresh) versus a user-modified file (which we
// preserve)? We check the body shape rather than full equality so that
// description-only edits in the manifest can propagate without trampling
// hand edits to the body.
function looksLikeGeneratorOutput(content, canonicalId, { template, targetDir }) {
if (typeof content !== 'string') return false;
const trimmed = content.trim();
const expectedTail = expandBodyTemplate(template, { canonicalId, targetDir }).trim();
// Must end with the exact body our generator writes (post-expansion).
if (!trimmed.endsWith(expectedTail)) return false;
// Must start with frontmatter containing exactly one description: line.
const fmMatch = trimmed.match(/^---\n([\S\s]*?)\n---\n/);
if (!fmMatch) return false;
const fmLines = fmMatch[1].split('\n').filter((l) => l.length > 0);
if (fmLines.length !== 1) return false;
if (!fmLines[0].startsWith('description:')) return false;
return true;
}
/**
* Config-driven IDE setup handler
@ -135,7 +16,7 @@ function looksLikeGeneratorOutput(content, canonicalId, { template, targetDir })
* Features:
* - Config-driven from platform-codes.yaml
* - Verbatim skill installation from skill-manifest.csv
* - IDE-specific marker removal (copilot-instructions, kilo modes, rovodev prompts)
* - Legacy directory cleanup and IDE-specific marker removal
*/
class ConfigDrivenIdeSetup {
constructor(platformCode, platformConfig) {
@ -163,20 +44,16 @@ class ConfigDrivenIdeSetup {
async detect(projectDir) {
if (!this.configDir) return false;
const root = projectDir || process.cwd();
const dir = path.join(root, this.configDir);
if (!(await fs.pathExists(dir))) return false;
let entries;
try {
entries = await fs.readdir(dir);
} catch {
return false;
const dir = path.join(projectDir || process.cwd(), this.configDir);
if (await fs.pathExists(dir)) {
try {
const entries = await fs.readdir(dir);
return entries.some((e) => typeof e === 'string' && e.startsWith('bmad'));
} catch {
return false;
}
}
const bmadDir = await this._findBmadDir(root);
const canonicalIds = await getInstalledCanonicalIds(bmadDir);
return entries.some((e) => isBmadOwnedEntry(e, canonicalIds));
return false;
}
/**
@ -215,18 +92,6 @@ class ConfigDrivenIdeSetup {
return { success: false, reason: 'no-config' };
}
// When a peer platform in the same install batch owns this target_dir,
// skip the skill write — the peer has already populated it. Command
// pointers, however, write to a separate per-IDE directory and must
// still be generated for this IDE; they are not deduped across peers.
if (options.skipTarget) {
const results = { skills: 0, sharedTargetHandledByPeer: true };
if (this.installerConfig.commands_target_dir) {
results.commands = await this.installCommandPointers(projectDir, bmadDir, this.installerConfig, options);
}
return { success: true, results };
}
if (this.installerConfig.target_dir) {
return this.installToTarget(projectDir, bmadDir, this.installerConfig, options);
}
@ -253,157 +118,11 @@ class ConfigDrivenIdeSetup {
results.skills = await this.installVerbatimSkills(projectDir, bmadDir, targetPath, config);
results.skillDirectories = this.skillWriteTracker.size;
if (config.commands_target_dir) {
results.commands = await this.installCommandPointers(projectDir, bmadDir, config, options);
}
await this.printSummary(results, target_dir, options);
this.skillWriteTracker = null;
return { success: true, results };
}
/**
* Generate per-skill command pointer files for IDEs that surface commands
* separately from skills (e.g. OpenCode's `.opencode/commands/<name>.md`).
*
* Each pointer is a tiny markdown file whose body is `@skills/<canonicalId>`
* so invoking `/<canonicalId>` routes the user straight to the skill instead
* of forcing them through a `/skills` menu.
*
* Skips:
* - Names that collide with reserved built-in slash commands.
* - canonicalIds that aren't safe basename-only identifiers (defense
* against path traversal even though the manifest is currently trusted).
* - Existing files whose body looks user-modified (preserves hand edits);
* pointer files matching the generator pattern get overwritten so that
* description changes in skill-manifest.csv propagate on re-install.
*
* Per-file write failures are recorded and reported but do not abort the
* rest of the install pointer files are a non-essential adjunct to the
* skill copy that already succeeded.
*
* @param {string} projectDir
* @param {string} bmadDir
* @param {Object} config - Installer config; reads commands_target_dir.
* @param {Object} options - Setup options. forceCommands overwrites existing
* files unconditionally (including hand-modified ones).
* @returns {Promise<Object>} { created, updated, skippedExisting, skippedCollision, skippedInvalidId, writeFailures, fallbackDescription }
*/
async installCommandPointers(projectDir, bmadDir, config, options = {}) {
const result = {
created: 0,
updated: 0,
skippedExisting: 0,
skippedCollision: 0,
skippedInvalidId: 0,
skippedFiltered: 0,
writeFailures: 0,
fallbackDescription: 0,
};
const csvPath = path.join(bmadDir, '_config', 'skill-manifest.csv');
if (!(await fs.pathExists(csvPath))) return result;
const commandsPath = path.join(projectDir, config.commands_target_dir);
await fs.ensureDir(commandsPath);
// Per-platform pointer-file shape, all overrideable in platform-codes.yaml.
const extension = config.commands_extension || '.md';
const template = config.commands_body_template || DEFAULT_COMMANDS_BODY_TEMPLATE;
const targetDir = config.target_dir;
const filter = config.commands_filter || null;
const csvContent = await fs.readFile(csvPath, 'utf8');
const records = csv.parse(csvContent, { columns: true, skip_empty_lines: true });
for (const record of records) {
const canonicalId = record.canonicalId;
if (!canonicalId) continue;
// Defensive basename validation. canonicalId comes from a trusted
// manifest today, but the value flows directly into a file path —
// reject anything that could escape commands_target_dir.
if (!isSafeCanonicalId(canonicalId)) {
result.skippedInvalidId++;
continue;
}
// Optional per-platform filter: surfaces that should only show
// persona agents (e.g. Copilot's Custom Agents picker) skip
// workflow/tool skills here so the picker isn't cluttered with
// 90+ unrelated entries.
if (filter === 'agents-only' && !(await isAgentSkill(record, bmadDir))) {
result.skippedFiltered++;
continue;
}
// Reserved-name guard is OpenCode-specific. Other adapters that opt
// into commands_target_dir later should declare their own reserved
// set rather than inheriting OpenCode's.
if (this.name === 'opencode' && RESERVED_OPENCODE_COMMANDS.has(canonicalId)) {
result.skippedCollision++;
continue;
}
let description = (record.description || '').trim();
if (!description) {
description = `Run the ${canonicalId} skill`;
result.fallbackDescription++;
}
const body = buildCommandPointerBody(description, canonicalId, { template, targetDir });
const commandFile = path.join(commandsPath, `${canonicalId}${extension}`);
// If a pointer file already exists, decide whether to overwrite based
// on whether it looks like generator output (description-only diff) or
// a user-modified file. forceCommands overrides this protection.
if (!options.forceCommands && (await fs.pathExists(commandFile))) {
let existing;
try {
existing = await fs.readFile(commandFile, 'utf8');
} catch {
// Treat unreadable as user-owned and skip — safer than overwriting.
result.skippedExisting++;
continue;
}
if (existing === body) {
// No-op idempotent re-run.
result.skippedExisting++;
continue;
}
if (looksLikeGeneratorOutput(existing, canonicalId, { template, targetDir })) {
// Description (or other generated bit) has changed; refresh in place.
try {
await fs.writeFile(commandFile, body, 'utf8');
result.updated++;
} catch (error) {
result.writeFailures++;
if (!options.silent) {
await prompts.log.warn(`Failed to update command pointer ${canonicalId}${extension}: ${error.message}`);
}
}
continue;
}
// Hand-modified pointer — preserve it.
result.skippedExisting++;
continue;
}
try {
await fs.writeFile(commandFile, body, 'utf8');
result.created++;
} catch (error) {
result.writeFailures++;
if (!options.silent) {
await prompts.log.warn(`Failed to write command pointer ${canonicalId}${extension}: ${error.message}`);
}
}
}
return result;
}
/**
* Install verbatim native SKILL.md directories from skill-manifest.csv.
* Copies the entire source directory as-is into the IDE skill directory.
@ -478,18 +197,6 @@ class ConfigDrivenIdeSetup {
if (count > 0) {
await prompts.log.success(`${this.name} configured: ${count} skills → ${targetDir}`);
}
const cmd = results.commands;
if (cmd && (cmd.created > 0 || cmd.updated > 0) && this.installerConfig?.commands_target_dir) {
const total = cmd.created + cmd.updated;
const detail = cmd.updated > 0 ? `${cmd.created} new, ${cmd.updated} refreshed` : `${total}`;
await prompts.log.success(`${this.name} commands: ${detail}${this.installerConfig.commands_target_dir}`);
if (cmd.skippedCollision > 0) {
await prompts.log.message(` (${cmd.skippedCollision} skipped — name collides with reserved slash command)`);
}
if (cmd.writeFailures > 0) {
await prompts.log.warn(` (${cmd.writeFailures} pointer writes failed — see warnings above)`);
}
}
}
/**
@ -515,6 +222,27 @@ class ConfigDrivenIdeSetup {
removalSet = new Set();
}
// Migrate legacy target directories (e.g. .opencode/agent → .opencode/agents)
// Legacy dirs are abandoned entirely, so use prefix matching (null removalSet)
if (this.installerConfig?.legacy_targets) {
const legacyDirsExist = await Promise.all(
this.installerConfig.legacy_targets.map((d) =>
this.isGlobalPath(d) ? fs.pathExists(d.replace(/^~/, os.homedir())) : fs.pathExists(path.join(projectDir, d)),
),
);
if (legacyDirsExist.some(Boolean)) {
if (!options.silent) await prompts.log.message(' Migrating legacy directories...');
for (const legacyDir of this.installerConfig.legacy_targets) {
if (this.isGlobalPath(legacyDir)) {
await this.warnGlobalLegacy(legacyDir, options);
} else {
await this.cleanupTarget(projectDir, legacyDir, options, null);
await this.removeEmptyParents(projectDir, legacyDir);
}
}
}
}
// Strip BMAD markers from copilot-instructions.md if present
if (this.name === 'github-copilot') {
await this.cleanupCopilotInstructions(projectDir, options);
@ -530,47 +258,47 @@ class ConfigDrivenIdeSetup {
await this.cleanupRovoDevPrompts(projectDir, options);
}
// Clean generated command pointer files in commands_target_dir.
// Mirrors target_dir cleanup so uninstalls and skill removals don't
// leave dangling /<canonicalId> commands pointing at missing skills.
// Runs regardless of skipTarget — command pointers live in a per-IDE
// directory and are not deduped across peers, so a peer-owned shared
// skills directory does not protect this IDE's command pointers from
// cleanup. The "currently active" set is passed so install-flow cleanup
// (where removalSet contains skills that will be re-added moments later)
// doesn't trample hand-edited pointers; install-flow cleanup will only
// delete pointers for skills that are not in the new manifest.
if (this.installerConfig?.commands_target_dir) {
// In the install/update flow (signal: previousSkillIds was passed),
// spare pointers whose canonicalId is still in the manifest so hand
// edits survive a routine reinstall. In the uninstall flow (no
// previousSkillIds — full uninstall or per-IDE removal via
// cleanupByList), don't spare anything; the IDE itself is going away,
// so its pointers should go with it.
const isInstallFlow = options.previousSkillIds && options.previousSkillIds.size > 0;
const activeSkillIds = isInstallFlow ? await this._readActiveSkillIds(resolvedBmadDir) : new Set();
const extension = this.installerConfig.commands_extension || '.md';
await this.cleanupCommandPointers(
projectDir,
this.installerConfig.commands_target_dir,
options,
removalSet,
activeSkillIds,
extension,
);
}
// Skip target_dir cleanup when a peer platform owns this directory
// (set during dedup'd install or when uninstalling one of several
// platforms that share the same target_dir).
if (options.skipTarget) return;
// Clean current target directory
if (this.installerConfig?.target_dir) {
await this.cleanupTarget(projectDir, this.installerConfig.target_dir, options, removalSet);
}
}
/**
* Check if a path is global (starts with ~ or is absolute)
* @param {string} p - Path to check
* @returns {boolean}
*/
isGlobalPath(p) {
return p.startsWith('~') || path.isAbsolute(p);
}
/**
* Warn about stale BMAD files in a global legacy directory (never auto-deletes)
* @param {string} legacyDir - Legacy directory path (may start with ~)
* @param {Object} options - Options (silent, etc.)
*/
async warnGlobalLegacy(legacyDir, options = {}) {
try {
const expanded = legacyDir.startsWith('~/')
? path.join(os.homedir(), legacyDir.slice(2))
: legacyDir === '~'
? os.homedir()
: legacyDir;
if (!(await fs.pathExists(expanded))) return;
const entries = await fs.readdir(expanded);
const bmadFiles = entries.filter((e) => typeof e === 'string' && e.startsWith('bmad'));
if (bmadFiles.length > 0 && !options.silent) {
await prompts.log.warn(`Found ${bmadFiles.length} stale BMAD file(s) in ${expanded}. Remove manually: rm ${expanded}/bmad-*`);
}
} catch {
// Errors reading global paths are silently ignored
}
}
/**
* Find the _bmad directory in a project
* @param {string} projectDir - Project directory
@ -659,97 +387,6 @@ class ConfigDrivenIdeSetup {
}
}
/**
* Cleanup generated command pointer files for entries in removalSet.
* Symmetric counterpart to installCommandPointers removes
* `<canonicalId><extension>` files whose canonicalId is in the set. Removes
* the commands directory entirely if it ends up empty.
* @param {string} projectDir
* @param {string} commandsTargetDir - Relative dir (e.g. .opencode/commands)
* @param {Object} options
* @param {Set<string>} removalSet - canonicalIds whose pointer files to remove
* @param {Set<string>} [activeSkillIds] - canonicalIds present in the
* current manifest. Pointers for IDs in this set are spared so an
* install-flow cleanup (where removalSet === previousSkillIds and the
* same skills are about to be re-installed) doesn't wipe hand-edited
* pointer files. Pass an empty set or omit to delete every match in
* removalSet (uninstall flow).
* @param {string} [extension] - Pointer file extension (default '.md');
* matches the platform's commands_extension config value so cleanup
* correctly identifies pointer files for IDEs whose convention isn't .md
* (e.g. Copilot's `.agent.md`).
*/
async cleanupCommandPointers(
projectDir,
commandsTargetDir,
options = {},
removalSet = new Set(),
activeSkillIds = new Set(),
extension = '.md',
) {
if (!removalSet || removalSet.size === 0) return;
const commandsPath = path.join(projectDir, commandsTargetDir);
if (!(await fs.pathExists(commandsPath))) return;
let entries;
try {
entries = await fs.readdir(commandsPath);
} catch {
return;
}
for (const entry of entries) {
if (!entry.endsWith(extension)) continue;
const canonicalId = entry.slice(0, -extension.length);
if (!removalSet.has(canonicalId)) continue;
// Spare pointers for skills that are still in the manifest; the
// install pass will refresh them in place if their content has gone
// stale, while preserving hand edits.
if (activeSkillIds.has(canonicalId)) continue;
try {
await fs.remove(path.join(commandsPath, entry));
} catch {
// Skip files we can't remove.
}
}
// Remove the commands directory if we emptied it.
try {
const remaining = await fs.readdir(commandsPath);
if (remaining.length === 0) {
await fs.remove(commandsPath);
}
} catch {
// Directory may already be gone.
}
}
/**
* Read the canonicalIds currently present in the skill-manifest.csv.
* Used by cleanup to distinguish "re-install of an existing skill"
* (preserve pointer) from "skill truly being removed" (delete pointer).
* @param {string|null} bmadDir
* @returns {Promise<Set<string>>}
*/
async _readActiveSkillIds(bmadDir) {
const ids = new Set();
if (!bmadDir) return ids;
const csvPath = path.join(bmadDir, '_config', 'skill-manifest.csv');
if (!(await fs.pathExists(csvPath))) return ids;
try {
const content = await fs.readFile(csvPath, 'utf8');
const records = csv.parse(content, { columns: true, skip_empty_lines: true });
for (const record of records) {
if (record.canonicalId) ids.add(record.canonicalId);
}
} catch {
// Manifest unreadable — return an empty set so cleanup falls back to
// the conservative "delete what removalSet says" behavior.
}
return ids;
}
/**
* Cleanup a specific target directory.
* When removalSet is provided, only removes entries in that set.
@ -789,8 +426,8 @@ class ConfigDrivenIdeSetup {
// Always preserve bmad-os-* utility skills regardless of cleanup mode
if (entry.startsWith('bmad-os-')) continue;
// Surgical removal from set, or fallback to manifest+prefix detection when null
const shouldRemove = removalSet ? removalSet.has(entry) : isBmadOwnedEntry(entry, null);
// Surgical removal from set, or legacy prefix matching when set is null
const shouldRemove = removalSet ? removalSet.has(entry) : entry.startsWith('bmad');
if (shouldRemove) {
try {
@ -953,9 +590,10 @@ class ConfigDrivenIdeSetup {
try {
if (await fs.pathExists(candidatePath)) {
const entries = await fs.readdir(candidatePath);
const ancestorBmadDir = await this._findBmadDir(current);
const canonicalIds = await getInstalledCanonicalIds(ancestorBmadDir);
if (entries.some((e) => isBmadOwnedEntry(e, canonicalIds))) {
const hasBmad = entries.some(
(e) => typeof e === 'string' && e.toLowerCase().startsWith('bmad') && !e.toLowerCase().startsWith('bmad-os-'),
);
if (hasBmad) {
return candidatePath;
}
}
@ -967,6 +605,43 @@ class ConfigDrivenIdeSetup {
return null;
}
/**
* Walk up ancestor directories from relativeDir toward projectDir, removing each if empty
* Stops at projectDir boundary never removes projectDir itself
* @param {string} projectDir - Project root (boundary)
* @param {string} relativeDir - Relative directory to start from
*/
async removeEmptyParents(projectDir, relativeDir) {
const resolvedProject = path.resolve(projectDir);
let current = relativeDir;
let last = null;
while (current && current !== '.' && current !== last) {
last = current;
const fullPath = path.resolve(projectDir, current);
// Boundary guard: never traverse outside projectDir
if (!fullPath.startsWith(resolvedProject + path.sep) && fullPath !== resolvedProject) break;
try {
if (!(await fs.pathExists(fullPath))) {
// Dir already gone — advance current; last is reset at top of next iteration
current = path.dirname(current);
continue;
}
const remaining = await fs.readdir(fullPath);
if (remaining.length > 0) break;
await fs.rmdir(fullPath);
} catch (error) {
// ENOTEMPTY: TOCTOU race (file added between readdir and rmdir) — skip level, continue upward
// ENOENT: dir removed by another process between pathExists and rmdir — skip level, continue upward
if (error.code === 'ENOTEMPTY' || error.code === 'ENOENT') {
current = path.dirname(current);
continue;
}
break; // fatal error (e.g. EACCES) — stop upward walk
}
current = path.dirname(current);
}
}
}
module.exports = { ConfigDrivenIdeSetup };

View File

@ -160,18 +160,8 @@ class IdeManager {
let detail = '';
if (handlerResult && handlerResult.results) {
const r = handlerResult.results;
let count = r.skillDirectories || r.skills || 0;
// Dedup'd platform: report the count its peer wrote so the user sees
// a consistent picture across all platforms sharing the dir.
if (count === 0 && r.sharedTargetHandledByPeer && options.sharedSkillCount) {
count = options.sharedSkillCount;
}
const targetDir = handler.installerConfig?.target_dir || null;
if (count > 0 && targetDir) {
detail = `${count} skills → ${targetDir}`;
} else if (count > 0) {
detail = `${count} skills`;
}
const count = r.skillDirectories || r.skills || 0;
if (count > 0) detail = `${count} skills`;
}
// Propagate handler's success status (default true for backward compat)
const success = handlerResult?.success !== false;
@ -182,57 +172,6 @@ class IdeManager {
}
}
/**
* Run setup for multiple IDEs as a single batch.
* Dedupes work when several selected platforms share the same target_dir:
* the first platform owns the directory write, peers skip it.
* @param {Array<string>} ideList - IDE names to set up
* @param {string} projectDir
* @param {string} bmadDir
* @param {Object} [options] - Forwarded to each handler.setup
* @returns {Promise<Array>} Per-IDE results
*/
async setupBatch(ideList, projectDir, bmadDir, options = {}) {
await this.ensureInitialized();
const results = [];
// target_dir → { firstIde, skillCount } from the platform that actually wrote it
const claimedTargets = new Map();
for (const ideName of ideList) {
const handler = this.handlers.get(ideName.toLowerCase());
if (!handler) {
results.push(await this.setup(ideName, projectDir, bmadDir, options));
continue;
}
const target = handler.installerConfig?.target_dir || null;
const claim = target ? claimedTargets.get(target) : null;
const skipTarget = !!claim;
const result = await this.setup(ideName, projectDir, bmadDir, {
...options,
skipTarget,
sharedWith: claim?.firstIde || null,
sharedTarget: target,
sharedSkillCount: claim?.skillCount || 0,
});
if (target && !claim) {
const writtenCount = result.handlerResult?.results?.skillDirectories || result.handlerResult?.results?.skills || 0;
// Only claim the target when the install actually succeeded and wrote skills.
// If the first platform fails (ancestor conflict, exception, etc.), leave the
// dir unclaimed so the next peer becomes the new first writer instead of
// silently skipping into a broken/empty target_dir.
if (result.success && writtenCount > 0) {
claimedTargets.set(target, { firstIde: ideName, skillCount: writtenCount });
}
}
results.push(result);
}
return results;
}
/**
* Cleanup IDE configurations
* @param {string} projectDir - Project directory
@ -259,8 +198,6 @@ class IdeManager {
* @param {string} projectDir - Project directory
* @param {Array<string>} ideList - List of IDE names to clean up
* @param {Object} [options] - Cleanup options passed through to handlers
* options.remainingIdes - IDE names still installed after this cleanup; used
* to skip target_dir wipe when a co-installed platform shares the dir.
* @returns {Array} Results array
*/
async cleanupByList(projectDir, ideList, options = {}) {
@ -274,27 +211,13 @@ class IdeManager {
// Build lowercase lookup for case-insensitive matching
const lowercaseHandlers = new Map([...this.handlers.entries()].map(([k, v]) => [k.toLowerCase(), v]));
// Resolve target_dirs for IDEs that will remain installed after this cleanup
const remainingTargets = new Set();
if (Array.isArray(options.remainingIdes)) {
for (const remaining of options.remainingIdes) {
const h = lowercaseHandlers.get(String(remaining).toLowerCase());
const t = h?.installerConfig?.target_dir;
if (t) remainingTargets.add(t);
}
}
for (const ideName of ideList) {
const handler = lowercaseHandlers.get(ideName.toLowerCase());
if (!handler) continue;
const target = handler.installerConfig?.target_dir || null;
const skipTarget = target && remainingTargets.has(target);
const cleanupOptions = skipTarget ? { ...options, skipTarget: true } : options;
try {
await handler.cleanup(projectDir, cleanupOptions);
results.push({ ide: ideName, success: true, skippedTarget: !!skipTarget });
await handler.cleanup(projectDir, options);
results.push({ ide: ideName, success: true });
} catch (error) {
results.push({ ide: ideName, success: false, error: error.message });
}

View File

@ -31,50 +31,7 @@ function clearCache() {
_cachedPlatformCodes = null;
}
/**
* Format the installable platform list for human-readable output (used by --list-tools).
* Sourced from IdeManager so this view matches what --tools accepts at install time
* (suspended platforms excluded).
* @returns {Promise<string>} Formatted multi-line string with id, name, target_dir, preferred flag.
*/
async function formatPlatformList() {
const { IdeManager } = require('./manager');
const ideManager = new IdeManager();
await ideManager.ensureInitialized();
const entries = ideManager.getAvailableIdes().map((ide) => {
const handler = ideManager.handlers.get(ide.value);
return {
id: ide.value,
name: ide.name,
targetDir: handler?.installerConfig?.target_dir || '',
preferred: ide.preferred,
};
});
const idWidth = Math.max(...entries.map((e) => e.id.length), 'ID'.length);
const nameWidth = Math.max(...entries.map((e) => e.name.length), 'Name'.length);
const pad = (s, w) => s + ' '.repeat(Math.max(0, w - s.length));
const lines = [
`Supported tool IDs (pass via --tools <id>[,<id>...]):`,
'',
` ${pad('ID', idWidth)} ${pad('Name', nameWidth)} Target dir`,
` ${pad('-'.repeat(idWidth), idWidth)} ${pad('-'.repeat(nameWidth), nameWidth)} ${'-'.repeat(10)}`,
];
for (const e of entries) {
const star = e.preferred ? ' *' : ' ';
lines.push(`${star}${pad(e.id, idWidth)} ${pad(e.name, nameWidth)} ${e.targetDir}`);
}
lines.push('', '* = recommended / preferred', '', 'Example: bmad-method install --modules bmm --tools claude-code');
return lines.join('\n');
}
module.exports = {
loadPlatformCodes,
clearCache,
formatPlatformList,
};

View File

@ -5,218 +5,122 @@
# preferred: Whether shown as a recommended option on install
# suspended: (optional) Message explaining why install is blocked
# installer:
# target_dir: Directory where skill directories are installed (project/workspace)
# global_target_dir: (optional) User-home directory for global install
# target_dir: Directory where skill directories are installed
# legacy_targets: (optional) Old target dirs to clean up on reinstall
# ancestor_conflict_check: (optional) Refuse install when ancestor dir has BMAD files
#
# Multiple platforms may share the same target_dir or global_target_dir — many tools
# read from the shared `.agents/skills/` and `~/.agents/skills/` cross-tool standard.
# Paths verified against each tool's primary docs as of 2026-04-25.
platforms:
adal:
name: "AdaL"
preferred: false
installer:
target_dir: .adal/skills
global_target_dir: ~/.adal/skills
amp:
name: "Sourcegraph Amp"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.config/agents/skills
antigravity:
name: "Google Antigravity"
preferred: false
installer:
legacy_targets:
- .agent/workflows
target_dir: .agent/skills
global_target_dir: ~/.gemini/antigravity/skills
auggie:
name: "Auggie"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.agents/skills
bob:
name: "IBM Bob"
preferred: false
installer:
target_dir: .bob/skills
global_target_dir: ~/.bob/skills
legacy_targets:
- .augment/commands
target_dir: .augment/skills
claude-code:
name: "Claude Code"
preferred: true
installer:
legacy_targets:
- .claude/commands
target_dir: .claude/skills
global_target_dir: ~/.claude/skills
cline:
name: "Cline"
preferred: false
installer:
legacy_targets:
- .clinerules/workflows
target_dir: .cline/skills
global_target_dir: ~/.cline/skills
codex:
name: "Codex"
preferred: true
preferred: false
installer:
legacy_targets:
- .codex/prompts
- ~/.codex/prompts
target_dir: .agents/skills
global_target_dir: ~/.codex/skills
codebuddy:
name: "CodeBuddy"
preferred: false
installer:
legacy_targets:
- .codebuddy/commands
target_dir: .codebuddy/skills
global_target_dir: ~/.codebuddy/skills
command-code:
name: "Command Code"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.agents/skills
cortex:
name: "Snowflake Cortex Code"
preferred: false
installer:
target_dir: .cortex/skills
global_target_dir: ~/.snowflake/cortex/skills
crush:
name: "Crush"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.config/agents/skills
legacy_targets:
- .crush/commands
target_dir: .crush/skills
cursor:
name: "Cursor"
preferred: true
installer:
target_dir: .agents/skills
global_target_dir: ~/.agents/skills
droid:
name: "Factory Droid"
preferred: false
installer:
target_dir: .factory/skills
global_target_dir: ~/.factory/skills
firebender:
name: "Firebender"
preferred: false
installer:
target_dir: .firebender/skills
global_target_dir: ~/.agents/skills
legacy_targets:
- .cursor/commands
target_dir: .cursor/skills
gemini:
name: "Gemini CLI"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.agents/skills
legacy_targets:
- .gemini/commands
target_dir: .gemini/skills
github-copilot:
name: "GitHub Copilot"
preferred: true
installer:
target_dir: .agents/skills
global_target_dir: ~/.agents/skills
commands_target_dir: .github/agents
commands_extension: .agent.md
commands_body_template: "LOAD the FULL {project-root}/{target_dir}/{canonicalId}/SKILL.md, READ its entire contents and follow its directions exactly!"
# The Custom Agents picker should only show persona agents (not
# workflows/tools). Detected by reading each skill's source
# `customize.toml` and checking for an `[agent]` section — that's
# the actual configuration source of truth: every BMAD persona is
# configured under `[agent]`, every workflow under `[workflow]`,
# every standalone skill has no customize.toml. This signal is
# naming-independent, so personas like `bmad-tea` (which doesn't
# follow the `-agent-` convention) are still included, and
# meta-skills like `bmad-agent-builder` (which contains `-agent-`
# but is a skill-builder workflow, not a persona) are correctly
# excluded.
commands_filter: agents-only
goose:
name: "Block Goose"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.config/agents/skills
legacy_targets:
- .github/agents
- .github/prompts
target_dir: .github/skills
iflow:
name: "iFlow"
preferred: false
installer:
legacy_targets:
- .iflow/commands
target_dir: .iflow/skills
global_target_dir: ~/.iflow/skills
junie:
name: "Junie"
preferred: false
installer:
target_dir: .junie/skills
global_target_dir: ~/.junie/skills
target_dir: .agents/skills
kilo:
name: "KiloCoder"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.kilocode/skills
kimi-code:
name: "Kimi Code"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.agents/skills
legacy_targets:
- .kilocode/workflows
target_dir: .kilocode/skills
kiro:
name: "Kiro"
preferred: false
installer:
legacy_targets:
- .kiro/steering
target_dir: .kiro/skills
global_target_dir: ~/.kiro/skills
kode:
name: "Kode"
preferred: false
installer:
target_dir: .kode/skills
global_target_dir: ~/.kode/skills
mistral-vibe:
name: "Mistral Vibe"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.vibe/skills
mux:
name: "Mux"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.agents/skills
neovate:
name: "Neovate"
preferred: false
installer:
target_dir: .neovate/skills
global_target_dir: ~/.neovate/skills
ona:
name: "Ona"
@ -224,99 +128,65 @@ platforms:
installer:
target_dir: .ona/skills
openclaw:
name: "OpenClaw"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.agents/skills
opencode:
name: "OpenCode"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.agents/skills
commands_target_dir: .opencode/commands
openhands:
name: "OpenHands"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.agents/skills
legacy_targets:
- .opencode/agents
- .opencode/commands
- .opencode/agent
- .opencode/command
target_dir: .opencode/skills
pi:
name: "Pi"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.agents/skills
pochi:
name: "Pochi"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.agents/skills
target_dir: .pi/skills
qoder:
name: "Qoder"
preferred: false
installer:
target_dir: .qoder/skills
global_target_dir: ~/.qoder/skills
qwen:
name: "QwenCoder"
preferred: false
installer:
legacy_targets:
- .qwen/commands
target_dir: .qwen/skills
global_target_dir: ~/.qwen/skills
replit:
name: "Replit Agent"
preferred: false
installer:
target_dir: .agents/skills
roo:
name: "Roo Code"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.agents/skills
legacy_targets:
- .roo/commands
target_dir: .roo/skills
rovo-dev:
name: "Rovo Dev"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.agents/skills
legacy_targets:
- .rovodev/workflows
target_dir: .rovodev/skills
trae:
name: "Trae"
preferred: false
installer:
legacy_targets:
- .trae/rules
target_dir: .trae/skills
warp:
name: "Warp"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.agents/skills
windsurf:
name: "Windsurf"
preferred: false
installer:
target_dir: .agents/skills
global_target_dir: ~/.agents/skills
zencoder:
name: "Zencoder"
preferred: false
installer:
target_dir: .zencoder/skills
global_target_dir: ~/.zencoder/skills
legacy_targets:
- .windsurf/workflows
target_dir: .windsurf/skills

View File

@ -1,50 +0,0 @@
const path = require('node:path');
const fs = require('../../fs-native');
const csv = require('csv-parse/sync');
/**
* Read the global skill-manifest.csv and return the set of canonicalIds.
* These define which directory entries in a target_dir are BMAD-owned, regardless
* of whether they happen to start with "bmad-" (custom modules can ship skills
* with any prefix, e.g. "fred-cool-skill").
*
* @param {string} bmadDir - Path to the _bmad install directory
* @returns {Promise<Set<string>>} Set of canonicalIds, or empty set if manifest missing
*/
async function getInstalledCanonicalIds(bmadDir) {
const ids = new Set();
if (!bmadDir) return ids;
const csvPath = path.join(bmadDir, '_config', 'skill-manifest.csv');
if (!(await fs.pathExists(csvPath))) return ids;
try {
const content = await fs.readFile(csvPath, 'utf8');
const records = csv.parse(content, { columns: true, skip_empty_lines: true });
for (const record of records) {
if (record.canonicalId) ids.add(record.canonicalId);
}
} catch {
// Unreadable/invalid manifest — treat as no info
}
return ids;
}
/**
* Test whether a directory entry is BMAD-owned.
* Prefers the manifest's canonicalIds; falls back to the legacy "bmad" prefix
* when no manifest is available (early install, ancestor lookup with no bmad dir).
*
* @param {string} entry - Directory entry name
* @param {Set<string>|null} canonicalIds - From getInstalledCanonicalIds, or null
* @returns {boolean}
*/
function isBmadOwnedEntry(entry, canonicalIds) {
if (!entry || typeof entry !== 'string') return false;
if (entry.toLowerCase().startsWith('bmad-os-')) return false;
if (canonicalIds && canonicalIds.size > 0) return canonicalIds.has(entry);
return entry.toLowerCase().startsWith('bmad');
}
module.exports = { getInstalledCanonicalIds, isBmadOwnedEntry };

View File

@ -1,210 +0,0 @@
const path = require('node:path');
const fs = require('./fs-native');
const yaml = require('yaml');
const { getProjectRoot, getModulePath, getExternalModuleCachePath } = require('./project-root');
/**
* Read a module.yaml and return its declared `code:` field, or null if missing/unparseable.
*/
async function readModuleCode(yamlPath) {
try {
const parsed = yaml.parse(await fs.readFile(yamlPath, 'utf8'));
if (parsed && typeof parsed === 'object' && typeof parsed.code === 'string') {
return parsed.code;
}
} catch {
// fall through
}
return null;
}
/**
* Discover module.yaml files for officials we can read locally:
* - core, bmm: bundled in src/ (always present)
* - external officials: only if previously cloned to ~/.bmad/cache/external-modules/
*
* Each result's `code` is the `code:` field from the module.yaml when present;
* that's the value `--set <module>.<key>=<value>` matches against.
*
* Community/custom modules are not enumerated; users reference their own
* module.yaml directly per the design (see issue #1663).
*
* @returns {Promise<Array<{code: string, yamlPath: string, source: string}>>}
*/
async function discoverOfficialModuleYamls() {
const found = [];
// Dedupe is case-insensitive because module caches occasionally retain a
// legacy UPPERCASE-named directory alongside the canonical lowercase one
// (same module, different cache key from an older schema). We pick whichever
// entry we see first and skip the alternate-case duplicate. NOTE: `--set`
// matching itself is case-sensitive (it keys on `moduleName` from the install
// flow's selected list, which is always lowercase short codes), so the
// surfaced `code` here is what users should type. Don't change to
// case-sensitive dedupe without revisiting that contract.
const seenCodes = new Set();
const addFound = async (yamlPath, source, fallbackCode) => {
const declaredCode = await readModuleCode(yamlPath);
const code = declaredCode || fallbackCode;
if (!code) return;
const lower = code.toLowerCase();
if (seenCodes.has(lower)) return;
seenCodes.add(lower);
found.push({ code, yamlPath, source });
};
// Built-ins.
for (const code of ['core', 'bmm']) {
const yamlPath = path.join(getModulePath(code), 'module.yaml');
if (await fs.pathExists(yamlPath)) {
// Built-ins use their well-known short codes regardless of what the
// module.yaml `code:` says, since the install flow keys on these.
seenCodes.add(code.toLowerCase());
found.push({ code, yamlPath, source: 'built-in' });
}
}
// Bundled in src/modules/<code>/module.yaml (rare, but supported by getModulePath).
const srcModulesDir = path.join(getProjectRoot(), 'src', 'modules');
if (await fs.pathExists(srcModulesDir)) {
const entries = await fs.readdir(srcModulesDir, { withFileTypes: true });
for (const entry of entries) {
if (!entry.isDirectory()) continue;
const yamlPath = path.join(srcModulesDir, entry.name, 'module.yaml');
if (await fs.pathExists(yamlPath)) {
await addFound(yamlPath, 'bundled', entry.name);
}
}
}
// External cache (~/.bmad/cache/external-modules/<code>/...).
const cacheRoot = getExternalModuleCachePath('').replace(/\/$/, '');
if (await fs.pathExists(cacheRoot)) {
const rawEntries = await fs.readdir(cacheRoot, { withFileTypes: true });
for (const entry of rawEntries) {
if (!entry.isDirectory()) continue;
const candidates = [
path.join(cacheRoot, entry.name, 'module.yaml'),
path.join(cacheRoot, entry.name, 'src', 'module.yaml'),
path.join(cacheRoot, entry.name, 'skills', 'module.yaml'),
];
for (const candidate of candidates) {
if (await fs.pathExists(candidate)) {
await addFound(candidate, 'cached', entry.name);
break;
}
}
}
}
return found;
}
function formatPromptText(item) {
if (Array.isArray(item.prompt)) return item.prompt.join(' ');
return String(item.prompt || '').trim();
}
function inferType(item) {
if (item['single-select']) return 'single-select';
if (item['multi-select']) return 'multi-select';
if (typeof item.default === 'boolean') return 'boolean';
if (typeof item.default === 'number') return 'number';
return 'string';
}
function formatModuleOptions(code, parsed, source) {
const lines = [];
const header = source === 'built-in' ? code : `${code} (${source})`;
lines.push(header + ':');
let count = 0;
for (const [key, item] of Object.entries(parsed)) {
if (!item || typeof item !== 'object' || !('prompt' in item)) continue;
count++;
const type = inferType(item);
const scope = item.scope === 'user' ? ' [user-scope]' : '';
const defaultStr = item.default === undefined || item.default === null ? '(none)' : String(item.default);
lines.push(` ${code}.${key} (${type}${scope}) default: ${defaultStr}`);
const promptText = formatPromptText(item);
if (promptText) lines.push(` ${promptText}`);
if (Array.isArray(item['single-select'])) {
const values = item['single-select'].map((v) => (typeof v === 'object' ? v.value : v)).filter((v) => v !== undefined);
if (values.length > 0) lines.push(` values: ${values.join(' | ')}`);
}
lines.push('');
}
if (count === 0) {
lines.push(' (no configurable options)', '');
}
return lines.join('\n');
}
/**
* Render `--list-options` output.
*
* Returns `{ text, ok }` so callers can surface a non-zero exit code on
* a typo'd module-code lookup. Discovery dedupes case-insensitively, so
* the lookup is also case-insensitive typing `--list-options BMM` and
* `--list-options bmm` both find the bmm built-in.
*
* @param {string|null} moduleCode - if non-null, restrict to this module
* @returns {Promise<{text: string, ok: boolean}>}
*/
async function formatOptionsList(moduleCode) {
const discovered = await discoverOfficialModuleYamls();
const needle = moduleCode ? moduleCode.toLowerCase() : null;
const filtered = needle ? discovered.filter((d) => d.code.toLowerCase() === needle) : discovered;
if (filtered.length === 0) {
if (moduleCode) {
const text = [
`No locally-known module.yaml for '${moduleCode}'.`,
'',
'Built-in modules (core, bmm) are always available. External officials',
'appear here after they have been installed at least once on this machine',
'(they are cached under ~/.bmad/cache/external-modules/).',
'',
'For community or custom modules, read the module.yaml file in that',
"module's source repository directly.",
].join('\n');
return { text, ok: false };
}
return { text: 'No modules found.', ok: false };
}
const sections = [];
// Track when a module-scoped lookup couldn't actually be rendered (yaml
// unparseable or empty after parse). The full `--list-options` output is
// tolerant of one bad entry, but `--list-options <module>` against a single
// unreadable module should still fail tooling so a CI script catches it.
let moduleScopedFailure = false;
sections.push('Available --set keys', 'Format: --set <module>.<key>=<value> (repeatable)', '');
for (const { code, yamlPath, source } of filtered) {
let parsed;
try {
parsed = yaml.parse(await fs.readFile(yamlPath, 'utf8'));
} catch {
sections.push(`${code} (${source}): could not parse module.yaml`, '');
if (moduleCode) moduleScopedFailure = true;
continue;
}
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
sections.push(`${code} (${source}): module.yaml is not a valid object (got ${Array.isArray(parsed) ? 'array' : typeof parsed})`, '');
if (moduleCode) moduleScopedFailure = true;
continue;
}
sections.push(formatModuleOptions(code, parsed, source));
}
if (!moduleCode) {
sections.push(
'Community and custom modules are not listed here — read their module.yaml directly. Unknown keys still persist with a warning.',
);
}
return { text: sections.join('\n'), ok: !moduleScopedFailure };
}
module.exports = { formatOptionsList, discoverOfficialModuleYamls };

View File

@ -29,11 +29,6 @@ class CommunityModuleManager {
// Shared across all instances; the manifest writer often uses a fresh instance.
static _resolutions = new Map();
// moduleCode → ResolvedModule (from PluginResolver) when the cloned repo ships
// a `.claude-plugin/marketplace.json`. Lets community installs reuse the same
// skill-level install pipeline as custom-source installs (installFromResolution).
static _pluginResolutions = new Map();
constructor() {
this._client = new RegistryClient();
this._cachedIndex = null;
@ -45,11 +40,6 @@ class CommunityModuleManager {
return CommunityModuleManager._resolutions.get(moduleCode) || null;
}
/** Get the marketplace.json-derived plugin resolution for a community module, if any. */
getPluginResolution(moduleCode) {
return CommunityModuleManager._pluginResolutions.get(moduleCode) || null;
}
// ─── Data Loading ──────────────────────────────────────────────────────────
/**
@ -381,18 +371,6 @@ class CommunityModuleManager {
planSource: planEntry.source,
});
// If the repo ships a marketplace.json, route through PluginResolver so the
// skill-level install pipeline (installFromResolution) handles the copy.
// Repos without marketplace.json fall through to the legacy findModuleSource
// path unchanged.
await this._tryResolveMarketplacePlugin(moduleCacheDir, moduleInfo, {
channel: planEntry.channel,
version: recordedVersion,
sha: installedSha,
approvedTag,
approvedSha,
});
// Install dependencies if needed
const packageJsonPath = path.join(moduleCacheDir, 'package.json');
if ((needsDependencyInstall || wasNewClone) && (await fs.pathExists(packageJsonPath))) {
@ -414,204 +392,6 @@ class CommunityModuleManager {
return moduleCacheDir;
}
// ─── Marketplace.json Resolution ──────────────────────────────────────────
/**
* Detect `.claude-plugin/marketplace.json` in a cloned community repo and
* route through PluginResolver. When successful, caches the resolution so
* OfficialModulesManager.install() can route the copy through
* installFromResolution() the same path used by custom-source installs.
*
* Silent no-op when marketplace.json is absent or the resolver returns no
* matches; the legacy findModuleSource path then handles the install.
*
* @param {string} repoPath - Absolute path to the cloned repo
* @param {Object} moduleInfo - Normalized community module info
* @param {Object} resolution - Resolution metadata from cloneModule
* @param {string} resolution.channel - Channel ('stable' | 'next' | 'pinned')
* @param {string} resolution.version - Recorded version string
* @param {string} resolution.sha - Resolved git SHA
* @param {string|null} resolution.approvedTag - Registry approved tag
* @param {string|null} resolution.approvedSha - Registry approved SHA
*/
async _tryResolveMarketplacePlugin(repoPath, moduleInfo, resolution) {
const marketplacePath = path.join(repoPath, '.claude-plugin', 'marketplace.json');
if (!(await fs.pathExists(marketplacePath))) return;
let marketplaceData;
try {
marketplaceData = JSON.parse(await fs.readFile(marketplacePath, 'utf8'));
} catch {
// Malformed marketplace.json — fall through to legacy path.
return;
}
const plugins = Array.isArray(marketplaceData?.plugins) ? marketplaceData.plugins : [];
if (plugins.length === 0) return;
const selection = this._selectPluginForModule(plugins, moduleInfo);
if (!selection) {
await this._safeWarn(
`Community module '${moduleInfo.code}' ships marketplace.json but no plugin entry matches the registry code. ` +
`Falling back to legacy install path.`,
);
return;
}
if (selection.source === 'single-fallback') {
// Single-entry marketplace.json whose plugin name doesn't match the registry
// code or the module_definition hint. Most likely correct, but worth surfacing
// in case marketplace.json is misconfigured and we'd install the wrong plugin.
await this._safeWarn(
`Community module '${moduleInfo.code}' picked the only plugin in marketplace.json ('${selection.plugin?.name}') ` +
`because no name or module_definition match was found. Verify marketplace.json if the install looks wrong.`,
);
}
const { PluginResolver } = require('./plugin-resolver');
const resolver = new PluginResolver();
let resolved;
try {
resolved = await resolver.resolve(repoPath, selection.plugin);
} catch (error) {
// PluginResolver threw (malformed plugin entry, missing files, etc.).
// Honor the silent-fallthrough contract — warn and let the legacy
// findModuleSource path handle the install.
await this._safeWarn(
`PluginResolver failed for community module '${moduleInfo.code}': ${error.message}. ` + `Falling back to legacy install path.`,
);
return;
}
if (!resolved || resolved.length === 0) return;
// The registry registers a single code per module. If the resolver returns
// multiple modules (Strategy 4: multiple standalone skills), accept only
// the entry whose code matches the registry. Other entries are ignored —
// they belong to plugins not registered in the community catalog.
const matched = resolved.find((mod) => mod.code === moduleInfo.code) || (resolved.length === 1 ? resolved[0] : null);
if (!matched) return;
// Shallow-clone before stamping provenance — the resolver may cache or reuse
// its return objects, and we don't want install-specific fields leaking back.
const stamped = {
...matched,
code: moduleInfo.code,
repoUrl: moduleInfo.url,
cloneRef: resolution.channel === 'pinned' ? resolution.version : resolution.approvedTag || null,
cloneSha: resolution.sha,
communitySource: true,
communityChannel: resolution.channel,
communityVersion: resolution.version,
registryApprovedTag: resolution.approvedTag,
registryApprovedSha: resolution.approvedSha,
};
CommunityModuleManager._pluginResolutions.set(moduleInfo.code, stamped);
}
/**
* Lazy fallback: resolve marketplace.json straight from the on-disk cache
* when `_pluginResolutions` is empty (e.g. callers that reach `install()`
* without `cloneModule` having populated the cache earlier in this process).
*
* Reuses an existing channel resolution if present; otherwise synthesizes a
* minimal stable-channel stub from the registry entry + the cached repo's
* current HEAD. Returns the cached plugin resolution if one is produced,
* otherwise null (caller falls back to the legacy path).
*
* @param {string} moduleCode
* @returns {Promise<Object|null>}
*/
async resolveFromCache(moduleCode) {
const existing = this.getPluginResolution(moduleCode);
if (existing) return existing;
const cacheRepoDir = path.join(this.getCacheDir(), moduleCode);
const marketplacePath = path.join(cacheRepoDir, '.claude-plugin', 'marketplace.json');
if (!(await fs.pathExists(marketplacePath))) return null;
let moduleInfo;
try {
moduleInfo = await this.getModuleByCode(moduleCode);
} catch {
return null;
}
if (!moduleInfo) return null;
let channelResolution = this.getResolution(moduleCode);
if (!channelResolution) {
let sha = '';
try {
sha = execSync('git rev-parse HEAD', { cwd: cacheRepoDir, stdio: 'pipe' }).toString().trim();
} catch {
// Not a git repo or unreadable — give up and let the legacy path run.
return null;
}
channelResolution = {
channel: 'stable',
version: moduleInfo.approvedTag || sha.slice(0, 7),
sha,
registryApprovedTag: moduleInfo.approvedTag || null,
registryApprovedSha: moduleInfo.approvedSha || null,
};
}
await this._tryResolveMarketplacePlugin(cacheRepoDir, moduleInfo, {
channel: channelResolution.channel,
version: channelResolution.version,
sha: channelResolution.sha,
approvedTag: channelResolution.registryApprovedTag,
approvedSha: channelResolution.registryApprovedSha,
});
return this.getPluginResolution(moduleCode);
}
/**
* Best-effort warning emitter. `prompts.log.warn` may be undefined in some
* harnesses and may return a rejected promise swallow both cases so a
* fallthrough warning can never crash the install.
*/
async _safeWarn(message) {
try {
const result = prompts.log?.warn?.(message);
if (result && typeof result.then === 'function') await result;
} catch {
/* ignore */
}
}
/**
* Pick which plugin entry from marketplace.json represents this community module.
* Precedence:
* 1. Exact match on `plugin.name === moduleInfo.code`
* 2. Trailing directory of `module_definition` matches `plugin.name`
* 3. Single plugin in marketplace.json accepted with a warning so a
* mismatched-but-uniquely-named plugin doesn't install silently.
* Otherwise null (caller falls back to legacy path).
*
* @returns {{plugin: Object, source: 'name'|'hint'|'single-fallback'}|null}
*/
_selectPluginForModule(plugins, moduleInfo) {
const byCode = plugins.find((p) => p && p.name === moduleInfo.code);
if (byCode) return { plugin: byCode, source: 'name' };
if (moduleInfo.moduleDefinition) {
// module_definition like "src/skills/suno-setup/assets/module.yaml" →
// hint segment "suno-setup". Match that against plugin names.
const segments = moduleInfo.moduleDefinition.split('/').filter(Boolean);
const setupIdx = segments.findIndex((s) => s.endsWith('-setup'));
if (setupIdx !== -1) {
const hint = segments[setupIdx];
const byHint = plugins.find((p) => p && p.name === hint);
if (byHint) return { plugin: byHint, source: 'hint' };
}
}
if (plugins.length === 1) return { plugin: plugins[0], source: 'single-fallback' };
return null;
}
// ─── Source Finding ───────────────────────────────────────────────────────
/**

View File

@ -24,9 +24,8 @@ class CustomModuleManager {
/**
* Parse a user-provided source input into a structured descriptor.
* Accepts local file paths, HTTPS Git URLs, HTTP Git URLs, and SSH Git URLs.
* For HTTPS/HTTP URLs with deep paths (e.g., /tree/main/subdir), extracts the subdir.
* The original protocol (http or https) is preserved in the returned cloneUrl.
* Accepts local file paths, HTTPS Git URLs, and SSH Git URLs.
* For HTTPS URLs with deep paths (e.g., /tree/main/subdir), extracts the subdir.
*
* @param {string} input - URL or local file path
* @returns {Object} Parsed source descriptor:
@ -128,102 +127,58 @@ class CustomModuleManager {
};
}
// HTTPS/HTTP URL: generic handling for any Git host.
// We avoid host-specific parsing — `git clone` will accept whatever URL the
// user provides. We only need to (a) separate an optional browser-style
// subdir suffix from the clone URL, (b) extract any embedded ref
// (branch/tag) from deep-path URLs, and (c) derive a cache key / display
// name from the path. The original protocol (http or https) is preserved.
if (/^https?:\/\//i.test(trimmed)) {
let url;
try {
url = new URL(trimmed);
} catch {
url = null;
}
// HTTPS URL: https://host/owner/repo[/tree/branch/subdir][.git]
const httpsMatch = trimmed.match(/^https?:\/\/([^/]+)\/([^/]+)\/([^/.]+?)(?:\.git)?(\/.*)?$/);
if (httpsMatch) {
const [, host, owner, repo, remainder] = httpsMatch;
const cloneUrl = `https://${host}/${owner}/${repo}`;
let subdir = null;
let urlRef = null; // branch/tag extracted from /tree/<ref>/subdir
if (url && url.host) {
const host = url.host;
let repoPath = url.pathname.replace(/^\/+/, '').replace(/\/+$/, '');
let subdir = null;
let urlRef = null; // branch/tag/commit extracted from deep-path URLs
// Detect browser-style deep-path patterns that embed a ref
// (branch/tag/commit) and optional subdirectory. These appear
// across many hosts:
// GitHub /<repo>/tree|blob/<ref>[/<subdir>]
// GitLab /<repo>/-/tree|blob/<ref>[/<subdir>]
// Gitea /<repo>/src/<ref>[/<subdir>]
// Gitea /<repo>/src/(branch|commit|tag)/<ref>[/<subdir>]
// Group 1 = repo path prefix, Group 2 = ref, Group 3 = subdir (optional).
if (remainder) {
// Extract subdir from deep path patterns used by various Git hosts
const deepPathPatterns = [
/^(.+?)\/(?:-\/)?(?:tree|blob)\/([^/]+)(?:\/(.+))?$/,
/^(.+?)\/src\/(?:branch\/|commit\/|tag\/)?([^/]+)(?:\/(.+))?$/,
{ regex: /^\/(?:-\/)?tree\/([^/]+)\/(.+)$/, refIdx: 1, pathIdx: 2 }, // GitHub, GitLab
{ regex: /^\/(?:-\/)?blob\/([^/]+)\/(.+)$/, refIdx: 1, pathIdx: 2 },
{ regex: /^\/src\/([^/]+)\/(.+)$/, refIdx: 1, pathIdx: 2 }, // Gitea/Forgejo
];
for (const pattern of deepPathPatterns) {
const match = repoPath.match(pattern);
// Also match `/tree/<ref>` with no subdir
const refOnlyPatterns = [/^\/(?:-\/)?tree\/([^/]+?)\/?$/, /^\/(?:-\/)?blob\/([^/]+?)\/?$/, /^\/src\/([^/]+?)\/?$/];
for (const p of deepPathPatterns) {
const match = remainder.match(p.regex);
if (match) {
repoPath = match[1];
if (match[2]) urlRef = match[2];
if (match[3]) {
const cleaned = match[3].replace(/\/+$/, '');
if (cleaned) subdir = cleaned;
}
urlRef = match[p.refIdx];
subdir = match[p.pathIdx].replace(/\/$/, '');
break;
}
}
// Some hosts use ?path=/subdir on browse links to point at a file or
// directory. Honor it when no deep-path marker matched above.
if (!subdir) {
const pathParam = url.searchParams.get('path');
if (pathParam) {
const cleaned = pathParam.replace(/^\/+/, '').replace(/\/+$/, '');
if (cleaned) subdir = cleaned;
for (const r of refOnlyPatterns) {
const match = remainder.match(r);
if (match) {
urlRef = match[1];
break;
}
}
}
// Strip a single trailing .git for a stable cacheKey/displayName.
const repoPathClean = repoPath.replace(/\.git$/i, '');
if (!repoPathClean) {
return {
type: null,
cloneUrl: null,
subdir: null,
localPath: null,
cacheKey: null,
displayName: null,
isValid: false,
error: 'Not a valid Git URL or local path',
};
}
const cloneUrl = `${url.protocol}//${host}/${repoPathClean}`;
const cacheKey = `${host}/${repoPathClean}`;
// Display name: prefer "<owner>/<repo>" using the last two meaningful
// path segments.
const segments = repoPathClean.split('/').filter(Boolean);
const repoSeg = segments.at(-1);
const ownerSeg = segments.at(-2);
const displayName = ownerSeg ? `${ownerSeg}/${repoSeg}` : repoSeg;
// Precedence: explicit @version suffix > URL /tree/<ref> path segment.
const version = versionSuffix || urlRef || null;
return {
type: 'url',
cloneUrl,
subdir,
localPath: null,
version,
rawInput: trimmedRaw,
cacheKey,
displayName,
isValid: true,
error: null,
};
}
// Precedence: explicit @version suffix > URL /tree/<ref> path segment.
const version = versionSuffix || urlRef || null;
return {
type: 'url',
cloneUrl,
subdir,
localPath: null,
version,
rawInput: trimmedRaw,
cacheKey: `${host}/${owner}/${repo}`,
displayName: `${owner}/${repo}`,
isValid: true,
error: null,
};
}
return {
@ -356,7 +311,7 @@ class CustomModuleManager {
/**
* Clone a custom module repository to cache.
* Supports any Git host (GitHub, GitLab, Bitbucket, self-hosted, etc.).
* @param {string} sourceInput - Git URL (HTTPS, HTTP, or SSH)
* @param {string} sourceInput - Git URL (HTTPS or SSH)
* @param {Object} [options] - Clone options
* @param {boolean} [options.silent] - Suppress spinner output
* @param {boolean} [options.skipInstall] - Skip npm install (for browsing before user confirms)

Some files were not shown because too many files have changed in this diff Show More