feat(bmad-spec): introduce Spec kernel distiller skill (#2417)
* feat(bmad-spec): add Spec kernel distiller skill
New 2-plan-workflows skill that distills any intent input (brain dump,
PRD, transcript, brief) into a spec.md carrying the five-field kernel:
Problem, Capabilities, Constraints, Non-goals, Success signal. Headless
callers receive JSON; interactive runs close conversationally with the
spec path and gap-coverage invitations.
Includes:
- SKILL.md with activation contract and conventions
- customize.toml exposing template path, output path, run-folder pattern
- assets/spec-template.md (five-field skeleton)
- assets/headless-schemas.md (JSON IO contracts)
* remove brain-dump fallback config from bmad-spec customize.toml
* refactor(bmad-spec): companions+sources model, routing tilt, flat output path
- Collapse `related:` into `companions:`; companion paths may point inside the spec folder (spec-authored) or outside it (adopted from an upstream skill), distinguished implicitly by path
- `sources:` reserved for fully-absorbed inputs; downstream does NOT read these
- Soften mutation contract: bmad-spec owns SPEC.md and spec-authored companions; adopted companions belong to their originating skill
- Add "when to spawn a companion" tilt: multi-item catalogs, tables, diagrams (always), editorial voice rules; sub-bullets in a kernel field signal it has outgrown the kernel
- Fix Spec Law rule 7 and Pass 2: load-bearing content lands in SPEC.md or a companion, not the decision log (the log records wrapper-drops only)
- Flatten output path to `{planning_artifacts}/specs/spec-{slug}-{date}/`, mirroring `prds/` and `ux-designs/`; drop `spec_folder_name` (no longer used)
- Extract Load-bearing definition into its own section above Spec Law
* chore(core): retire bmad-distillator, promote bmad-spec to core
- Delete bmad-distillator/ and all registry + doc references (superseded by bmad-spec; no skill or workflow in any BMad module invoked it)
- Add bmad-distillator to removals.txt so installer cleans it from existing IDE skill directories on update
- Move bmad-spec from bmm-skills/2-plan-workflows/ to core-skills/ (universal scope: game design, research hypotheses, editorial briefs, policy, business plans, not just software)
- Register bmad-spec in core module-help.csv and bmad-pro-skills marketplace plugin
- Drop bmad-distillator section from core-tools.md (en, vi-vn, cs, fr, zh-cn) and vi-vn dev guide; renumber subsequent sections
* refactor(bmad-spec): add lean-prose discipline + generalize help text
- Add Spec Law rule 8: lean prose. Every sentence carries load-bearing content; cut decoration, hedges, backstory, throat-clearing. Applies to SPEC.md, companions, and decision log.
- Update Self-Validate Pass 1 to enforce rules 1-6 and 8 (rule 7 stays in Pass 2)
- Prime the operation up-front: write lean from the first pass, every sentence must earn its place
- Note in Companions section that companions follow the same lean discipline
- Generalize core module-help.csv entry: domain-agnostic framing (software, game design, research, editorial, policy, business, anything intent-bearing); call out succinct, no-fluff and "locks the WHAT before the HOW" as the value props
* fix(bmad-spec): address PR review findings (CodeRabbit + Augment)
- headless-schemas.md: rewrite spec_path examples to point at the spec folder (not a file), rename source_artifact to sources[] array, add companions[] array, update verdict from "six rules" to "eight rules", disambiguate reason requirement (only when status=blocked)
- SKILL.md activation: fix config path from {project-root}/_bmad/config.yaml to {project-root}/_bmad/core/config.yaml (matches other BMM skills)
- customize.toml + SKILL.md Workspace: drop {date} from default run_folder_pattern (spec-{slug}); same slug = same folder = trivial in-place update, no glob-and-pick-most-recent needed. Override available for users who want dated history.
- spec-template.md: rename "## Success signals" (plural) to "## Success signal" (singular) to match SKILL.md kernel naming
- SKILL.md Frontmatter conventions: fix adopted-companion example path from _bmad-output/ux-designs/foo-ux/DESIGN.md to ../../ux-designs/ux-foo-bar-2026-05-23/DESIGN.md (matches actual flat-output convention)
- SKILL.md Spec Law: fix double-period typo in rule 2 ((stack, conventions)..)
- SKILL.md Overview: fix awkward "bloat with expansive line item details the kernel" phrasing; drop software-flavored downstream consumer list since bmad-spec is now a core skill serving any domain
* fix(bmad-spec): drop {planning_artifacts} dependency; output to {output_folder}/specs
bmad-spec is a core skill but its default path used {planning_artifacts}, a bmm-module variable. Core-only installs (no bmm) would fail at activation when the resolver tried to expand the path.
Land specs directly under {output_folder}/specs/spec-{slug}/ instead. Works in any install regardless of installed modules, and aligns with the long-term BMad direction of grouping artifacts as siblings under {output_folder}/<type>/ rather than nested under planning vs implementation parents.
In bmm installs, adopted-companion paths from spec to UX/PRD pick up one extra .. (e.g., ../planning-artifacts/ux-designs/<run>/DESIGN.md) since the spec folder is now one level up from planning-artifacts. Examples in SKILL.md and headless-schemas.md updated. module-help.csv output-location updated and stale -{date} fragment removed.
* docs(bmad-spec): add reference docs, trim headless schema, tighten defaults
- Add full bmad-spec entry to docs/reference/core-tools.md and table-row
stubs to cs/fr/vi-vn/zh-cn (full translation pending).
- Strip headless-schemas.md to a minimal {status, files} success response
and {status, error_code, reason} blocked response. Drop spec_path,
capabilities, verdict, decision_log_path — all derivable from the files
themselves.
- Narrow customize.toml persistent_facts default from recursive glob to
single {project-root}/project-context.md; document override path.
- Drop unused {doc_workspace} convention line from SKILL.md.
- Clarify Self-Validate verdict handling for interactive vs headless.
- Document missing_slug error code in SKILL.md + headless schema.
This commit is contained in:
parent
ee47e30cf6
commit
aa6dece05d
|
|
@ -20,7 +20,7 @@
|
||||||
"skills": [
|
"skills": [
|
||||||
"./src/core-skills/bmad-help",
|
"./src/core-skills/bmad-help",
|
||||||
"./src/core-skills/bmad-brainstorming",
|
"./src/core-skills/bmad-brainstorming",
|
||||||
"./src/core-skills/bmad-distillator",
|
"./src/core-skills/bmad-spec",
|
||||||
"./src/core-skills/bmad-party-mode",
|
"./src/core-skills/bmad-party-mode",
|
||||||
"./src/core-skills/bmad-shard-doc",
|
"./src/core-skills/bmad-shard-doc",
|
||||||
"./src/core-skills/bmad-advanced-elicitation",
|
"./src/core-skills/bmad-advanced-elicitation",
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ Spusťte jakýkoli základní nástroj zadáním jeho názvu skillu (např. `bma
|
||||||
| [`bmad-help`](#bmad-help) | Task | Kontextové poradenství, co dělat dál |
|
| [`bmad-help`](#bmad-help) | Task | Kontextové poradenství, co dělat dál |
|
||||||
| [`bmad-brainstorming`](#bmad-brainstorming) | Workflow | Facilitace interaktivních brainstormingových sezení |
|
| [`bmad-brainstorming`](#bmad-brainstorming) | Workflow | Facilitace interaktivních brainstormingových sezení |
|
||||||
| [`bmad-party-mode`](#bmad-party-mode) | Workflow | Orchestrace skupinových diskuzí více agentů |
|
| [`bmad-party-mode`](#bmad-party-mode) | Workflow | Orchestrace skupinových diskuzí více agentů |
|
||||||
| [`bmad-distillator`](#bmad-distillator) | Task | Bezeztrátová LLM-optimalizovaná komprese dokumentů |
|
| [`bmad-spec`](#bmad-spec) | Workflow | Distill any intent input into a SPEC kernel and companions, the canonical contract for downstream work (translation pending) |
|
||||||
| [`bmad-advanced-elicitation`](#bmad-advanced-elicitation) | Task | Iterativní zdokonalování LLM výstupu |
|
| [`bmad-advanced-elicitation`](#bmad-advanced-elicitation) | Task | Iterativní zdokonalování LLM výstupu |
|
||||||
| [`bmad-review-adversarial-general`](#bmad-review-adversarial-general) | Task | Cynická revize hledající chybějící a chybné |
|
| [`bmad-review-adversarial-general`](#bmad-review-adversarial-general) | Task | Cynická revize hledající chybějící a chybné |
|
||||||
| [`bmad-review-edge-case-hunter`](#bmad-review-edge-case-hunter) | Task | Vyčerpávající analýza větvících cest pro neošetřené hraniční případy |
|
| [`bmad-review-edge-case-hunter`](#bmad-review-edge-case-hunter) | Task | Vyčerpávající analýza větvících cest pro neošetřené hraniční případy |
|
||||||
|
|
@ -97,32 +97,6 @@ Kouzlo se děje v nápadech 50–100. Workflow povzbuzuje generování 100+ náp
|
||||||
|
|
||||||
**Výstup:** Real-time multi-agentní konverzace s udržovanými osobnostmi agentů
|
**Výstup:** Real-time multi-agentní konverzace s udržovanými osobnostmi agentů
|
||||||
|
|
||||||
## bmad-distillator
|
|
||||||
|
|
||||||
**Bezeztrátová LLM-optimalizovaná komprese zdrojových dokumentů.** — Produkuje husté, tokenově efektivní destiláty, které zachovávají všechny informace pro následné LLM zpracování. Ověřitelné prostřednictvím round-trip rekonstrukce.
|
|
||||||
|
|
||||||
**Použijte když:**
|
|
||||||
|
|
||||||
- Dokument je příliš velký pro kontextové okno LLM
|
|
||||||
- Potřebujete tokenově efektivní verze výzkumů, specifikací nebo plánovacích artefaktů
|
|
||||||
- Chcete ověřit, že během komprese nebyly ztraceny žádné informace
|
|
||||||
|
|
||||||
**Jak to funguje:**
|
|
||||||
|
|
||||||
1. **Analýza** — Čte zdrojové dokumenty, identifikuje hustotu informací a strukturu
|
|
||||||
2. **Komprese** — Převádí prózu na hustý odrážkový formát, odstraňuje dekorativní formátování
|
|
||||||
3. **Ověření** — Kontroluje úplnost pro zajištění zachování všech informací
|
|
||||||
4. **Validace** (volitelné) — Round-trip rekonstrukční test dokazuje bezeztrátovou kompresi
|
|
||||||
|
|
||||||
**Vstup:**
|
|
||||||
|
|
||||||
- `source_documents` (povinné) — Cesty k souborům, složkám nebo glob vzory
|
|
||||||
- `downstream_consumer` (volitelné) — Co to konzumuje (např. „tvorba PRD“)
|
|
||||||
- `token_budget` (volitelné) — Přibližná cílová velikost
|
|
||||||
- `--validate` (příznak) — Spuštění round-trip rekonstrukčního testu
|
|
||||||
|
|
||||||
**Výstup:** Destilátové markdown soubory s reportem kompresního poměru (např. „3.2:1“)
|
|
||||||
|
|
||||||
## bmad-advanced-elicitation
|
## bmad-advanced-elicitation
|
||||||
|
|
||||||
**Iterativní zdokonalování LLM výstupu metodami elicitace.** — Vybírá z knihovny elicitačních technik pro systematické zlepšování obsahu více průchody.
|
**Iterativní zdokonalování LLM výstupu metodami elicitace.** — Vybírá z knihovny elicitačních technik pro systematické zlepšování obsahu více průchody.
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ Exécutez n'importe quel outil principal en tapant son nom de compétence (par e
|
||||||
| [`bmad-help`](#bmad-help) | Tâche | Obtenir des conseils contextuels sur la prochaine étape |
|
| [`bmad-help`](#bmad-help) | Tâche | Obtenir des conseils contextuels sur la prochaine étape |
|
||||||
| [`bmad-brainstorming`](#bmad-brainstorming) | Workflow | Faciliter des sessions de brainstorming interactives |
|
| [`bmad-brainstorming`](#bmad-brainstorming) | Workflow | Faciliter des sessions de brainstorming interactives |
|
||||||
| [`bmad-party-mode`](#bmad-party-mode) | Workflow | Orchestrer des discussions de groupe multi-agents |
|
| [`bmad-party-mode`](#bmad-party-mode) | Workflow | Orchestrer des discussions de groupe multi-agents |
|
||||||
| [`bmad-distillator`](#bmad-distillator) | Tâche | Compression sans perte optimisée pour LLM de documents |
|
| [`bmad-spec`](#bmad-spec) | Workflow | Distill any intent input into a SPEC kernel and companions (translation pending) |
|
||||||
| [`bmad-advanced-elicitation`](#bmad-advanced-elicitation) | Tâche | Pousser la sortie LLM à travers des méthodes de raffinement itératives |
|
| [`bmad-advanced-elicitation`](#bmad-advanced-elicitation) | Tâche | Pousser la sortie LLM à travers des méthodes de raffinement itératives |
|
||||||
| [`bmad-review-adversarial-general`](#bmad-review-adversarial-general) | Tâche | Revue cynique qui trouve ce qui manque et ce qui ne va pas |
|
| [`bmad-review-adversarial-general`](#bmad-review-adversarial-general) | Tâche | Revue cynique qui trouve ce qui manque et ce qui ne va pas |
|
||||||
| [`bmad-review-edge-case-hunter`](#bmad-review-edge-case-hunter) | Tâche | Analyse exhaustive des chemins de branchement pour les cas limites non gérés |
|
| [`bmad-review-edge-case-hunter`](#bmad-review-edge-case-hunter) | Tâche | Analyse exhaustive des chemins de branchement pour les cas limites non gérés |
|
||||||
|
|
@ -97,33 +97,6 @@ La magie se produit dans les idées 50–100. Le workflow encourage la générat
|
||||||
|
|
||||||
**Sortie :** Conversation multi-agents en temps réel avec des personnalités d'agents maintenues
|
**Sortie :** Conversation multi-agents en temps réel avec des personnalités d'agents maintenues
|
||||||
|
|
||||||
## bmad-distillator
|
|
||||||
|
|
||||||
**Compression sans perte optimisée pour LLM de documents sources.** — Produit des distillats denses et efficaces en tokens qui préservent toute l'information pour la consommation par des LLM en aval. Vérifiable par reconstruction aller-retour.
|
|
||||||
|
|
||||||
**Utilisez-le quand :**
|
|
||||||
|
|
||||||
- Un document est trop volumineux pour la fenêtre de contexte d'un LLM
|
|
||||||
- Vous avez besoin de versions économes en tokens de recherches, spécifications ou artefacts de planification
|
|
||||||
- Vous voulez vérifier qu'aucune information n'est perdue pendant la compression
|
|
||||||
- Les agents auront besoin de référencer et de trouver fréquemment des informations dedans
|
|
||||||
|
|
||||||
**Fonctionnement :**
|
|
||||||
|
|
||||||
1. **Analyser** — Lit les documents sources, identifie la densité d'information et la structure
|
|
||||||
2. **Compresser** — Convertit la prose en format dense de liste de points, supprime le formatage décoratif
|
|
||||||
3. **Vérifier** — Vérifie l'exhaustivité pour s'assurer que toute l'information originale est préservée
|
|
||||||
4. **Valider** (optionnel) — Le test de reconstruction aller-retour prouve la compression sans perte
|
|
||||||
|
|
||||||
**Entrée :**
|
|
||||||
|
|
||||||
- `source_documents` (requis) — Chemins de fichiers, chemins de dossiers ou motifs glob
|
|
||||||
- `downstream_consumer` (optionnel) — Ce qui va le consommer (par ex., "création de PRD")
|
|
||||||
- `token_budget` (optionnel) — Taille cible approximative
|
|
||||||
- `--validate` (drapeau) — Exécuter le test de reconstruction aller-retour
|
|
||||||
|
|
||||||
**Sortie :** Fichier(s) markdown distillé(s) avec rapport de ratio de compression (par ex., "3.2:1")
|
|
||||||
|
|
||||||
## bmad-advanced-elicitation
|
## bmad-advanced-elicitation
|
||||||
|
|
||||||
**Passer la sortie du LLM à travers des méthodes de raffinement itératives.** — Sélectionne depuis une bibliothèque de techniques d'élicitation pour améliorer systématiquement le contenu à travers multiples passages.
|
**Passer la sortie du LLM à travers des méthodes de raffinement itératives.** — Sélectionne depuis une bibliothèque de techniques d'élicitation pour améliorer systématiquement le contenu à travers multiples passages.
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ Run any core tool by typing its skill name (e.g., `bmad-help`) in your IDE. No a
|
||||||
| [`bmad-help`](#bmad-help) | Task | Get context-aware guidance on what to do next |
|
| [`bmad-help`](#bmad-help) | Task | Get context-aware guidance on what to do next |
|
||||||
| [`bmad-brainstorming`](#bmad-brainstorming) | Workflow | Facilitate interactive brainstorming sessions |
|
| [`bmad-brainstorming`](#bmad-brainstorming) | Workflow | Facilitate interactive brainstorming sessions |
|
||||||
| [`bmad-party-mode`](#bmad-party-mode) | Workflow | Orchestrate multi-agent group discussions |
|
| [`bmad-party-mode`](#bmad-party-mode) | Workflow | Orchestrate multi-agent group discussions |
|
||||||
| [`bmad-distillator`](#bmad-distillator) | Task | Lossless LLM-optimized compression of documents |
|
| [`bmad-spec`](#bmad-spec) | Workflow | Distill any intent input into a SPEC kernel and companions, the canonical contract for downstream work |
|
||||||
| [`bmad-advanced-elicitation`](#bmad-advanced-elicitation) | Task | Push LLM output through iterative refinement methods |
|
| [`bmad-advanced-elicitation`](#bmad-advanced-elicitation) | Task | Push LLM output through iterative refinement methods |
|
||||||
| [`bmad-review-adversarial-general`](#bmad-review-adversarial-general) | Task | Cynical review that finds what's missing and what's wrong |
|
| [`bmad-review-adversarial-general`](#bmad-review-adversarial-general) | Task | Cynical review that finds what's missing and what's wrong |
|
||||||
| [`bmad-review-edge-case-hunter`](#bmad-review-edge-case-hunter) | Task | Exhaustive branching-path analysis for unhandled edge cases |
|
| [`bmad-review-edge-case-hunter`](#bmad-review-edge-case-hunter) | Task | Exhaustive branching-path analysis for unhandled edge cases |
|
||||||
|
|
@ -97,32 +97,36 @@ The magic happens in ideas 50–100. The workflow encourages generating 100+ ide
|
||||||
|
|
||||||
**Output:** Real-time multi-agent conversation with maintained agent personalities
|
**Output:** Real-time multi-agent conversation with maintained agent personalities
|
||||||
|
|
||||||
## bmad-distillator
|
## bmad-spec
|
||||||
|
|
||||||
**Lossless LLM-optimized compression of source documents.** — Produces dense, token-efficient distillates that preserve all information for downstream LLM consumption. Verifiable through round-trip reconstruction.
|
**Distill any intent input into the canonical SPEC contract for downstream work.** Takes a brief, PRD, GDD, RFC, brain dump, transcript, UX folder, or mixed multi-source input and produces a `SPEC.md` carrying the five-field kernel (Why, Capabilities, Constraints, Non-goals, Success signal) plus companion files for load-bearing content that does not fit the kernel.
|
||||||
|
|
||||||
**Use it when:**
|
**Use it when:**
|
||||||
|
|
||||||
- A document is too large for an LLM's context window
|
- You need to lock the WHAT before the HOW for any kind of work (software, game design, research, editorial, policy, business).
|
||||||
- You need token-efficient versions of research, specs, or planning artifacts
|
- You want a LLM Optimized succinct, no-fluff contract that downstream skills can consume without re-reading every upstream artifact.
|
||||||
- You want to verify no information is lost during compression
|
- You want to validate or update an existing spec.
|
||||||
- Agents will need to frequently reference and find information in it
|
|
||||||
|
|
||||||
**How it works:**
|
**How it works:**
|
||||||
|
|
||||||
1. **Analyze** — Reads source documents, identifies information density and structure
|
1. Reads the input and any ancillary linked materials.
|
||||||
2. **Compress** — Converts prose to dense bullet-point format, strips decorative formatting
|
2. Distills into the five-field kernel using a configurable template; routes overflow into appropriately-named companions.
|
||||||
3. **Verify** — Checks completeness to ensure all original information is preserved
|
3. Runs a two-pass self-validate (coherence rules, then preservation of every load-bearing source claim).
|
||||||
4. **Validate** (optional) — Round-trip reconstruction test proves lossless compression
|
4. Writes `SPEC.md`, sibling companions, and a `.decision-log.md` under `{output_folder}/specs/spec-{slug}/`.
|
||||||
|
|
||||||
|
Spec Law enforces eight rules: capabilities carry both intent and success; intents are WHAT not HOW; constraints actually bend decisions; non-goals are explicit; success signals are concrete; capability IDs are stable; every load-bearing source claim is preserved; prose is lean.
|
||||||
|
|
||||||
**Input:**
|
**Input:**
|
||||||
|
|
||||||
- `source_documents` (required) — File paths, folder paths, or glob patterns
|
- `input` (required) — path or inline text. Vague idea, brain dump, PRD, GDD, RFC, brief, transcript, mockup folder, mixed multi-source.
|
||||||
- `downstream_consumer` (optional) — What consumes this (e.g., "PRD creation")
|
- `slug` (optional) — required only when input is sparse and no slug is derivable from a source filename.
|
||||||
- `token_budget` (optional) — Approximate target size
|
- `target_spec_path` (optional) — set to update an existing spec instead of creating a new one.
|
||||||
- `--validate` (flag) — Run round-trip reconstruction test
|
|
||||||
|
|
||||||
**Output:** Distillate markdown file(s) with compression ratio report (e.g., "3.2:1")
|
**Output:** Spec folder containing `SPEC.md`, any companion files, and a `.decision-log.md`. Headless callers receive a JSON response with the result status and the list of files written or modified.
|
||||||
|
|
||||||
|
:::note[Mutation contract]
|
||||||
|
`bmad-spec` is the only writer of `SPEC.md` and of spec-authored companions. Other skills produce their own native artifacts and invoke `bmad-spec` headless when they need to express intent as the canonical contract or propose updates.
|
||||||
|
:::
|
||||||
|
|
||||||
## bmad-advanced-elicitation
|
## bmad-advanced-elicitation
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -694,15 +694,7 @@ Review kiểu "devil's advocate" — giả định vấn đề luôn tồn tại
|
||||||
- Tìm những gì **còn thiếu**, không chỉ những gì sai
|
- Tìm những gì **còn thiếu**, không chỉ những gì sai
|
||||||
- Trực giao với Edge Case Hunter
|
- Trực giao với Edge Case Hunter
|
||||||
|
|
||||||
### 8.4. Distillator — Nén tài liệu cho LLM
|
### 8.4. Shard Large Documents — Tách file lớn
|
||||||
|
|
||||||
```bash
|
|
||||||
bmad-distillator
|
|
||||||
```
|
|
||||||
|
|
||||||
Khi tài liệu quá lớn (PRD dài, Architecture phức tạp), Distillator nén nội dung tối ưu cho LLM mà không mất thông tin quan trọng.
|
|
||||||
|
|
||||||
### 8.5. Shard Large Documents — Tách file lớn
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bmad-shard-doc
|
bmad-shard-doc
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ Chạy bất kỳ công cụ cốt lõi nào bằng cách gõ tên skill của n
|
||||||
| [`bmad-help`](#bmad-help) | Tác vụ | Nhận hướng dẫn có ngữ cảnh về việc nên làm gì tiếp theo |
|
| [`bmad-help`](#bmad-help) | Tác vụ | Nhận hướng dẫn có ngữ cảnh về việc nên làm gì tiếp theo |
|
||||||
| [`bmad-brainstorming`](#bmad-brainstorming) | Quy trình | Tổ chức các phiên brainstorming có tương tác |
|
| [`bmad-brainstorming`](#bmad-brainstorming) | Quy trình | Tổ chức các phiên brainstorming có tương tác |
|
||||||
| [`bmad-party-mode`](#bmad-party-mode) | Quy trình | Điều phối thảo luận nhóm nhiều agent |
|
| [`bmad-party-mode`](#bmad-party-mode) | Quy trình | Điều phối thảo luận nhóm nhiều agent |
|
||||||
| [`bmad-distillator`](#bmad-distillator) | Tác vụ | Nén tài liệu tối ưu cho LLM mà không mất thông tin |
|
| [`bmad-spec`](#bmad-spec) | Quy trình | Distill any intent input into a SPEC kernel and companions, the canonical contract for downstream work (translation pending) |
|
||||||
| [`bmad-advanced-elicitation`](#bmad-advanced-elicitation) | Tác vụ | Đẩy đầu ra của LLM qua các vòng tinh luyện lặp |
|
| [`bmad-advanced-elicitation`](#bmad-advanced-elicitation) | Tác vụ | Đẩy đầu ra của LLM qua các vòng tinh luyện lặp |
|
||||||
| [`bmad-review-adversarial-general`](#bmad-review-adversarial-general) | Tác vụ | Rà soát hoài nghi để tìm chỗ thiếu và chỗ sai |
|
| [`bmad-review-adversarial-general`](#bmad-review-adversarial-general) | Tác vụ | Rà soát hoài nghi để tìm chỗ thiếu và chỗ sai |
|
||||||
| [`bmad-review-edge-case-hunter`](#bmad-review-edge-case-hunter) | Tác vụ | Phân tích toàn bộ nhánh rẽ để tìm trường hợp biên chưa được xử lý |
|
| [`bmad-review-edge-case-hunter`](#bmad-review-edge-case-hunter) | Tác vụ | Phân tích toàn bộ nhánh rẽ để tìm trường hợp biên chưa được xử lý |
|
||||||
|
|
@ -97,33 +97,6 @@ Chạy bất kỳ công cụ cốt lõi nào bằng cách gõ tên skill của n
|
||||||
|
|
||||||
**Đầu ra:** Cuộc hội thoại nhiều agent theo thời gian thực, vẫn giữ nguyên cá tính từng agent
|
**Đầu ra:** Cuộc hội thoại nhiều agent theo thời gian thực, vẫn giữ nguyên cá tính từng agent
|
||||||
|
|
||||||
## bmad-distillator
|
|
||||||
|
|
||||||
**Nén tài liệu nguồn tối ưu cho LLM mà không mất thông tin.** Công cụ này tạo ra các bản chưng cất dày đặc, tiết kiệm token nhưng vẫn giữ nguyên toàn bộ thông tin cho LLM dùng về sau. Có thể xác minh bằng tái dựng hai chiều.
|
|
||||||
|
|
||||||
**Dùng khi:**
|
|
||||||
|
|
||||||
- Một tài liệu quá lớn so với context window của LLM
|
|
||||||
- Bạn cần phiên bản tiết kiệm token của tài liệu nghiên cứu, đặc tả hoặc artifact lập kế hoạch
|
|
||||||
- Bạn muốn xác minh rằng không có thông tin nào bị mất trong quá trình nén
|
|
||||||
- Các agent sẽ cần tham chiếu và tìm thông tin trong đó thường xuyên
|
|
||||||
|
|
||||||
**Cách hoạt động:**
|
|
||||||
|
|
||||||
1. **Analyze** — Đọc tài liệu nguồn, nhận diện mật độ thông tin và cấu trúc
|
|
||||||
2. **Compress** — Chuyển văn xuôi thành dạng bullet dày đặc, bỏ trang trí không cần thiết
|
|
||||||
3. **Verify** — Kiểm tra tính đầy đủ để đảm bảo mọi thông tin gốc còn nguyên
|
|
||||||
4. **Validate** *(tùy chọn)* — Tái dựng hai chiều để chứng minh nén không mất mát
|
|
||||||
|
|
||||||
**Đầu vào:**
|
|
||||||
|
|
||||||
- `source_documents` *(bắt buộc)* — Đường dẫn file, thư mục hoặc mẫu glob
|
|
||||||
- `downstream_consumer` *(tùy chọn)* — Thành phần sẽ dùng đầu ra này, ví dụ "PRD creation"
|
|
||||||
- `token_budget` *(tùy chọn)* — Kích thước mục tiêu gần đúng
|
|
||||||
- `--validate` *(cờ)* — Chạy kiểm tra tái dựng hai chiều
|
|
||||||
|
|
||||||
**Đầu ra:** Một hoặc nhiều file markdown distillate kèm báo cáo tỷ lệ nén, ví dụ `3.2:1`
|
|
||||||
|
|
||||||
## bmad-advanced-elicitation
|
## bmad-advanced-elicitation
|
||||||
|
|
||||||
**Đẩy đầu ra của LLM qua các phương pháp tinh luyện lặp.** Công cụ này chọn từ thư viện kỹ thuật elicitation để cải thiện nội dung một cách có hệ thống qua nhiều lượt.
|
**Đẩy đầu ra của LLM qua các phương pháp tinh luyện lặp.** Công cụ này chọn từ thư viện kỹ thuật elicitation để cải thiện nội dung một cách có hệ thống qua nhiều lượt.
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ sidebar:
|
||||||
| [`bmad-help`](#bmad-help) | Task | 基于项目上下文推荐下一步 |
|
| [`bmad-help`](#bmad-help) | Task | 基于项目上下文推荐下一步 |
|
||||||
| [`bmad-brainstorming`](#bmad-brainstorming) | Workflow | 引导式头脑风暴与想法扩展 |
|
| [`bmad-brainstorming`](#bmad-brainstorming) | Workflow | 引导式头脑风暴与想法扩展 |
|
||||||
| [`bmad-party-mode`](#bmad-party-mode) | Workflow | 多智能体协作讨论 |
|
| [`bmad-party-mode`](#bmad-party-mode) | Workflow | 多智能体协作讨论 |
|
||||||
| [`bmad-distillator`](#bmad-distillator) | Task | 无损压缩文档,提升 LLM 消费效率 |
|
| [`bmad-spec`](#bmad-spec) | Workflow | Distill any intent input into a SPEC kernel and companions, the canonical contract for downstream work (translation pending) |
|
||||||
| [`bmad-advanced-elicitation`](#bmad-advanced-elicitation) | Task | 通过多轮技法增强 LLM 输出 |
|
| [`bmad-advanced-elicitation`](#bmad-advanced-elicitation) | Task | 通过多轮技法增强 LLM 输出 |
|
||||||
| [`bmad-review-adversarial-general`](#bmad-review-adversarial-general) | Task | 对抗式问题发现审查 |
|
| [`bmad-review-adversarial-general`](#bmad-review-adversarial-general) | Task | 对抗式问题发现审查 |
|
||||||
| [`bmad-review-edge-case-hunter`](#bmad-review-edge-case-hunter) | Task | 边界与分支路径穷举审查 |
|
| [`bmad-review-edge-case-hunter`](#bmad-review-edge-case-hunter) | Task | 边界与分支路径穷举审查 |
|
||||||
|
|
@ -80,29 +80,6 @@ sidebar:
|
||||||
**输入:** 讨论主题(可指定希望参与的角色)
|
**输入:** 讨论主题(可指定希望参与的角色)
|
||||||
**输出:** 多智能体实时对话过程
|
**输出:** 多智能体实时对话过程
|
||||||
|
|
||||||
## bmad-distillator
|
|
||||||
|
|
||||||
**定位:** 在不丢失信息前提下压缩文档,降低 token 成本。
|
|
||||||
|
|
||||||
**适用场景:**
|
|
||||||
- 源文档超过上下文窗口
|
|
||||||
- 需要把研究/规格材料转成高密度引用版本
|
|
||||||
- 想验证压缩结果是否可逆
|
|
||||||
|
|
||||||
**工作机制:**
|
|
||||||
1. 分析源文档结构与信息密度
|
|
||||||
2. 压缩为高密度结构化表达
|
|
||||||
3. 校验信息完整性
|
|
||||||
4. 可选执行往返重构验证(round-trip)
|
|
||||||
|
|
||||||
**输入:**
|
|
||||||
- `source_documents`(必填)
|
|
||||||
- `downstream_consumer`(可选)
|
|
||||||
- `token_budget`(可选)
|
|
||||||
- `--validate`(可选标志)
|
|
||||||
|
|
||||||
**输出:** 精馏文档 + 压缩比报告
|
|
||||||
|
|
||||||
## bmad-advanced-elicitation
|
## bmad-advanced-elicitation
|
||||||
|
|
||||||
**定位:** 对已有 LLM 输出做第二轮深挖与改写强化。
|
**定位:** 对已有 LLM 输出做第二轮深挖与改写强化。
|
||||||
|
|
|
||||||
|
|
@ -52,3 +52,8 @@ bmad-bmm-sprint-planning
|
||||||
bmad-bmm-sprint-status
|
bmad-bmm-sprint-status
|
||||||
bmad-bmm-technical-research
|
bmad-bmm-technical-research
|
||||||
bmad-bmm-validate-prd
|
bmad-bmm-validate-prd
|
||||||
|
|
||||||
|
# Removed skills (post-v6.7.x)
|
||||||
|
# bmad-distillator: superseded by bmad-spec (universal intent distiller with
|
||||||
|
# preservation-validated contract for downstream skills).
|
||||||
|
bmad-distillator
|
||||||
|
|
|
||||||
|
|
@ -1,177 +0,0 @@
|
||||||
---
|
|
||||||
name: bmad-distillator
|
|
||||||
description: Lossless LLM-optimized compression of source documents. Use when the user requests to 'distill documents' or 'create a distillate'.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Distillator: A Document Distillation Engine
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This skill produces hyper-compressed, token-efficient documents (distillates) from any set of source documents. A distillate preserves every fact, decision, constraint, and relationship from the sources while stripping all overhead that humans need and LLMs don't. Act as an information extraction and compression specialist. The output is a single dense document (or semantically-split set) that a downstream LLM workflow can consume as sole context input without information loss.
|
|
||||||
|
|
||||||
This is a compression task, not a summarization task. Summaries are lossy. Distillates are lossless compression optimized for LLM consumption.
|
|
||||||
|
|
||||||
## On Activation
|
|
||||||
|
|
||||||
1. **Validate inputs.** The caller must provide:
|
|
||||||
- **source_documents** (required) — One or more file paths, folder paths, or glob patterns to distill
|
|
||||||
- **downstream_consumer** (optional) — What workflow/agent consumes this distillate (e.g., "PRD creation", "architecture design"). When provided, use it to judge signal vs noise. When omitted, preserve everything.
|
|
||||||
- **token_budget** (optional) — Approximate target size. When provided and the distillate would exceed it, trigger semantic splitting.
|
|
||||||
- **output_path** (optional) — Where to save. When omitted, save adjacent to the primary source document with `-distillate.md` suffix.
|
|
||||||
- **--validate** (flag) — Run round-trip reconstruction test after producing the distillate.
|
|
||||||
|
|
||||||
2. **Route** — proceed to Stage 1.
|
|
||||||
|
|
||||||
## Stages
|
|
||||||
|
|
||||||
| # | Stage | Purpose |
|
|
||||||
|---|-------|---------|
|
|
||||||
| 1 | Analyze | Run analysis script, determine routing and splitting |
|
|
||||||
| 2 | Compress | Spawn compressor agent(s) to produce the distillate |
|
|
||||||
| 3 | Verify & Output | Completeness check, format check, save output |
|
|
||||||
| 4 | Round-Trip Validate | (--validate only) Reconstruct and diff against originals |
|
|
||||||
|
|
||||||
### Stage 1: Analyze
|
|
||||||
|
|
||||||
Run `scripts/analyze_sources.py --help` then run it with the source paths. Use its routing recommendation and grouping output to drive Stage 2. Do NOT read the source documents yourself.
|
|
||||||
|
|
||||||
### Stage 2: Compress
|
|
||||||
|
|
||||||
**Single mode** (routing = `"single"`, ≤3 files, ≤15K estimated tokens):
|
|
||||||
|
|
||||||
Spawn one subagent using `agents/distillate-compressor.md` with all source file paths.
|
|
||||||
|
|
||||||
**Fan-out mode** (routing = `"fan-out"`):
|
|
||||||
|
|
||||||
1. Spawn one compressor subagent per group from the analysis output. Each compressor receives only its group's file paths and produces an intermediate distillate.
|
|
||||||
|
|
||||||
2. After all compressors return, spawn one final **merge compressor** subagent using `agents/distillate-compressor.md`. Pass it the intermediate distillate contents as its input (not the original files). Its job is cross-group deduplication, thematic regrouping, and final compression.
|
|
||||||
|
|
||||||
3. Clean up intermediate distillate content (it exists only in memory, not saved to disk).
|
|
||||||
|
|
||||||
**Graceful degradation:** If subagent spawning is unavailable, read the source documents and perform the compression work directly using the same instructions from `agents/distillate-compressor.md`. For fan-out, process groups sequentially then merge.
|
|
||||||
|
|
||||||
The compressor returns a structured JSON result containing the distillate content, source headings, named entities, and token estimate.
|
|
||||||
|
|
||||||
### Stage 3: Verify & Output
|
|
||||||
|
|
||||||
After the compressor (or merge compressor) returns:
|
|
||||||
|
|
||||||
1. **Completeness check.** Using the headings and named entities list returned by the compressor, verify each appears in the distillate content. If gaps are found, send them back to the compressor for a targeted fix pass — not a full recompression. Limit to 2 fix passes maximum.
|
|
||||||
|
|
||||||
2. **Format check.** Verify the output follows distillate format rules:
|
|
||||||
- No prose paragraphs (only bullets)
|
|
||||||
- No decorative formatting
|
|
||||||
- No repeated information
|
|
||||||
- Each bullet is self-contained
|
|
||||||
- Themes are clearly delineated with `##` headings
|
|
||||||
|
|
||||||
3. **Determine output format.** Using the split prediction from Stage 1 and actual distillate size:
|
|
||||||
|
|
||||||
**Single distillate** (≤~5,000 tokens or token_budget not exceeded):
|
|
||||||
|
|
||||||
Save as a single file with frontmatter:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
---
|
|
||||||
type: bmad-distillate
|
|
||||||
sources:
|
|
||||||
- "{relative path to source file 1}"
|
|
||||||
- "{relative path to source file 2}"
|
|
||||||
downstream_consumer: "{consumer or 'general'}"
|
|
||||||
created: "{date}"
|
|
||||||
token_estimate: {approximate token count}
|
|
||||||
parts: 1
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
**Split distillate** (>~5,000 tokens, or token_budget requires it):
|
|
||||||
|
|
||||||
Create a folder `{base-name}-distillate/` containing:
|
|
||||||
|
|
||||||
```
|
|
||||||
{base-name}-distillate/
|
|
||||||
├── _index.md # Orientation, cross-cutting items, section manifest
|
|
||||||
├── 01-{topic-slug}.md # Self-contained section
|
|
||||||
├── 02-{topic-slug}.md
|
|
||||||
└── 03-{topic-slug}.md
|
|
||||||
```
|
|
||||||
|
|
||||||
The `_index.md` contains:
|
|
||||||
- Frontmatter with sources (relative paths from the distillate folder to the originals)
|
|
||||||
- 3-5 bullet orientation (what was distilled, from what)
|
|
||||||
- Section manifest: each section's filename + 1-line description
|
|
||||||
- Cross-cutting items that span multiple sections
|
|
||||||
|
|
||||||
Each section file is self-contained — loadable independently. Include a 1-line context header: "This section covers [topic]. Part N of M."
|
|
||||||
|
|
||||||
Source paths in frontmatter must be relative to the distillate's location.
|
|
||||||
|
|
||||||
4. **Measure distillate.** Run `scripts/analyze_sources.py` on the final distillate file(s) to get accurate token counts for the output. Use the `total_estimated_tokens` from this analysis as `distillate_total_tokens`.
|
|
||||||
|
|
||||||
5. **Report results.** Always return structured JSON output:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"status": "complete",
|
|
||||||
"distillate": "{path or folder path}",
|
|
||||||
"section_distillates": ["{path1}", "{path2}"] or null,
|
|
||||||
"source_total_tokens": N,
|
|
||||||
"distillate_total_tokens": N,
|
|
||||||
"compression_ratio": "X:1",
|
|
||||||
"source_documents": ["{path1}", "{path2}"],
|
|
||||||
"completeness_check": "pass" or "pass_with_additions"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Where `source_total_tokens` is from the Stage 1 analysis and `distillate_total_tokens` is from step 4. The `compression_ratio` is `source_total_tokens / distillate_total_tokens` formatted as "X:1" (e.g., "3.2:1").
|
|
||||||
|
|
||||||
6. If `--validate` flag was set, proceed to Stage 4. Otherwise, done.
|
|
||||||
|
|
||||||
### Stage 4: Round-Trip Validation (--validate only)
|
|
||||||
|
|
||||||
This stage proves the distillate is lossless by reconstructing source documents from the distillate alone. Use for critical documents where information loss is unacceptable, or as a quality gate for high-stakes downstream workflows. Not for routine use — it adds significant token cost.
|
|
||||||
|
|
||||||
1. **Spawn the reconstructor agent** using `agents/round-trip-reconstructor.md`. Pass it ONLY the distillate file path (or `_index.md` path for split distillates) — it must NOT have access to the original source documents.
|
|
||||||
|
|
||||||
For split distillates, spawn one reconstructor per section in parallel. Each receives its section file plus the `_index.md` for cross-cutting context.
|
|
||||||
|
|
||||||
**Graceful degradation:** If subagent spawning is unavailable, this stage cannot be performed by the main agent (it has already seen the originals). Report that round-trip validation requires subagent support and skip.
|
|
||||||
|
|
||||||
2. **Receive reconstructions.** The reconstructor returns reconstruction file paths saved adjacent to the distillate.
|
|
||||||
|
|
||||||
3. **Perform semantic diff.** Read both the original source documents and the reconstructions. For each section of the original, assess:
|
|
||||||
- Is the core information present in the reconstruction?
|
|
||||||
- Are specific details preserved (numbers, names, decisions)?
|
|
||||||
- Are relationships and rationale intact?
|
|
||||||
- Did the reconstruction add anything not in the original? (indicates hallucination filling gaps)
|
|
||||||
|
|
||||||
4. **Produce validation report** saved adjacent to the distillate as `-validation-report.md`:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
---
|
|
||||||
type: distillate-validation
|
|
||||||
distillate: "{distillate path}"
|
|
||||||
sources: ["{source paths}"]
|
|
||||||
created: "{date}"
|
|
||||||
---
|
|
||||||
|
|
||||||
## Validation Summary
|
|
||||||
- Status: PASS | PASS_WITH_WARNINGS | FAIL
|
|
||||||
- Information preserved: {percentage estimate}
|
|
||||||
- Gaps found: {count}
|
|
||||||
- Hallucinations detected: {count}
|
|
||||||
|
|
||||||
## Gaps (information in originals but missing from reconstruction)
|
|
||||||
- {gap description} — Source: {which original}, Section: {where}
|
|
||||||
|
|
||||||
## Hallucinations (information in reconstruction not traceable to originals)
|
|
||||||
- {hallucination description} — appears to fill gap in: {section}
|
|
||||||
|
|
||||||
## Possible Gap Markers (flagged by reconstructor)
|
|
||||||
- {marker description}
|
|
||||||
```
|
|
||||||
|
|
||||||
5. **If gaps are found**, offer to run a targeted fix pass on the distillate — adding the missing information without full recompression. Limit to 2 fix passes maximum.
|
|
||||||
|
|
||||||
6. **Clean up** — delete the temporary reconstruction files after the report is generated.
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
# Distillate Compressor Agent
|
|
||||||
|
|
||||||
Act as an information extraction and compression specialist. Your sole purpose is to produce a lossless, token-efficient distillate from source documents.
|
|
||||||
|
|
||||||
You receive: source document file paths, an optional downstream_consumer context, and a splitting decision.
|
|
||||||
|
|
||||||
You must load and apply `../resources/compression-rules.md` before producing output. Reference `../resources/distillate-format-reference.md` for the expected output format.
|
|
||||||
|
|
||||||
## Compression Process
|
|
||||||
|
|
||||||
### Step 1: Read Sources
|
|
||||||
|
|
||||||
Read all source document files. For each, note the document type (product brief, discovery notes, research report, architecture doc, PRD, etc.) based on content and naming.
|
|
||||||
|
|
||||||
### Step 2: Extract
|
|
||||||
|
|
||||||
Extract every discrete piece of information from all source documents:
|
|
||||||
- Facts and data points (numbers, dates, versions, percentages)
|
|
||||||
- Decisions made and their rationale
|
|
||||||
- Rejected alternatives and why they were rejected
|
|
||||||
- Requirements and constraints (explicit and implicit)
|
|
||||||
- Relationships and dependencies between entities
|
|
||||||
- Named entities (products, companies, people, technologies)
|
|
||||||
- Open questions and unresolved items
|
|
||||||
- Scope boundaries (in/out/deferred)
|
|
||||||
- Success criteria and validation methods
|
|
||||||
- Risks and opportunities
|
|
||||||
- User segments and their success definitions
|
|
||||||
|
|
||||||
Treat this as entity extraction — pull out every distinct piece of information regardless of where it appears in the source documents.
|
|
||||||
|
|
||||||
### Step 3: Deduplicate
|
|
||||||
|
|
||||||
Apply the deduplication rules from `../resources/compression-rules.md`.
|
|
||||||
|
|
||||||
### Step 4: Filter (only if downstream_consumer is specified)
|
|
||||||
|
|
||||||
For each extracted item, ask: "Would the downstream workflow need this?"
|
|
||||||
- Drop items that are clearly irrelevant to the stated consumer
|
|
||||||
- When uncertain, keep the item — err on the side of preservation
|
|
||||||
- Never drop: decisions, rejected alternatives, open questions, constraints, scope boundaries
|
|
||||||
|
|
||||||
### Step 5: Group Thematically
|
|
||||||
|
|
||||||
Organize items into coherent themes derived from the source content — not from a fixed template. The themes should reflect what the documents are actually about.
|
|
||||||
|
|
||||||
Common groupings (use what fits, omit what doesn't, add what's needed):
|
|
||||||
- Core concept / problem / motivation
|
|
||||||
- Solution / approach / architecture
|
|
||||||
- Users / segments
|
|
||||||
- Technical decisions / constraints
|
|
||||||
- Scope boundaries (in/out/deferred)
|
|
||||||
- Competitive context
|
|
||||||
- Success criteria
|
|
||||||
- Rejected alternatives
|
|
||||||
- Open questions
|
|
||||||
- Risks and opportunities
|
|
||||||
|
|
||||||
### Step 6: Compress Language
|
|
||||||
|
|
||||||
For each item, apply the compression rules from `../resources/compression-rules.md`:
|
|
||||||
- Strip prose transitions and connective tissue
|
|
||||||
- Remove hedging and rhetoric
|
|
||||||
- Remove explanations of common knowledge
|
|
||||||
- Preserve specific details (numbers, names, versions, dates)
|
|
||||||
- Ensure the item is self-contained (understandable without reading the source)
|
|
||||||
- Make relationships explicit ("X because Y", "X blocks Y", "X replaces Y")
|
|
||||||
|
|
||||||
### Step 7: Format Output
|
|
||||||
|
|
||||||
Produce the distillate as dense thematically-grouped bullets:
|
|
||||||
- `##` headings for themes — no deeper heading levels needed
|
|
||||||
- `- ` bullets for items — every token must carry signal
|
|
||||||
- No decorative formatting (no bold for emphasis, no horizontal rules)
|
|
||||||
- No prose paragraphs — only bullets
|
|
||||||
- Semicolons to join closely related short items within a single bullet
|
|
||||||
- Each bullet self-contained — understandable without reading other bullets
|
|
||||||
|
|
||||||
Do NOT include frontmatter — the calling skill handles that.
|
|
||||||
|
|
||||||
## Semantic Splitting
|
|
||||||
|
|
||||||
If the splitting decision indicates splitting is needed, load `../resources/splitting-strategy.md` and follow it.
|
|
||||||
|
|
||||||
When splitting:
|
|
||||||
|
|
||||||
1. Identify natural semantic boundaries in the content — coherent topic clusters, not arbitrary size breaks.
|
|
||||||
|
|
||||||
2. Produce a **root distillate** containing:
|
|
||||||
- 3-5 bullet orientation (what was distilled, for whom, how many parts)
|
|
||||||
- Cross-references to section distillates
|
|
||||||
- Items that span multiple sections
|
|
||||||
|
|
||||||
3. Produce **section distillates**, each self-sufficient. Include a 1-line context header: "This section covers [topic]. Part N of M from [source document names]."
|
|
||||||
|
|
||||||
## Return Format
|
|
||||||
|
|
||||||
Return a structured result to the calling skill:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"distillate_content": "{the complete distillate text without frontmatter}",
|
|
||||||
"source_headings": ["heading 1", "heading 2"],
|
|
||||||
"source_named_entities": ["entity 1", "entity 2"],
|
|
||||||
"token_estimate": N,
|
|
||||||
"sections": null or [{"topic": "...", "content": "..."}]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- **distillate_content**: The full distillate text
|
|
||||||
- **source_headings**: All Level 2+ headings found across source documents (for completeness verification)
|
|
||||||
- **source_named_entities**: Key named entities (products, companies, people, technologies, decisions) found in sources
|
|
||||||
- **token_estimate**: Approximate token count of the distillate
|
|
||||||
- **sections**: null for single distillates; array of section objects if semantically split
|
|
||||||
|
|
||||||
Do not include conversational text, status updates, or preamble — return only the structured result.
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
# Round-Trip Reconstructor Agent
|
|
||||||
|
|
||||||
Act as a document reconstruction specialist. Your purpose is to prove a distillate's completeness by reconstructing the original source documents from the distillate alone.
|
|
||||||
|
|
||||||
**Critical constraint:** You receive ONLY the distillate file path. You must NOT have access to the original source documents. If you can see the originals, the test is meaningless.
|
|
||||||
|
|
||||||
## Process
|
|
||||||
|
|
||||||
### Step 1: Analyze the Distillate
|
|
||||||
|
|
||||||
Read the distillate file. Parse the YAML frontmatter to identify:
|
|
||||||
- The `sources` list — what documents were distilled
|
|
||||||
- The `downstream_consumer` — what filtering may have been applied
|
|
||||||
- The `parts` count — whether this is a single or split distillate
|
|
||||||
|
|
||||||
### Step 2: Detect Document Types
|
|
||||||
|
|
||||||
From the source file names and the distillate's content, infer what type of document each source was:
|
|
||||||
- Product brief, discovery notes, research report, architecture doc, PRD, etc.
|
|
||||||
- Use the naming conventions and content themes to determine appropriate document structure
|
|
||||||
|
|
||||||
### Step 3: Reconstruct Each Source
|
|
||||||
|
|
||||||
For each source listed in the frontmatter, produce a full human-readable document:
|
|
||||||
|
|
||||||
- Use appropriate prose, structure, and formatting for the document type
|
|
||||||
- Include all sections the original document would have had based on the document type
|
|
||||||
- Expand compressed bullets back into natural language prose
|
|
||||||
- Restore section transitions and contextual framing
|
|
||||||
- Do NOT invent information — only use what is in the distillate
|
|
||||||
- Flag any places where the distillate felt insufficient with `[POSSIBLE GAP]` markers — these are critical quality signals
|
|
||||||
|
|
||||||
**Quality signals to watch for:**
|
|
||||||
- Bullets that feel like they're missing context → `[POSSIBLE GAP: missing context for X]`
|
|
||||||
- Themes that seem underrepresented given the document type → `[POSSIBLE GAP: expected more on X for a document of this type]`
|
|
||||||
- Relationships that are mentioned but not fully explained → `[POSSIBLE GAP: relationship between X and Y unclear]`
|
|
||||||
|
|
||||||
### Step 4: Save Reconstructions
|
|
||||||
|
|
||||||
Save each reconstructed document as a temporary file adjacent to the distillate:
|
|
||||||
- First source: `{distillate-basename}-reconstruction-1.md`
|
|
||||||
- Second source: `{distillate-basename}-reconstruction-2.md`
|
|
||||||
- And so on for each source
|
|
||||||
|
|
||||||
Each reconstruction should include a header noting it was reconstructed:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
---
|
|
||||||
type: distillate-reconstruction
|
|
||||||
source_distillate: "{distillate path}"
|
|
||||||
reconstructed_from: "{original source name}"
|
|
||||||
reconstruction_number: {N}
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 5: Return
|
|
||||||
|
|
||||||
Return a structured result to the calling skill:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"reconstruction_files": ["{path1}", "{path2}"],
|
|
||||||
"possible_gaps": ["gap description 1", "gap description 2"],
|
|
||||||
"source_count": N
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Do not include conversational text, status updates, or preamble — return only the structured result.
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
# Compression Rules
|
|
||||||
|
|
||||||
These rules govern how source text is compressed into distillate format. Apply as a final pass over all output.
|
|
||||||
|
|
||||||
## Strip — Remove entirely
|
|
||||||
|
|
||||||
- Prose transitions: "As mentioned earlier", "It's worth noting", "In addition to this"
|
|
||||||
- Rhetoric and persuasion: "This is a game-changer", "The exciting thing is"
|
|
||||||
- Hedging: "We believe", "It's likely that", "Perhaps", "It seems"
|
|
||||||
- Self-reference: "This document describes", "As outlined above"
|
|
||||||
- Common knowledge explanations: "Vercel is a cloud platform company", "MIT is an open-source license", "JSON is a data interchange format"
|
|
||||||
- Repeated introductions of the same concept
|
|
||||||
- Section transition paragraphs
|
|
||||||
- Formatting-only elements (decorative bold/italic for emphasis, horizontal rules for visual breaks)
|
|
||||||
- Filler phrases: "In order to", "It should be noted that", "The fact that"
|
|
||||||
|
|
||||||
## Preserve — Keep always
|
|
||||||
|
|
||||||
- Specific numbers, dates, versions, percentages
|
|
||||||
- Named entities (products, companies, people, technologies)
|
|
||||||
- Decisions made and their rationale (compressed: "Decision: X. Reason: Y")
|
|
||||||
- Rejected alternatives and why (compressed: "Rejected: X. Reason: Y")
|
|
||||||
- Explicit constraints and non-negotiables
|
|
||||||
- Dependencies and ordering relationships
|
|
||||||
- Open questions and unresolved items
|
|
||||||
- Scope boundaries (in/out/deferred)
|
|
||||||
- Success criteria and how they're validated
|
|
||||||
- User segments and what success means for each
|
|
||||||
- Risks with their severity signals
|
|
||||||
- Conflicts between source documents
|
|
||||||
|
|
||||||
## Transform — Change form for efficiency
|
|
||||||
|
|
||||||
- Long prose paragraphs → single dense bullet capturing the same information
|
|
||||||
- "We decided to use X because Y and Z" → "X (rationale: Y, Z)"
|
|
||||||
- Repeated category labels → group under a single heading, no per-item labels
|
|
||||||
- "Risk: ... Severity: high" → "HIGH RISK: ..."
|
|
||||||
- Conditional statements → "If X → Y" form
|
|
||||||
- Multi-sentence explanations → semicolon-separated compressed form
|
|
||||||
- Lists of related short items → single bullet with semicolons
|
|
||||||
- "X is used for Y" → "X: Y" when context is clear
|
|
||||||
- Verbose enumerations → parenthetical lists: "platforms (Cursor, Claude Code, Windsurf, Copilot)"
|
|
||||||
|
|
||||||
## Deduplication Rules
|
|
||||||
|
|
||||||
- Same fact in multiple documents → keep the version with most context
|
|
||||||
- Same concept at different detail levels → keep the detailed version
|
|
||||||
- Overlapping lists → merge into single list, no duplicates
|
|
||||||
- When source documents disagree → note the conflict explicitly: "Brief says X; discovery notes say Y — unresolved"
|
|
||||||
- Executive summary points that are expanded elsewhere → keep only the expanded version
|
|
||||||
- Introductory framing repeated across sections → capture once under the most relevant theme
|
|
||||||
|
|
@ -1,227 +0,0 @@
|
||||||
# Distillate Format Reference
|
|
||||||
|
|
||||||
Examples showing the transformation from human-readable source content to distillate format.
|
|
||||||
|
|
||||||
## Frontmatter
|
|
||||||
|
|
||||||
Every distillate includes YAML frontmatter. Source paths are relative to the distillate's location so the distillate remains portable:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
---
|
|
||||||
type: bmad-distillate
|
|
||||||
sources:
|
|
||||||
- "product-brief-example.md"
|
|
||||||
- "product-brief-example-discovery-notes.md"
|
|
||||||
downstream_consumer: "PRD creation"
|
|
||||||
created: "2026-03-13"
|
|
||||||
token_estimate: 1200
|
|
||||||
parts: 1
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
## Before/After Examples
|
|
||||||
|
|
||||||
### Prose Paragraph to Dense Bullet
|
|
||||||
|
|
||||||
**Before** (human-readable brief excerpt):
|
|
||||||
```
|
|
||||||
## What Makes This Different
|
|
||||||
|
|
||||||
**The anti-fragmentation layer.** The AI tooling space is fracturing across 40+
|
|
||||||
platforms with no shared methodology layer. BMAD is uniquely positioned to be the
|
|
||||||
cross-platform constant — the structured approach that works the same in Cursor,
|
|
||||||
Claude Code, Windsurf, Copilot, and whatever launches next month. Every other
|
|
||||||
methodology or skill framework maintains its own platform support matrix. By
|
|
||||||
building on the open-source skills CLI ecosystem, BMAD offloads the highest-churn
|
|
||||||
maintenance burden and focuses on what actually differentiates it: the methodology
|
|
||||||
itself.
|
|
||||||
```
|
|
||||||
|
|
||||||
**After** (distillate):
|
|
||||||
```
|
|
||||||
## Differentiation
|
|
||||||
- Anti-fragmentation positioning: BMAD = cross-platform constant across 40+ fragmenting AI tools; no competitor provides shared methodology layer
|
|
||||||
- Platform complexity delegated to Vercel skills CLI ecosystem (MIT); BMAD maintains methodology, not platform configs
|
|
||||||
```
|
|
||||||
|
|
||||||
### Technical Details to Compressed Facts
|
|
||||||
|
|
||||||
**Before** (discovery notes excerpt):
|
|
||||||
```
|
|
||||||
## Competitive Landscape
|
|
||||||
|
|
||||||
- **Vercel Skills.sh**: 83K+ skills, 18 agents, largest curated leaderboard —
|
|
||||||
but dev-only, skills trigger unreliably (20% without explicit prompting)
|
|
||||||
- **SkillsMP**: 400K+ skills directory, pure aggregator with no curation or CLI
|
|
||||||
- **ClawHub/OpenClaw**: ~3.2K curated skills with versioning/rollback, small ecosystem
|
|
||||||
- **Lindy**: No-code AI agent builder for business automation — closed platform,
|
|
||||||
no skill sharing
|
|
||||||
- **Microsoft Copilot Studio**: Enterprise no-code agent builder — vendor-locked
|
|
||||||
to Microsoft
|
|
||||||
- **MindStudio**: No-code AI agent platform — siloed, no interoperability
|
|
||||||
- **Make/Zapier AI**: Workflow automation adding AI agents — workflow-centric,
|
|
||||||
not methodology-centric
|
|
||||||
- **Key gap**: NO competitor combines structured methodology with plugin
|
|
||||||
marketplace — this is BMAD's whitespace
|
|
||||||
```
|
|
||||||
|
|
||||||
**After** (distillate):
|
|
||||||
```
|
|
||||||
## Competitive Landscape
|
|
||||||
- No competitor combines structured methodology + plugin marketplace (whitespace)
|
|
||||||
- Skills.sh (Vercel): 83K skills, 18 agents, dev-only, 20% trigger reliability
|
|
||||||
- SkillsMP: 400K skills, aggregator only, no curation/CLI
|
|
||||||
- ClawHub: 3.2K curated, versioning, small ecosystem
|
|
||||||
- No-code platforms (Lindy, Copilot Studio, MindStudio, Make/Zapier): closed/siloed, no skill portability, business-only
|
|
||||||
```
|
|
||||||
|
|
||||||
### Deduplication Across Documents
|
|
||||||
|
|
||||||
When the same fact appears in both a brief and discovery notes:
|
|
||||||
|
|
||||||
**Brief says:**
|
|
||||||
```
|
|
||||||
bmad-help must always be included as a base skill in every bundle
|
|
||||||
```
|
|
||||||
|
|
||||||
**Discovery notes say:**
|
|
||||||
```
|
|
||||||
bmad-help must always be included as a base skill in every bundle/install
|
|
||||||
(solves discoverability problem)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Distillate keeps the more contextual version:**
|
|
||||||
```
|
|
||||||
- bmad-help: always included as base skill in every bundle (solves discoverability)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Decision/Rationale Compression
|
|
||||||
|
|
||||||
**Before:**
|
|
||||||
```
|
|
||||||
We decided not to build our own platform support matrix going forward, instead
|
|
||||||
delegating to the Vercel skills CLI ecosystem. The rationale is that maintaining
|
|
||||||
20+ platform configs is the biggest maintenance burden and it's unsustainable
|
|
||||||
at 40+ platforms.
|
|
||||||
```
|
|
||||||
|
|
||||||
**After:**
|
|
||||||
```
|
|
||||||
- Rejected: own platform support matrix. Reason: unsustainable at 40+ platforms; delegate to Vercel CLI ecosystem
|
|
||||||
```
|
|
||||||
|
|
||||||
## Full Example
|
|
||||||
|
|
||||||
A complete distillate produced from a product brief and its discovery notes, targeted at PRD creation:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
---
|
|
||||||
type: bmad-distillate
|
|
||||||
sources:
|
|
||||||
- "product-brief-bmad-next-gen-installer.md"
|
|
||||||
- "product-brief-bmad-next-gen-installer-discovery-notes.md"
|
|
||||||
downstream_consumer: "PRD creation"
|
|
||||||
created: "2026-03-13"
|
|
||||||
token_estimate: 1450
|
|
||||||
parts: 1
|
|
||||||
---
|
|
||||||
|
|
||||||
## Core Concept
|
|
||||||
- BMAD Next-Gen Installer: replaces monolithic Node.js CLI with skill-based plugin architecture for distributing BMAD methodology across 40+ AI platforms
|
|
||||||
- Three layers: self-describing plugins (bmad-manifest.json), cross-platform install via Vercel skills CLI (MIT), runtime registration via bmad-setup skill
|
|
||||||
- Transforms BMAD from dev-only methodology into open platform for any domain (creative, therapeutic, educational, personal)
|
|
||||||
|
|
||||||
## Problem
|
|
||||||
- Current installer maintains ~20 platform configs manually; each platform convention change requires installer update, test, release — largest maintenance burden on team
|
|
||||||
- Node.js/npm required — blocks non-technical users on UI-based platforms (Claude Co-Work, etc.)
|
|
||||||
- CSV manifests are static, generated once at install; no runtime scanning/registration
|
|
||||||
- Unsustainable at 40+ platforms; new tools launching weekly
|
|
||||||
|
|
||||||
## 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}]}`
|
|
||||||
- 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
|
|
||||||
- Distribution tiers: (1) NPX installer wrapping skills CLI for technical users, (2) zip bundle + platform-specific README for non-technical users, (3) future marketplace
|
|
||||||
- Non-technical path has honest friction: "copy to right folder" requires knowing where; per-platform README instructions; improves over time as low-code space matures
|
|
||||||
|
|
||||||
## Differentiation
|
|
||||||
- Anti-fragmentation: BMAD = cross-platform constant; no competitor provides shared methodology layer across AI tools
|
|
||||||
- Curated quality: all submissions gated, human-reviewed by BMad + core team; 13.4% of community skills have critical vulnerabilities (Snyk 2026); quality gate value increases as ecosystem gets noisier
|
|
||||||
- Domain-agnostic: no competitor builds beyond software dev workflows; same plugin system powers any domain via BMAD Builder (separate initiative)
|
|
||||||
|
|
||||||
## Users (ordered by v1 priority)
|
|
||||||
- Module authors (primary v1): package/test/distribute plugins independently without installer changes
|
|
||||||
- Developers: single-command install on any of 40+ platforms via NPX
|
|
||||||
- Non-technical users: install without Node/Git/terminal; emerging segment including PMs, designers, educators
|
|
||||||
- Future plugin creators: non-dev authors using BMAD Builder; need distribution without building own installer
|
|
||||||
|
|
||||||
## Success Criteria
|
|
||||||
- Zero (or near-zero) custom platform directory code; delegated to skills CLI ecosystem
|
|
||||||
- Installation verified on top platforms by volume; skills CLI handles long tail
|
|
||||||
- Non-technical install path validated with non-developer users
|
|
||||||
- bmad-setup discovers/registers all plugins from manifests; clear errors for malformed manifests
|
|
||||||
- At least one external module author successfully publishes plugin using manifest system
|
|
||||||
- bmad-update works without full reinstall
|
|
||||||
- Existing CLI users have documented migration path
|
|
||||||
|
|
||||||
## Scope
|
|
||||||
- In: manifest spec, bmad-setup, bmad-update, Vercel CLI integration, NPX installer, zip bundles, migration path
|
|
||||||
- Out: BMAD Builder, marketplace web platform, skill conversion (prerequisite, separate), one-click install for all platforms, monetization, quality certification process (gated-submission principle is architectural requirement; process defined separately)
|
|
||||||
- Deferred: CI/CD integration, telemetry for module authors, air-gapped enterprise install, zip bundle integrity verification (checksums/signing), deeper non-technical platform integrations
|
|
||||||
|
|
||||||
## Current Installer (migration context)
|
|
||||||
- Entry: `tools/installer/bmad-cli.js` (Commander.js) → `tools/installer/core/installer.js`
|
|
||||||
- Platforms: `platform-codes.yaml` (~20 platforms with target dirs, legacy dirs, template types, special flags)
|
|
||||||
- Manifests: skill-manifest.csv is the current source of truth; agent essence lives in `_bmad/config.toml` (generated from each module.yaml's `agents:` block)
|
|
||||||
- External modules: `external-official-modules.yaml` (CIS, GDS, TEA, WDS) from npm with semver
|
|
||||||
- Dependencies: 4-pass resolver (collect → parse → resolve → transitive); YAML-declared only
|
|
||||||
- Config: prompts for name, communication language, document output language, output folder
|
|
||||||
- Skills already use directory-per-skill layout; bmad-manifest.json sidecars exist but are not source of truth
|
|
||||||
- Key shift: CSV-based static manifests → JSON-based runtime scanning
|
|
||||||
|
|
||||||
## Vercel Skills CLI
|
|
||||||
- `npx skills add <source>` — GitHub, GitLab, local paths, git URLs
|
|
||||||
- 40+ agents; per-agent path mappings; symlinks (recommended) or copies
|
|
||||||
- Scopes: project-level or global
|
|
||||||
- Discovery: `skills/`, `.agents/skills/`, agent-specific paths, `.claude-plugin/marketplace.json`
|
|
||||||
- Commands: add, list, find, remove, check, update, init
|
|
||||||
- Non-interactive: `-y`, `--all` flags for CI/CD
|
|
||||||
|
|
||||||
## Competitive Landscape
|
|
||||||
- No competitor combines structured methodology + plugin marketplace (whitespace)
|
|
||||||
- Skills.sh (Vercel): 83K skills, dev-only, 20% trigger reliability without explicit prompting
|
|
||||||
- SkillsMP: 400K skills, aggregator only, no curation
|
|
||||||
- ClawHub: 3.2K curated, versioning, small
|
|
||||||
- No-code platforms (Lindy, Copilot Studio, MindStudio, Make/Zapier): closed/siloed, no skill portability, business-only
|
|
||||||
- Market: $7.84B (2025) → $52.62B (2030); Agent Skills spec ~4 months old, 351K+ skills; standards converging under Linux Foundation AAIF (MCP, AGENTS.md, A2A)
|
|
||||||
|
|
||||||
## Rejected Alternatives
|
|
||||||
- Building own platform support matrix: unsustainable at 40+; delegate to Vercel ecosystem
|
|
||||||
- One-click install for non-technical v1: emerging space; guidance-based, improve over time
|
|
||||||
- Prior roadmap/brainstorming: clean start, unconstrained by previous planning
|
|
||||||
|
|
||||||
## Open Questions
|
|
||||||
- Vercel CLI integration pattern: wrap/fork/call/peer dependency?
|
|
||||||
- bmad-update mechanics: diff/replace? Preserve user customizations?
|
|
||||||
- Migration story: command/manual reinstall/compatibility shim?
|
|
||||||
- Cross-platform testing: CI matrix for top N? Community testing for rest?
|
|
||||||
- bmad-manifest.json as open standard submission to Agent Skills governance?
|
|
||||||
- Platforms NOT supported by Vercel skills CLI?
|
|
||||||
- Manifest versioning strategy for backward compatibility?
|
|
||||||
- Plugin author getting-started experience and tooling?
|
|
||||||
|
|
||||||
## Opportunities
|
|
||||||
- Module authors as acquisition channel: each published plugin distributes BMAD to creator's audience
|
|
||||||
- CI/CD integration: bmad-setup as pipeline one-liner increases stickiness
|
|
||||||
- Educational institutions: structured methodology + non-technical install → university AI curriculum
|
|
||||||
- Skill composability: mixing BMAD modules with third-party skills for custom methodology stacks
|
|
||||||
|
|
||||||
## Risks
|
|
||||||
- Manifest format evolution creates versioning/compatibility burden once third-party authors publish
|
|
||||||
- Quality gate needs defined process, not just claim — gated review model addresses
|
|
||||||
- 40+ platform testing environments even with Vercel handling translation
|
|
||||||
- Scope creep pressure from marketplace vision (explicitly excluded but primary long-term value)
|
|
||||||
- Vercel dependency: minor supply-chain risk; MIT license allows fork if deprioritized
|
|
||||||
```
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
# Semantic Splitting Strategy
|
|
||||||
|
|
||||||
When the source content is large (exceeds ~15,000 tokens) or a token_budget requires it, split the distillate into semantically coherent sections rather than arbitrary size breaks.
|
|
||||||
|
|
||||||
## Why Semantic Over Size-Based
|
|
||||||
|
|
||||||
Arbitrary splits (every N tokens) break coherence. A downstream workflow loading "part 2 of 4" gets context fragments. Semantic splits produce self-contained topic clusters that a workflow can load selectively — "give me just the technical decisions section" — which is more useful and more token-efficient for the consumer.
|
|
||||||
|
|
||||||
## Splitting Process
|
|
||||||
|
|
||||||
### 1. Identify Natural Boundaries
|
|
||||||
|
|
||||||
After the initial extraction and deduplication (Steps 1-2 of the compression process), look for natural semantic boundaries:
|
|
||||||
- Distinct problem domains or functional areas
|
|
||||||
- Different stakeholder perspectives (users, technical, business)
|
|
||||||
- Temporal boundaries (current state vs future vision)
|
|
||||||
- Scope boundaries (in-scope vs out-of-scope vs deferred)
|
|
||||||
- Phase boundaries (analysis, design, implementation)
|
|
||||||
|
|
||||||
Choose boundaries that produce sections a downstream workflow might load independently.
|
|
||||||
|
|
||||||
### 2. Assign Items to Sections
|
|
||||||
|
|
||||||
For each extracted item, assign it to the most relevant section. Items that span multiple sections go in the root distillate.
|
|
||||||
|
|
||||||
Cross-cutting items (items relevant to multiple sections):
|
|
||||||
- Constraints that affect all areas → root distillate
|
|
||||||
- Decisions with broad impact → root distillate
|
|
||||||
- Section-specific decisions → section distillate
|
|
||||||
|
|
||||||
### 3. Produce Root Distillate
|
|
||||||
|
|
||||||
The root distillate contains:
|
|
||||||
- **Orientation** (3-5 bullets): what was distilled, from what sources, for what consumer, how many sections
|
|
||||||
- **Cross-references**: list of section distillates with 1-line descriptions
|
|
||||||
- **Cross-cutting items**: facts, decisions, and constraints that span multiple sections
|
|
||||||
- **Scope summary**: high-level in/out/deferred if applicable
|
|
||||||
|
|
||||||
### 4. Produce Section Distillates
|
|
||||||
|
|
||||||
Each section distillate must be self-sufficient — a reader loading only one section should understand it without the others.
|
|
||||||
|
|
||||||
Each section includes:
|
|
||||||
- **Context header** (1 line): "This section covers [topic]. Part N of M from [source document names]."
|
|
||||||
- **Section content**: thematically-grouped bullets following the same compression rules as a single distillate
|
|
||||||
- **Cross-references** (if needed): pointers to other sections for related content
|
|
||||||
|
|
||||||
### 5. Output Structure
|
|
||||||
|
|
||||||
Create a folder `{base-name}-distillate/` containing:
|
|
||||||
|
|
||||||
```
|
|
||||||
{base-name}-distillate/
|
|
||||||
├── _index.md # Root distillate: orientation, cross-cutting items, section manifest
|
|
||||||
├── 01-{topic-slug}.md # Self-contained section
|
|
||||||
├── 02-{topic-slug}.md
|
|
||||||
└── 03-{topic-slug}.md
|
|
||||||
```
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```
|
|
||||||
product-brief-distillate/
|
|
||||||
├── _index.md
|
|
||||||
├── 01-problem-solution.md
|
|
||||||
├── 02-technical-decisions.md
|
|
||||||
└── 03-users-market.md
|
|
||||||
```
|
|
||||||
|
|
||||||
## Size Targets
|
|
||||||
|
|
||||||
When a token_budget is specified:
|
|
||||||
- Root distillate: ~20% of budget (orientation + cross-cutting items)
|
|
||||||
- Remaining budget split proportionally across sections based on content density
|
|
||||||
- If a section exceeds its proportional share, compress more aggressively or sub-split
|
|
||||||
|
|
||||||
When no token_budget but splitting is needed:
|
|
||||||
- Aim for sections of 3,000-5,000 tokens each
|
|
||||||
- Root distillate as small as possible while remaining useful standalone
|
|
||||||
|
|
@ -1,300 +0,0 @@
|
||||||
# /// script
|
|
||||||
# /// requires-python = ">=3.10"
|
|
||||||
# /// dependencies = []
|
|
||||||
# ///
|
|
||||||
"""Analyze source documents for the distillation generator.
|
|
||||||
|
|
||||||
Enumerates files from paths/folders/globs, computes sizes and token estimates,
|
|
||||||
detects document types from naming conventions, and suggests groupings for
|
|
||||||
related documents (e.g., a brief paired with its discovery notes).
|
|
||||||
|
|
||||||
Accepts: file paths, folder paths (scans recursively for .md/.txt/.yaml/.yml/.json),
|
|
||||||
or glob patterns. Skips node_modules, .git, __pycache__, .venv, _bmad-output.
|
|
||||||
|
|
||||||
Output JSON structure:
|
|
||||||
status: "ok" | "error"
|
|
||||||
files[]: path, filename, size_bytes, estimated_tokens, doc_type
|
|
||||||
summary: total_files, total_size_bytes, total_estimated_tokens
|
|
||||||
groups[]: group_key, files[] with role (primary/companion/standalone)
|
|
||||||
- Groups related docs by naming convention (e.g., brief + discovery-notes)
|
|
||||||
routing: recommendation ("single" | "fan-out"), reason
|
|
||||||
- single: ≤3 files AND ≤15K estimated tokens
|
|
||||||
- fan-out: >3 files OR >15K estimated tokens
|
|
||||||
split_prediction: prediction ("likely" | "unlikely"), reason, estimated_distillate_tokens
|
|
||||||
- Estimates distillate at ~1/3 source size; splits if >5K tokens
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import glob
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
# Extensions to include when scanning folders
|
|
||||||
INCLUDE_EXTENSIONS = {".md", ".txt", ".yaml", ".yml", ".json"}
|
|
||||||
|
|
||||||
# Directories to skip when scanning folders
|
|
||||||
SKIP_DIRS = {
|
|
||||||
"node_modules", ".git", "__pycache__", ".venv", "venv",
|
|
||||||
".claude", "_bmad-output", ".cursor", ".vscode",
|
|
||||||
}
|
|
||||||
|
|
||||||
# Approximate chars per token for estimation
|
|
||||||
CHARS_PER_TOKEN = 4
|
|
||||||
|
|
||||||
# Thresholds
|
|
||||||
SINGLE_COMPRESSOR_MAX_TOKENS = 15_000
|
|
||||||
SINGLE_DISTILLATE_MAX_TOKENS = 5_000
|
|
||||||
|
|
||||||
# Naming patterns for document type detection
|
|
||||||
DOC_TYPE_PATTERNS = [
|
|
||||||
(r"discovery[_-]notes", "discovery-notes"),
|
|
||||||
(r"product[_-]brief", "product-brief"),
|
|
||||||
(r"research[_-]report", "research-report"),
|
|
||||||
(r"architecture", "architecture-doc"),
|
|
||||||
(r"prd", "prd"),
|
|
||||||
(r"distillate", "distillate"),
|
|
||||||
(r"changelog", "changelog"),
|
|
||||||
(r"readme", "readme"),
|
|
||||||
(r"spec", "specification"),
|
|
||||||
(r"requirements", "requirements"),
|
|
||||||
(r"design[_-]doc", "design-doc"),
|
|
||||||
(r"meeting[_-]notes", "meeting-notes"),
|
|
||||||
(r"brainstorm", "brainstorming"),
|
|
||||||
(r"interview", "interview-notes"),
|
|
||||||
]
|
|
||||||
|
|
||||||
# Patterns for grouping related documents
|
|
||||||
GROUP_PATTERNS = [
|
|
||||||
# base document + discovery notes
|
|
||||||
(r"^(.+?)(?:-discovery-notes|-discovery_notes)\.(\w+)$", r"\1.\2"),
|
|
||||||
# base document + appendix
|
|
||||||
(r"^(.+?)(?:-appendix|-addendum)(?:-\w+)?\.(\w+)$", r"\1.\2"),
|
|
||||||
# base document + review/feedback
|
|
||||||
(r"^(.+?)(?:-review|-feedback)\.(\w+)$", r"\1.\2"),
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_inputs(inputs: list[str]) -> list[Path]:
|
|
||||||
"""Resolve input arguments to a flat list of file paths."""
|
|
||||||
files: list[Path] = []
|
|
||||||
for inp in inputs:
|
|
||||||
path = Path(inp)
|
|
||||||
if path.is_file():
|
|
||||||
files.append(path.resolve())
|
|
||||||
elif path.is_dir():
|
|
||||||
for root, dirs, filenames in os.walk(path):
|
|
||||||
dirs[:] = [d for d in dirs if d not in SKIP_DIRS]
|
|
||||||
for fn in sorted(filenames):
|
|
||||||
fp = Path(root) / fn
|
|
||||||
if fp.suffix.lower() in INCLUDE_EXTENSIONS:
|
|
||||||
files.append(fp.resolve())
|
|
||||||
else:
|
|
||||||
# Try as glob
|
|
||||||
matches = glob.glob(inp, recursive=True)
|
|
||||||
for m in sorted(matches):
|
|
||||||
mp = Path(m)
|
|
||||||
if mp.is_file() and mp.suffix.lower() in INCLUDE_EXTENSIONS:
|
|
||||||
files.append(mp.resolve())
|
|
||||||
# Deduplicate while preserving order
|
|
||||||
seen: set[Path] = set()
|
|
||||||
deduped: list[Path] = []
|
|
||||||
for f in files:
|
|
||||||
if f not in seen:
|
|
||||||
seen.add(f)
|
|
||||||
deduped.append(f)
|
|
||||||
return deduped
|
|
||||||
|
|
||||||
|
|
||||||
def detect_doc_type(filename: str) -> str:
|
|
||||||
"""Detect document type from filename."""
|
|
||||||
name_lower = filename.lower()
|
|
||||||
for pattern, doc_type in DOC_TYPE_PATTERNS:
|
|
||||||
if re.search(pattern, name_lower):
|
|
||||||
return doc_type
|
|
||||||
return "unknown"
|
|
||||||
|
|
||||||
|
|
||||||
def suggest_groups(files: list[Path]) -> list[dict]:
|
|
||||||
"""Suggest document groupings based on naming conventions."""
|
|
||||||
groups: dict[str, list[dict]] = {}
|
|
||||||
ungrouped: list[dict] = []
|
|
||||||
|
|
||||||
file_map = {f.name: f for f in files}
|
|
||||||
|
|
||||||
assigned: set[str] = set()
|
|
||||||
|
|
||||||
for f in files:
|
|
||||||
if f.name in assigned:
|
|
||||||
continue
|
|
||||||
|
|
||||||
matched = False
|
|
||||||
for pattern, base_pattern in GROUP_PATTERNS:
|
|
||||||
m = re.match(pattern, f.name, re.IGNORECASE)
|
|
||||||
if m:
|
|
||||||
# This file is a companion — find its base
|
|
||||||
base_name = re.sub(pattern, base_pattern, f.name, flags=re.IGNORECASE)
|
|
||||||
group_key = base_name
|
|
||||||
if group_key not in groups:
|
|
||||||
groups[group_key] = []
|
|
||||||
# Add the base file if it exists
|
|
||||||
if base_name in file_map and base_name not in assigned:
|
|
||||||
groups[group_key].append({
|
|
||||||
"path": str(file_map[base_name]),
|
|
||||||
"filename": base_name,
|
|
||||||
"role": "primary",
|
|
||||||
})
|
|
||||||
assigned.add(base_name)
|
|
||||||
groups[group_key].append({
|
|
||||||
"path": str(f),
|
|
||||||
"filename": f.name,
|
|
||||||
"role": "companion",
|
|
||||||
})
|
|
||||||
assigned.add(f.name)
|
|
||||||
matched = True
|
|
||||||
break
|
|
||||||
|
|
||||||
if not matched:
|
|
||||||
# Check if this file is a base that already has companions
|
|
||||||
if f.name in groups:
|
|
||||||
continue # Already added as primary
|
|
||||||
ungrouped.append({
|
|
||||||
"path": str(f),
|
|
||||||
"filename": f.name,
|
|
||||||
})
|
|
||||||
|
|
||||||
result = []
|
|
||||||
for group_key, members in groups.items():
|
|
||||||
result.append({
|
|
||||||
"group_key": group_key,
|
|
||||||
"files": members,
|
|
||||||
})
|
|
||||||
for ug in ungrouped:
|
|
||||||
if ug["filename"] not in assigned:
|
|
||||||
result.append({
|
|
||||||
"group_key": ug["filename"],
|
|
||||||
"files": [{"path": ug["path"], "filename": ug["filename"], "role": "standalone"}],
|
|
||||||
})
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def analyze(inputs: list[str], output_path: str | None = None) -> None:
|
|
||||||
"""Main analysis function."""
|
|
||||||
files = resolve_inputs(inputs)
|
|
||||||
|
|
||||||
if not files:
|
|
||||||
result = {
|
|
||||||
"status": "error",
|
|
||||||
"error": "No readable files found from provided inputs",
|
|
||||||
"inputs": inputs,
|
|
||||||
}
|
|
||||||
output_json(result, output_path)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Analyze each file
|
|
||||||
file_details = []
|
|
||||||
total_chars = 0
|
|
||||||
for f in files:
|
|
||||||
size = f.stat().st_size
|
|
||||||
total_chars += size
|
|
||||||
file_details.append({
|
|
||||||
"path": str(f),
|
|
||||||
"filename": f.name,
|
|
||||||
"size_bytes": size,
|
|
||||||
"estimated_tokens": size // CHARS_PER_TOKEN,
|
|
||||||
"doc_type": detect_doc_type(f.name),
|
|
||||||
})
|
|
||||||
|
|
||||||
total_tokens = total_chars // CHARS_PER_TOKEN
|
|
||||||
groups = suggest_groups(files)
|
|
||||||
|
|
||||||
# Routing recommendation
|
|
||||||
if len(files) <= 3 and total_tokens <= SINGLE_COMPRESSOR_MAX_TOKENS:
|
|
||||||
routing = "single"
|
|
||||||
routing_reason = (
|
|
||||||
f"{len(files)} file(s), ~{total_tokens:,} estimated tokens — "
|
|
||||||
f"within single compressor threshold"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
routing = "fan-out"
|
|
||||||
routing_reason = (
|
|
||||||
f"{len(files)} file(s), ~{total_tokens:,} estimated tokens — "
|
|
||||||
f"exceeds single compressor threshold "
|
|
||||||
f"({'>' + str(SINGLE_COMPRESSOR_MAX_TOKENS) + ' tokens' if total_tokens > SINGLE_COMPRESSOR_MAX_TOKENS else '> 3 files'})"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Split prediction
|
|
||||||
estimated_distillate_tokens = total_tokens // 3 # rough: distillate is ~1/3 of source
|
|
||||||
if estimated_distillate_tokens > SINGLE_DISTILLATE_MAX_TOKENS:
|
|
||||||
split_prediction = "likely"
|
|
||||||
split_reason = (
|
|
||||||
f"Estimated distillate ~{estimated_distillate_tokens:,} tokens "
|
|
||||||
f"exceeds {SINGLE_DISTILLATE_MAX_TOKENS:,} threshold"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
split_prediction = "unlikely"
|
|
||||||
split_reason = (
|
|
||||||
f"Estimated distillate ~{estimated_distillate_tokens:,} tokens "
|
|
||||||
f"within {SINGLE_DISTILLATE_MAX_TOKENS:,} threshold"
|
|
||||||
)
|
|
||||||
|
|
||||||
result = {
|
|
||||||
"status": "ok",
|
|
||||||
"files": file_details,
|
|
||||||
"summary": {
|
|
||||||
"total_files": len(files),
|
|
||||||
"total_size_bytes": total_chars,
|
|
||||||
"total_estimated_tokens": total_tokens,
|
|
||||||
},
|
|
||||||
"groups": groups,
|
|
||||||
"routing": {
|
|
||||||
"recommendation": routing,
|
|
||||||
"reason": routing_reason,
|
|
||||||
},
|
|
||||||
"split_prediction": {
|
|
||||||
"prediction": split_prediction,
|
|
||||||
"reason": split_reason,
|
|
||||||
"estimated_distillate_tokens": estimated_distillate_tokens,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
output_json(result, output_path)
|
|
||||||
|
|
||||||
|
|
||||||
def output_json(data: dict, output_path: str | None) -> None:
|
|
||||||
"""Write JSON to file or stdout."""
|
|
||||||
json_str = json.dumps(data, indent=2)
|
|
||||||
if output_path:
|
|
||||||
Path(output_path).parent.mkdir(parents=True, exist_ok=True)
|
|
||||||
Path(output_path).write_text(json_str + "\n")
|
|
||||||
print(f"Results written to {output_path}", file=sys.stderr)
|
|
||||||
else:
|
|
||||||
print(json_str)
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description=__doc__,
|
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"inputs",
|
|
||||||
nargs="+",
|
|
||||||
help="File paths, folder paths, or glob patterns to analyze",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-o", "--output",
|
|
||||||
help="Output JSON to file instead of stdout",
|
|
||||||
)
|
|
||||||
args = parser.parse_args()
|
|
||||||
analyze(args.inputs, args.output)
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|
@ -1,204 +0,0 @@
|
||||||
"""Tests for analyze_sources.py"""
|
|
||||||
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import tempfile
|
|
||||||
from pathlib import Path
|
|
||||||
from unittest.mock import patch
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
# Add parent dir to path so we can import the script
|
|
||||||
import sys
|
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
||||||
|
|
||||||
from analyze_sources import (
|
|
||||||
resolve_inputs,
|
|
||||||
detect_doc_type,
|
|
||||||
suggest_groups,
|
|
||||||
analyze,
|
|
||||||
INCLUDE_EXTENSIONS,
|
|
||||||
SKIP_DIRS,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def temp_dir():
|
|
||||||
"""Create a temp directory with sample files."""
|
|
||||||
with tempfile.TemporaryDirectory() as d:
|
|
||||||
# Create sample files
|
|
||||||
(Path(d) / "product-brief-foo.md").write_text("# Product Brief\nContent here")
|
|
||||||
(Path(d) / "product-brief-foo-discovery-notes.md").write_text("# Discovery\nNotes")
|
|
||||||
(Path(d) / "architecture-doc.md").write_text("# Architecture\nDesign here")
|
|
||||||
(Path(d) / "research-report.md").write_text("# Research\nFindings")
|
|
||||||
(Path(d) / "random.txt").write_text("Some text content")
|
|
||||||
(Path(d) / "image.png").write_bytes(b"\x89PNG")
|
|
||||||
# Create a subdirectory with more files
|
|
||||||
sub = Path(d) / "subdir"
|
|
||||||
sub.mkdir()
|
|
||||||
(sub / "prd-v2.md").write_text("# PRD\nRequirements")
|
|
||||||
# Create a skip directory
|
|
||||||
skip = Path(d) / "node_modules"
|
|
||||||
skip.mkdir()
|
|
||||||
(skip / "junk.md").write_text("Should be skipped")
|
|
||||||
yield d
|
|
||||||
|
|
||||||
|
|
||||||
class TestResolveInputs:
|
|
||||||
def test_single_file(self, temp_dir):
|
|
||||||
f = str(Path(temp_dir) / "product-brief-foo.md")
|
|
||||||
result = resolve_inputs([f])
|
|
||||||
assert len(result) == 1
|
|
||||||
assert result[0].name == "product-brief-foo.md"
|
|
||||||
|
|
||||||
def test_folder_recursion(self, temp_dir):
|
|
||||||
result = resolve_inputs([temp_dir])
|
|
||||||
names = {f.name for f in result}
|
|
||||||
assert "product-brief-foo.md" in names
|
|
||||||
assert "prd-v2.md" in names
|
|
||||||
assert "random.txt" in names
|
|
||||||
|
|
||||||
def test_folder_skips_excluded_dirs(self, temp_dir):
|
|
||||||
result = resolve_inputs([temp_dir])
|
|
||||||
names = {f.name for f in result}
|
|
||||||
assert "junk.md" not in names
|
|
||||||
|
|
||||||
def test_folder_skips_non_text_files(self, temp_dir):
|
|
||||||
result = resolve_inputs([temp_dir])
|
|
||||||
names = {f.name for f in result}
|
|
||||||
assert "image.png" not in names
|
|
||||||
|
|
||||||
def test_glob_pattern(self, temp_dir):
|
|
||||||
pattern = str(Path(temp_dir) / "product-brief-*.md")
|
|
||||||
result = resolve_inputs([pattern])
|
|
||||||
assert len(result) == 2
|
|
||||||
names = {f.name for f in result}
|
|
||||||
assert "product-brief-foo.md" in names
|
|
||||||
assert "product-brief-foo-discovery-notes.md" in names
|
|
||||||
|
|
||||||
def test_deduplication(self, temp_dir):
|
|
||||||
f = str(Path(temp_dir) / "product-brief-foo.md")
|
|
||||||
result = resolve_inputs([f, f, f])
|
|
||||||
assert len(result) == 1
|
|
||||||
|
|
||||||
def test_mixed_inputs(self, temp_dir):
|
|
||||||
file_path = str(Path(temp_dir) / "architecture-doc.md")
|
|
||||||
folder_path = str(Path(temp_dir) / "subdir")
|
|
||||||
result = resolve_inputs([file_path, folder_path])
|
|
||||||
names = {f.name for f in result}
|
|
||||||
assert "architecture-doc.md" in names
|
|
||||||
assert "prd-v2.md" in names
|
|
||||||
|
|
||||||
def test_nonexistent_path(self):
|
|
||||||
result = resolve_inputs(["/nonexistent/path/file.md"])
|
|
||||||
assert len(result) == 0
|
|
||||||
|
|
||||||
|
|
||||||
class TestDetectDocType:
|
|
||||||
@pytest.mark.parametrize("filename,expected", [
|
|
||||||
("product-brief-foo.md", "product-brief"),
|
|
||||||
("product_brief_bar.md", "product-brief"),
|
|
||||||
("foo-discovery-notes.md", "discovery-notes"),
|
|
||||||
("foo-discovery_notes.md", "discovery-notes"),
|
|
||||||
("architecture-overview.md", "architecture-doc"),
|
|
||||||
("my-prd.md", "prd"),
|
|
||||||
("research-report-q4.md", "research-report"),
|
|
||||||
("foo-distillate.md", "distillate"),
|
|
||||||
("changelog.md", "changelog"),
|
|
||||||
("readme.md", "readme"),
|
|
||||||
("api-spec.md", "specification"),
|
|
||||||
("design-doc-v2.md", "design-doc"),
|
|
||||||
("meeting-notes-2026.md", "meeting-notes"),
|
|
||||||
("brainstorm-session.md", "brainstorming"),
|
|
||||||
("user-interview-notes.md", "interview-notes"),
|
|
||||||
("random-file.md", "unknown"),
|
|
||||||
])
|
|
||||||
def test_detection(self, filename, expected):
|
|
||||||
assert detect_doc_type(filename) == expected
|
|
||||||
|
|
||||||
|
|
||||||
class TestSuggestGroups:
|
|
||||||
def test_groups_brief_with_discovery_notes(self, temp_dir):
|
|
||||||
files = [
|
|
||||||
Path(temp_dir) / "product-brief-foo.md",
|
|
||||||
Path(temp_dir) / "product-brief-foo-discovery-notes.md",
|
|
||||||
]
|
|
||||||
groups = suggest_groups(files)
|
|
||||||
# Should produce one group with both files
|
|
||||||
paired = [g for g in groups if len(g["files"]) > 1]
|
|
||||||
assert len(paired) == 1
|
|
||||||
filenames = {f["filename"] for f in paired[0]["files"]}
|
|
||||||
assert "product-brief-foo.md" in filenames
|
|
||||||
assert "product-brief-foo-discovery-notes.md" in filenames
|
|
||||||
|
|
||||||
def test_standalone_files(self, temp_dir):
|
|
||||||
files = [
|
|
||||||
Path(temp_dir) / "architecture-doc.md",
|
|
||||||
Path(temp_dir) / "research-report.md",
|
|
||||||
]
|
|
||||||
groups = suggest_groups(files)
|
|
||||||
assert len(groups) == 2
|
|
||||||
for g in groups:
|
|
||||||
assert len(g["files"]) == 1
|
|
||||||
|
|
||||||
def test_mixed_grouped_and_standalone(self, temp_dir):
|
|
||||||
files = [
|
|
||||||
Path(temp_dir) / "product-brief-foo.md",
|
|
||||||
Path(temp_dir) / "product-brief-foo-discovery-notes.md",
|
|
||||||
Path(temp_dir) / "architecture-doc.md",
|
|
||||||
]
|
|
||||||
groups = suggest_groups(files)
|
|
||||||
paired = [g for g in groups if len(g["files"]) > 1]
|
|
||||||
standalone = [g for g in groups if len(g["files"]) == 1]
|
|
||||||
assert len(paired) == 1
|
|
||||||
assert len(standalone) == 1
|
|
||||||
|
|
||||||
|
|
||||||
class TestAnalyze:
|
|
||||||
def test_basic_analysis(self, temp_dir):
|
|
||||||
f = str(Path(temp_dir) / "product-brief-foo.md")
|
|
||||||
output_file = str(Path(temp_dir) / "output.json")
|
|
||||||
analyze([f], output_file)
|
|
||||||
result = json.loads(Path(output_file).read_text())
|
|
||||||
assert result["status"] == "ok"
|
|
||||||
assert result["summary"]["total_files"] == 1
|
|
||||||
assert result["files"][0]["doc_type"] == "product-brief"
|
|
||||||
assert result["files"][0]["estimated_tokens"] > 0
|
|
||||||
|
|
||||||
def test_routing_single_small_input(self, temp_dir):
|
|
||||||
f = str(Path(temp_dir) / "product-brief-foo.md")
|
|
||||||
output_file = str(Path(temp_dir) / "output.json")
|
|
||||||
analyze([f], output_file)
|
|
||||||
result = json.loads(Path(output_file).read_text())
|
|
||||||
assert result["routing"]["recommendation"] == "single"
|
|
||||||
|
|
||||||
def test_routing_fanout_many_files(self, temp_dir):
|
|
||||||
# Create enough files to trigger fan-out (> 3 files)
|
|
||||||
for i in range(5):
|
|
||||||
(Path(temp_dir) / f"doc-{i}.md").write_text("x" * 1000)
|
|
||||||
output_file = str(Path(temp_dir) / "output.json")
|
|
||||||
analyze([temp_dir], output_file)
|
|
||||||
result = json.loads(Path(output_file).read_text())
|
|
||||||
assert result["routing"]["recommendation"] == "fan-out"
|
|
||||||
|
|
||||||
def test_folder_analysis(self, temp_dir):
|
|
||||||
output_file = str(Path(temp_dir) / "output.json")
|
|
||||||
analyze([temp_dir], output_file)
|
|
||||||
result = json.loads(Path(output_file).read_text())
|
|
||||||
assert result["status"] == "ok"
|
|
||||||
assert result["summary"]["total_files"] >= 4 # at least the base files
|
|
||||||
assert len(result["groups"]) > 0
|
|
||||||
|
|
||||||
def test_no_files_found(self):
|
|
||||||
output_file = "/tmp/test_analyze_empty.json"
|
|
||||||
analyze(["/nonexistent/path"], output_file)
|
|
||||||
result = json.loads(Path(output_file).read_text())
|
|
||||||
assert result["status"] == "error"
|
|
||||||
os.unlink(output_file)
|
|
||||||
|
|
||||||
def test_stdout_output(self, temp_dir, capsys):
|
|
||||||
f = str(Path(temp_dir) / "product-brief-foo.md")
|
|
||||||
analyze([f])
|
|
||||||
captured = capsys.readouterr()
|
|
||||||
result = json.loads(captured.out)
|
|
||||||
assert result["status"] == "ok"
|
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
---
|
||||||
|
name: bmad-spec
|
||||||
|
description: Distill any intent input into the SPEC kernel + companions — the canonical, preservation-validated machine contract for downstream work. Use when the user says "create a spec", "distill this into a spec", "validate this spec", or "update the spec".
|
||||||
|
---
|
||||||
|
|
||||||
|
# BMad Spec
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Canonical transformer for the BMad spec-kernel ecosystem. Takes any intent input — vague idea, brain dump, PRD, GDD, RFC, brief, Slack thread, customer email, meeting transcript, mockups, mixed multi-source — and produces **SPEC.md** carrying the five-field kernel (Why, Capabilities, Constraints, Non-goals, Success signal) plus companion files for load-bearing content that does not fit or would bloat the kernel with expansive line-item detail. Together they are the machine contract every downstream BMad skill consumes.
|
||||||
|
|
||||||
|
Multiple skills may call to update the same spec over time.
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
- Bare paths (e.g. `assets/spec-template.md`) resolve from the skill root.
|
||||||
|
- `{skill-root}` is this skill's install dir; `{project-root}` is the working dir.
|
||||||
|
- `{workflow.<name>}` resolves to fields in `customize.toml`.
|
||||||
|
|
||||||
|
## On Activation
|
||||||
|
|
||||||
|
1. Resolve customization: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly.
|
||||||
|
2. Run `{workflow.activation_steps_prepend}`. Treat `{workflow.persistent_facts}` as foundational context (`file:` entries are loaded).
|
||||||
|
3. Load `{project-root}/_bmad/core/config.yaml` (and `config.user.yaml` if present), root level and `bmm` section. Resolve `{user_name}`, `{communication_language}`, `{document_output_language}`, `{planning_artifacts}`, `{project_name}`, `{date}`.
|
||||||
|
4. Detect mode. **Headless** when any of: no TTY, programmatic caller (another skill or non-interactive runner), or the first message pre-supplies all inputs and asks for an artifact path back. **Interactive** otherwise. In interactive mode, greet by `{user_name}` in `{communication_language}`, stay in that language, and mention that `bmad-party-mode` and `bmad-advanced-elicitation` are available for deeper exploration on any field.
|
||||||
|
5. Run `{workflow.activation_steps_append}`.
|
||||||
|
|
||||||
|
## Workspace
|
||||||
|
|
||||||
|
The spec is **always a folder** named `{workflow.spec_output_path}/{workflow.run_folder_pattern}`, resolving by default to `{output_folder}/specs/spec-{slug}/`.
|
||||||
|
|
||||||
|
`{slug}` describes the thing being specced, not the input shape:
|
||||||
|
|
||||||
|
- Source artifact already carries a slug (e.g., `prd-foo-bar-2026-05-23/`): inherit (`foo-bar`).
|
||||||
|
- Sparse, in-chat, or multi-source input: interactive asks; headless caller provides it as part of the input. If absent and underivable, headless blocks with `error_code: "missing_slug"`.
|
||||||
|
- Same slug = same folder. A second invocation with the same `{slug}` lands at the existing spec folder and updates in place, preserving capability IDs.
|
||||||
|
|
||||||
|
**No input.** Interactive: ask the user to share a file path, paste content, explain the idea in detail, or point to a source. Headless: respond with JSON containing `error_code: "insufficient_intent"`.
|
||||||
|
|
||||||
|
Inside the spec folder:
|
||||||
|
|
||||||
|
```
|
||||||
|
<spec-folder>/
|
||||||
|
SPEC.md ← uppercase, the kernel
|
||||||
|
<companion-1>.md ← optional, content-typed (e.g. glossary.md)
|
||||||
|
<companion-2>.md
|
||||||
|
.decision-log.md ← canonical memory for this spec
|
||||||
|
```
|
||||||
|
|
||||||
|
## The Operation
|
||||||
|
|
||||||
|
Read the input and its ancillary linked materials. If there is no input, follow the no-input branch in **Workspace** (ask or block). If a prior `SPEC.md` exists at the target folder, read it too — the operation becomes an update. Preserve capability IDs; new capabilities get the next unused `CAP-N`; never reuse retired IDs. Otherwise this is a create.
|
||||||
|
|
||||||
|
When the input is structured and pre-sorted (a PRD with an addendum, a GDD, a brief produced by an upstream BMad skill), trust the authored separation: lift kernel-fitting content into SPEC.md, lift overflow into appropriately-named companions. When the input is mixed (a brain dump, a transcript, an RFC, a customer email), do the sorting yourself: walk each claim, apply the three-lens load-bearing test (Spec Law rule 7), and route to the kernel field or a companion.
|
||||||
|
|
||||||
|
Distill the input into the five-field kernel using `{workflow.spec_template}` as the skeleton. When input is rich, extract directly — no elicitation. When input is sparse, choose: **express** (best-effort distill, every gap becomes an `open_questions[]` entry) or **guided** (walk the five fields with the user one at a time). Headless defaults to express and logs the choice. Interactive asks.
|
||||||
|
|
||||||
|
Write lean from the first pass: every sentence must earn its place. Decoration costs tokens and dilutes downstream readers.
|
||||||
|
|
||||||
|
If the input is genuinely too thin to distill (e.g. "an app for hikers" with no surrounding context), stop and suggest `bmad-prd` (or sibling ceremony skill). This skill distills; it does not coach.
|
||||||
|
|
||||||
|
## Load-bearing
|
||||||
|
|
||||||
|
A claim is **load-bearing** if any consumer (downstream skill, implementing agent, verification pass) would change a decision without it.
|
||||||
|
|
||||||
|
## Companions
|
||||||
|
|
||||||
|
When load-bearing content does not fit the five-field kernel, it lives in a companion. The kernel cites it; the companion holds it. Companions are part of the contract; every consumer reads `companions:` in SPEC.md frontmatter to discover them. Companions follow the same lean discipline as SPEC.md (Spec Law rule 8).
|
||||||
|
|
||||||
|
**Spawn a companion when the content needs more than one kernel-shape line:** multi-item catalogs (per-entity matrices like archetypes, drinks, modes, routes), tables, diagrams (always), editorial voice rules, long-form reference material the kernel cites by name (glossary, brownfield notes, project conventions). Single-line decision-benders stay in Constraints; intent+success pairs stay in Capabilities. If a kernel field is starting to bullet into sub-bullets, the content has outgrown the kernel and wants a companion.
|
||||||
|
|
||||||
|
Companions are either:
|
||||||
|
|
||||||
|
- **Spec-authored** companions are written by bmad-spec and live as **siblings of SPEC.md** (e.g., `glossary.md`, `patron-archetypes.md`). bmad-spec owns them and may edit them on update operations.
|
||||||
|
- **Adopted** companions are load-bearing artifacts written by an upstream skill that downstream still needs to read. bmad-spec references them into `companions:` by relative path but does NOT edit them (e.g., a `DESIGN.md` or `EXPERIENCE.md` from a UX run, an integration partner's API spec). The originating skill owns them.
|
||||||
|
|
||||||
|
Two rules govern companions:
|
||||||
|
|
||||||
|
1. **Name spec-authored companions for the content type they hold.** `glossary.md`, `<entity-class>.md` (e.g. `patron-archetypes.md`, `medication-routes.md`, `flight-modes.md`), `stack.md`, `conventions.md`, `brownfield.md`, `architecture-diagrams.md`, `state-machines.md`, `failure-modes.md`, `compliance-references.md`. The principle: "a reader should know what is inside before opening it." Adopted companions keep whatever name their originating skill gave them.
|
||||||
|
2. **Diagrams always land in a companion**, regardless of size. SPEC.md kernel holds prose only. Mermaid blocks, ASCII diagrams, and image references all live in a companion (e.g. `architecture-diagrams.md`), with sibling image files referenced from there.
|
||||||
|
|
||||||
|
Pre-existing project-wide docs (e.g. `project-context.md`) that downstream needs are listed as **adopted companions**, never duplicated into SPEC.md or a spec-authored companion.
|
||||||
|
|
||||||
|
## Spec Law
|
||||||
|
|
||||||
|
Every spec must satisfy these eight rules. The operation aims for them; the self-validate sweep enforces them.
|
||||||
|
|
||||||
|
1. **Each capability has both `intent` and `success`.** Missing either = not a capability.
|
||||||
|
2. **Intents describe WHAT, not HOW.** Implementation prescription belongs in a companion (stack, conventions).
|
||||||
|
3. **Constraints actually bend design decisions.** A "constraint" that rules nothing out is decoration.
|
||||||
|
4. **Non-goals are explicit.** At least one. Absence means downstream skills fill the vacuum.
|
||||||
|
5. **Success signal is concrete enough to test or demonstrate against.** "Users love it" doesn't qualify.
|
||||||
|
6. **Capability IDs are stable and unique.** Never reused, never renumbered.
|
||||||
|
7. **Preservation.** Every load-bearing source claim lands in SPEC.md or a companion. Wrapper ceremony does not.
|
||||||
|
8. **Lean prose.** Every sentence carries load-bearing content. Cut decoration, hedges, backstory, throat-clearing. Applies to SPEC.md, companions, and `.decision-log.md`.
|
||||||
|
|
||||||
|
## Self-Validate
|
||||||
|
|
||||||
|
After every create or update, sweep the resulting artifact in **two passes** before presenting.
|
||||||
|
|
||||||
|
**Pass 1 — Coherence.** Judge the spec against Spec Law rules 1–6 and 8. For anything that fails or feels weak, attempt to fix it without inventing content the input did not support. Calls made without direct confirmation become `assumptions[]`; gaps that could not be filled become `open_questions[]`.
|
||||||
|
|
||||||
|
**Pass 2 — Preservation.** Walk the source claim by claim. Confirm each load-bearing claim landed in SPEC.md or a companion. Wrapper-ceremony drops are logged under "Wrapper-only content" so the drop is on the record, not silent.
|
||||||
|
|
||||||
|
Append a one-paragraph verdict to `.decision-log.md` covering both passes. In interactive mode, review the verdict with the user. In headless mode, `.decision-log.md` is one of the files returned, so the caller (or its downstream LLM) reads the verdict there.
|
||||||
|
|
||||||
|
## Spec with no change signal
|
||||||
|
|
||||||
|
When the user points the skill at an existing spec folder (or its SPEC.md) with no change signal, offer to review assumptions or open questions, or determine what they want to do.
|
||||||
|
|
||||||
|
## Output
|
||||||
|
|
||||||
|
**Interactive** — share the spec folder path conversationally. Name the capability count, the companions produced, and the verdict in one or two sentences. If `assumptions[]` or `open_questions[]` are non-empty, list them (short — one line each) and invite the user to walk through them. Make clear that addressing them can update the source input (if it was a file), the spec, or both — whichever combination the user prefers. Do not dump JSON or present a wall of output.
|
||||||
|
|
||||||
|
**Headless** — return JSON per `assets/headless-schemas.md`.
|
||||||
|
|
||||||
|
Run `{workflow.on_complete}` if set.
|
||||||
|
|
||||||
|
## After Spec is Output
|
||||||
|
|
||||||
|
Any update to spec regarding assumptions, open questions, or other changes should be appended to that source's decision log also and offer to update the source.
|
||||||
|
|
||||||
|
## Frontmatter conventions
|
||||||
|
|
||||||
|
- `companions:` array of `.md` files downstream MUST read alongside SPEC.md to have the full contract. Paths may point inside the spec folder (spec-authored companions like `glossary.md`) or outside it (adopted companions like `../planning-artifacts/ux-designs/ux-foo-bar-2026-05-23/DESIGN.md`). The split between spec-authored and adopted is implicit by path; downstream treats both the same.
|
||||||
|
- `sources:` array of paths to files that were **fully absorbed** into the SPEC, with no remaining downstream value (e.g., a PRD whose every load-bearing claim is now in the kernel). Listed for audit and for bmad-spec to re-read on update. Downstream does NOT read these. Files that downstream still needs to read belong in `companions:`, not here.
|
||||||
|
- **Do not list** decision logs, README files, organizational artifacts, or any operational record of how upstream skills produced their artifacts. Those are not source content; they are process metadata that downstream consumers don't need.
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Headless JSON Response
|
||||||
|
|
||||||
|
The default invocation is headless: input goes in, JSON comes out. The contract is intentionally tiny — return the outcome and the files touched. Anything else a caller needs is inside those files (SPEC.md, companions, `.decision-log.md`).
|
||||||
|
|
||||||
|
## Success
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "complete",
|
||||||
|
"files": [
|
||||||
|
"_bmad-output/specs/spec-quarter-drop/SPEC.md",
|
||||||
|
"_bmad-output/specs/spec-quarter-drop/glossary.md",
|
||||||
|
"_bmad-output/specs/spec-quarter-drop/.decision-log.md"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`files` lists every file written or modified in this run, in any order. The spec folder, kernel filename, decision log location, capabilities, companions, and verdict are all readable from those files; no need to re-encode them in the response.
|
||||||
|
|
||||||
|
## Blocked
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "blocked",
|
||||||
|
"error_code": "insufficient_intent",
|
||||||
|
"reason": "Input was a one-line idea with no surrounding context; too thin to distill. Suggest bmad-prd to draw the vision out first."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Defined `error_code` values:
|
||||||
|
|
||||||
|
- `insufficient_intent` — input too thin to distill into a kernel.
|
||||||
|
- `missing_slug` — input is sparse or multi-source and no slug was provided by the caller or derivable from a source path.
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
---
|
||||||
|
id: SPEC-{slug}
|
||||||
|
companions: [] # files downstream MUST read alongside SPEC.md. Paths may point inside the spec folder (spec-authored) or outside it (adopted from an upstream skill).
|
||||||
|
sources: [] # files fully absorbed into the SPEC (audit only; downstream does NOT read these). Never decision logs.
|
||||||
|
---
|
||||||
|
|
||||||
|
> **Canonical contract.** This SPEC and the files in `companions:` are the complete, preservation-validated contract for what to build, test, and validate. Source documents listed in frontmatter are for traceability only — consult them only if you need narrative rationale or prose color this contract intentionally omits.
|
||||||
|
|
||||||
|
# {Spec Title}
|
||||||
|
|
||||||
|
## Why
|
||||||
|
|
||||||
|
{One paragraph naming the force behind this work. A spec can exist for any of:
|
||||||
|
- **a pain to solve** — a user or operator is stuck on a specific gap;
|
||||||
|
- **an opportunity to capture** — something newly possible we want to claim;
|
||||||
|
- **a vision to realize** — a thing we want to make exist because we want it to exist;
|
||||||
|
- **a mandate to meet** — a regulation, deprecation, deadline, or contractual obligation.
|
||||||
|
|
||||||
|
Name which (or which combination) applies, who is affected, and the backdrop that makes it matter now. This is the anchor every downstream trade-off resolves against.}
|
||||||
|
|
||||||
|
## Capabilities
|
||||||
|
|
||||||
|
- id: CAP-1
|
||||||
|
intent: {One sentence. "User or system can do X to achieve Y." WHAT, not HOW.}
|
||||||
|
success: {Testable or demonstrable criterion. Something a test or a real demonstration can decide.}
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
|
||||||
|
- {A non-negotiable that bends design. If it doesn't rule anything out, it doesn't belong.}
|
||||||
|
|
||||||
|
## Non-goals
|
||||||
|
|
||||||
|
- {Explicit out-of-scope item. At least one. Stops downstream from filling the vacuum.}
|
||||||
|
|
||||||
|
## Success signal
|
||||||
|
|
||||||
|
- {One or two sentences. World-change moment, not dashboard. Concrete enough to write a test or run a demonstration against.}
|
||||||
|
|
||||||
|
## Assumptions
|
||||||
|
|
||||||
|
<!-- Optional. Omit this section entirely if empty. Inferred calls made without direct confirmation from the input. -->
|
||||||
|
|
||||||
|
- {Statement of fact the Spec proceeded under, e.g. "Assumed mobile-first since input mentioned GPS but no platform."}
|
||||||
|
|
||||||
|
## Open Questions
|
||||||
|
|
||||||
|
<!-- Optional. Omit this section entirely if empty. Gaps the input did not resolve that need a human decision before downstream skills consume the Spec. -->
|
||||||
|
|
||||||
|
- {Question phrased so a human can answer it, e.g. "Is offline playback in scope for CAP-2?"}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
# DO NOT EDIT -- overwritten on every update.
|
||||||
|
#
|
||||||
|
# Workflow customization surface for bmad-spec.
|
||||||
|
#
|
||||||
|
# Override files (not edited here):
|
||||||
|
# {project-root}/_bmad/custom/bmad-spec.toml (team)
|
||||||
|
# {project-root}/_bmad/custom/bmad-spec.user.toml (personal)
|
||||||
|
|
||||||
|
[workflow]
|
||||||
|
|
||||||
|
# --- Configurable below. Overrides merge per BMad structural rules: ---
|
||||||
|
# scalars: override wins • arrays: append
|
||||||
|
|
||||||
|
# Steps to run before the standard activation (config load, greet).
|
||||||
|
activation_steps_prepend = []
|
||||||
|
|
||||||
|
# Steps to run after greet but before the operation begins.
|
||||||
|
activation_steps_append = []
|
||||||
|
|
||||||
|
# Persistent facts the workflow keeps in mind for the whole run.
|
||||||
|
# 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 points to a single top-level file; override in team/user TOML
|
||||||
|
# to widen the scope (e.g. `_bmad/**/project-context.md`) if needed.
|
||||||
|
persistent_facts = [
|
||||||
|
"file:{project-root}/project-context.md",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Executed when the workflow completes. Scalar or array of instructions.
|
||||||
|
on_complete = ""
|
||||||
|
|
||||||
|
# Spec template. The five-field kernel skeleton. Override the path in
|
||||||
|
# team/user TOML to enforce a different shape (e.g. a hypothesis field
|
||||||
|
# for research initiatives, or a mechanics field for games).
|
||||||
|
spec_template = "assets/spec-template.md"
|
||||||
|
|
||||||
|
# Canonical filename for the kernel artifact inside the spec folder.
|
||||||
|
# Uppercase by convention to signal "the central source of truth."
|
||||||
|
spec_filename = "SPEC.md"
|
||||||
|
|
||||||
|
# Output path for spec folders. Lands directly under {output_folder}
|
||||||
|
# so bmad-spec works in core-only installs and matches the
|
||||||
|
# long-term BMad direction of grouping artifacts as siblings under
|
||||||
|
# {output_folder}/<type>/ rather than nested inside planning vs
|
||||||
|
# implementation folders.
|
||||||
|
spec_output_path = "{output_folder}/specs"
|
||||||
|
|
||||||
|
# Run-folder pattern inside spec_output_path. Resolved against the
|
||||||
|
# input-derived slug at activation. Same slug = same folder, so a
|
||||||
|
# second invocation updates the existing spec in place (capability
|
||||||
|
# IDs preserved). Override to add {date} or other components if a
|
||||||
|
# fresh dated history is preferred.
|
||||||
|
run_folder_pattern = "spec-{slug}"
|
||||||
|
|
@ -9,5 +9,5 @@ Core,bmad-editorial-review-prose,Editorial Review - Prose,EP,Use after drafting
|
||||||
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-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-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-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-spec,Spec,SP,"Use to distill any intent input (brief, PRD, transcript, brain dump, design folder, mixed multi-source) into a succinct, no-fluff SPEC.md contract + companions that downstream work derives from. Locks the WHAT before the HOW. Works for software, game design, research, editorial, policy, business, anything intent-bearing. Validation mode also available.",,[path],anytime,,,false,{output_folder}/specs/spec-{slug},SPEC.md + companion files
|
||||||
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-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
|
||||||
|
|
|
||||||
|
Loading…
Reference in New Issue