From d363e5b04e8ce79ed8f9ea18610d51973081ae47 Mon Sep 17 00:00:00 2001 From: Brian Madison Date: Mon, 18 May 2026 18:39:34 -0500 Subject: [PATCH] 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) --- .../2-plan-workflows/bmad-spec/SKILL.md | 80 +++++++++++++++++++ .../bmad-spec/assets/headless-schemas.md | 65 +++++++++++++++ .../bmad-spec/assets/spec-template.md | 43 ++++++++++ .../2-plan-workflows/bmad-spec/customize.toml | 48 +++++++++++ 4 files changed, 236 insertions(+) create mode 100644 src/bmm-skills/2-plan-workflows/bmad-spec/SKILL.md create mode 100644 src/bmm-skills/2-plan-workflows/bmad-spec/assets/headless-schemas.md create mode 100644 src/bmm-skills/2-plan-workflows/bmad-spec/assets/spec-template.md create mode 100644 src/bmm-skills/2-plan-workflows/bmad-spec/customize.toml diff --git a/src/bmm-skills/2-plan-workflows/bmad-spec/SKILL.md b/src/bmm-skills/2-plan-workflows/bmad-spec/SKILL.md new file mode 100644 index 000000000..1c58336f5 --- /dev/null +++ b/src/bmm-skills/2-plan-workflows/bmad-spec/SKILL.md @@ -0,0 +1,80 @@ +--- +name: bmad-spec +description: Distill any intent input into the five-field Spec kernel. Use when the user says "create a spec", "distill this into a spec", "validate this spec", or "update the spec". +--- + +# BMad Spec + +Universal distiller. Takes any intent input — vague idea, brain dump, PRD, GDD, RFC, brief, Slack thread, customer email, meeting transcript — and produces a `spec.md` carrying the five-field kernel: Problem, Capabilities, Constraints, Non-goals, Success signal. Quality scales with input richness; the contract holds. + +The operation is input-driven: read the input, produce the Spec, self-validate, present. Headless callers get JSON; interactive users get a conversational close with the spec path and an invitation to address gaps. The Spec is the machine-readable contract every downstream BMad skill consumes (UX, Architecture, Ticketing). PRDs and other ceremony docs are for humans; Specs are for machines. + +## 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.}` resolves to fields in `customize.toml`. +- `{doc_workspace}` is the bound run folder for this Spec. + +## 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/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 — the normal case when a user is in the conversation. 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 + +Where the Spec lands depends on the input: + +- **Input is a local file** — write `{input-basename}-spec-{datetime}.md` as a sibling of the source. +- **Input is in-chat prose or a remote source we cannot write next to** — write `{planning_artifacts}/specs/{slug}-spec-{datetime}.md`. +- **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. + +When a `.decision-log.md` is in scope (file-input case, source folder already has one), it is canonical memory — every decision, override, assumption, and rejected alternative captured during the run. When no decision log is in scope, the verdict surfaces in the conversational output (interactive) and the headless JSON only. + +## The Operation + +Read the input. If there is no input, follow the no-input branch in **Workspace** (ask or block). If the input is itself a prior Spec — or a prior Spec exists at the target sibling path — 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. + +Distill the input into the five-field kernel using `{workflow.spec_template}` as the skeleton. When input is rich (PRD, GDD, RFC, detailed brain dump), extract directly — no elicitation. When input is sparse (a paragraph, a one-line idea), 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. + +When the user volunteers content that belongs in the wrapper rather than the kernel (a persona detail, a milestone, an architecture choice), capture it to a sibling `addendum.md` rather than pushing back mid-flow. Tell them at the end where it landed. + +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. + +## Spec Law + +Every Spec must satisfy these six 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 the wrapper or downstream architecture. +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. + +What does NOT belong in a Spec, regardless of input: personas, NFR matrices, journey diagrams, risk registers, milestones, acceptance criteria matrices, traceability tables, implementation prescription, stakeholder approval ceremony. All of that lives in the wrapper. + +## Self-Validate + +After every create or update, sweep the resulting Spec file against Spec Law before presenting. For each rule, judge whether the Spec passes; for anything that fails or feels weak, attempt to fix it without inventing content the input did not support. Calls you made without direct confirmation become `assumptions[]`; gaps you could not fill become `open_questions[]`. If a `.decision-log.md` is in scope (per **Workspace**), append a one-paragraph verdict to it. + +This is judgment, not ceremony — no separate report, no grade tiers, no severity counts. The verdict either reads "ready for downstream" or names what's blocking that. The user sees the verdict, the assumptions, and the open questions in the final output. + +## Validate-Only Mode + +When the user points the skill at an existing Spec file with no change signal, run the self-validate sweep without modifying anything. Surface findings inline; if a `.decision-log.md` sits alongside the Spec, append the verdict to it. Offer to roll findings into an update. + +## Output + +**Interactive** — share the Spec file path conversationally. Name the capability count 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. Do not present a wall of numbers. + +**Headless** — return JSON per `assets/headless-schemas.md`. Nothing else. + +Run `{workflow.on_complete}` if set. + +## Post Output + +If the user wants to address assumptions or open questions, loop back into the operation with the Spec as input. If they want to update the source input, loop back with that. If they want to update both, loop back with the Spec and overwrite the source file if there is one. If they want to update neither, end the conversation. If there are any udpates to the source, and there is a `.decision-log.md` in scope, append all details of change to the source about the updates to it. diff --git a/src/bmm-skills/2-plan-workflows/bmad-spec/assets/headless-schemas.md b/src/bmm-skills/2-plan-workflows/bmad-spec/assets/headless-schemas.md new file mode 100644 index 000000000..1e1638ce2 --- /dev/null +++ b/src/bmm-skills/2-plan-workflows/bmad-spec/assets/headless-schemas.md @@ -0,0 +1,65 @@ +# Headless JSON Schemas + +The default invocation is headless: input goes in, JSON comes out. Omit keys for artifacts not produced. + +## Common fields + +- `status` — `"complete"`, `"partial"`, or `"blocked"` +- `intent` — `"create"`, `"update"`, or `"validate"` (inferred from inputs) +- `reason` — required when `status` is `"blocked"`; one-sentence explanation +- `assumptions` — array of inferred values not directly confirmed by inputs +- `open_questions` — array of gaps that need a human decision + +## Create / Update + +```json +{ + "status": "complete", + "intent": "create", + "spec_path": "{run_folder}/prd-spec-20260518-1432.md", + "decision_log_path": "{run_folder}/.decision-log.md", + "source_artifact": "{run_folder}/prd.md", + "capabilities": [ + {"id": "CAP-1", "intent": "User can record a voice memo pinned to current GPS coords."}, + {"id": "CAP-2", "intent": "User hears memos auto-trigger when walking within range of a drop."} + ], + "verdict": "Ready for downstream. All six Spec Law rules pass.", + "assumptions": [], + "open_questions": [] +} +``` + +- `spec_path` follows the **Workspace** rules in `SKILL.md`: sibling of the source file (`{input-basename}-spec-{datetime}.md`) when input is a local file, or `{planning_artifacts}/specs/{slug}-spec-{datetime}.md` when input is chat-only or remote. +- `source_artifact` is the path consumed when distilling a ceremony doc; `null` for pure brain-dump or chat-only runs. +- `decision_log_path` is included only when a `.decision-log.md` was actually written to (the source's folder already had one). Omit the key entirely otherwise. +- `capabilities` carries IDs and one-line intents only — enough for downstream consumers to address them without re-reading the Spec. +- `verdict` is the one-paragraph self-validate result. When `status` is `"partial"`, the verdict explains what is blocking "ready for downstream." + +## Validate-only + +```json +{ + "status": "complete", + "intent": "validate", + "spec_path": "{run_folder}/prd-spec-20260518-1432.md", + "decision_log_path": "{run_folder}/.decision-log.md", + "verdict": "Two rules weak: success signal is decorative; non-goals section empty.", + "findings": [ + {"rule": "Success signal is concrete", "note": "Currently reads 'users love it' — not testable."}, + {"rule": "Non-goals are explicit", "note": "Section absent."} + ], + "offer_to_update": true +} +``` + +## Blocked + +```json +{ + "status": "blocked", + "intent": "create", + "reason": "Input was a one-line idea with no surrounding context; too thin to distill. Suggest bmad-prd to draw the vision out first." +} +``` + +Always include the intent (best-guess if not certain) and a one-sentence `reason`. diff --git a/src/bmm-skills/2-plan-workflows/bmad-spec/assets/spec-template.md b/src/bmm-skills/2-plan-workflows/bmad-spec/assets/spec-template.md new file mode 100644 index 000000000..1d79556c0 --- /dev/null +++ b/src/bmm-skills/2-plan-workflows/bmad-spec/assets/spec-template.md @@ -0,0 +1,43 @@ +--- +id: SPEC-{slug} +created: {date} +updated: {date} +status: draft +source_artifact: null +--- + +# {Spec Title} + +## Problem + +{One paragraph. What gap, for whom, why now. Concrete: name the user and the gap they're stuck on. 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 signals + +- {One or two sentences. World-change moment, not dashboard. Concrete enough to write a test or run a demonstration against.} + +## Assumptions + + + +- {Statement of fact the Spec proceeded under, e.g. "Assumed mobile-first since input mentioned GPS but no platform."} + +## Open Questions + + + +- {Question phrased so a human can answer it, e.g. "Is offline playback in scope for CAP-2?"} diff --git a/src/bmm-skills/2-plan-workflows/bmad-spec/customize.toml b/src/bmm-skills/2-plan-workflows/bmad-spec/customize.toml new file mode 100644 index 000000000..07b6dcc27 --- /dev/null +++ b/src/bmm-skills/2-plan-workflows/bmad-spec/customize.toml @@ -0,0 +1,48 @@ +# 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. +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" + +# Fallback output path used when the input is a brain dump (no source +# artifact to co-locate next to). When the input IS a ceremony artifact +# inside an existing run folder under {planning_artifacts}, the Spec +# is written as a sibling of that artifact instead and this path is +# unused. +spec_output_path = "{planning_artifacts}/spec" + +# Run folder pattern for the brain-dump fallback path. Resolved against +# {project_name} and {date} at activation. +run_folder_pattern = "spec-{project_name}-{date}" + +# The primary artifact filename. Override if a team prefers `kernel.md` +# or any other convention. +spec_filename = "spec.md"