refactor(bmad-customize): apply QA pass (top 3 recommendations)

Applies the three highest-payoff themes from the quality analysis:

- Labeling + completion contracts: rename ## Purpose to ## Overview,
  add domain framing (what customization means in BMad, typical user
  arrival shapes), add an explicit Completion block with testable
  conditions for "skill run is done"
- Hostile-environment robustness: add On-Activation preflight that
  classifies no-BMad / BMad-without-resolver / full-install states,
  instruct Step 2 to surface scanner errors[] and scanned_roots on
  empty results, add resolver-missing fallback to Step 6.4, add a
  re-enter-Step-4 recovery loop when verify shows the override didn't
  take effect
- Returning-user and iteration experience: add "Audit / iterate"
  intent class in Step 1, lead discovery with already-overridden
  skills for that intent, read existing overrides in Step 3 before
  composing, frame Step 4 as additive-on-top rather than fresh
  authoring, give Cross-cutting intent an explicit Step 3 branch
  that walks agent-vs-workflow with the user

Resolves 12 of 18 observations from the quality report. Lint clean
(scan-path-standards and scan-scripts both 0 findings). Unit tests
still 10/10.
This commit is contained in:
Brian Madison 2026-04-20 21:16:40 -05:00
parent 1e13b75e5b
commit f98977bca2
1 changed files with 51 additions and 8 deletions

View File

@ -5,10 +5,12 @@ description: Help users author or update {project-root}/_bmad/custom overrides f
# BMad Customize # BMad Customize
## Purpose ## Overview
Translate a user's intent ("I want X to behave differently") into a correctly-placed TOML override file in `{project-root}/_bmad/custom/`. Walk them through discovery when they're exploring, route them to the right surface (agent vs workflow) when the ask is ambiguous, author the override conversationally, and verify the merge landed. Translate a user's intent ("I want X to behave differently") into a correctly-placed TOML override file in `{project-root}/_bmad/custom/`. Walk them through discovery when they're exploring, route them to the right surface (agent vs workflow) when the ask is ambiguous, author the override conversationally, and verify the merge landed.
**What customization means in BMad.** Every customizable skill ships a `customize.toml` that declares the knobs it exposes — scalars, arrays, and keyed tables under `[agent]` or `[workflow]`. Users never edit that file. Instead, they write sparse override files to `{project-root}/_bmad/custom/`, and the resolver merges base → team → user at activation. This skill's job is to help users author those override files correctly. Users typically arrive either with a specific skill and change in mind ("make bmad-create-prd require a brief first") or with a broader want ("the PM agent should speak more formally"); you handle both.
Scope for this version: per-skill **agent** overrides (`bmad-agent-<role>.toml` / `.user.toml`) and per-skill **workflow** overrides (`bmad-<workflow>.toml` / `.user.toml`). Central config (`{project-root}/_bmad/custom/config.toml`) is out of scope — flag it and point the user at `docs/how-to/customize-bmad.md` if their ask lives there. Scope for this version: per-skill **agent** overrides (`bmad-agent-<role>.toml` / `.user.toml`) and per-skill **workflow** overrides (`bmad-<workflow>.toml` / `.user.toml`). Central config (`{project-root}/_bmad/custom/config.toml`) is out of scope — flag it and point the user at `docs/how-to/customize-bmad.md` if their ask lives there.
## Desired Outcomes ## Desired Outcomes
@ -26,6 +28,16 @@ Act as a customization guide. Trust the user's domain knowledge; your job is to
## On Activation ## On Activation
### Preflight
Before any other work, verify the project environment supports this skill:
- **No `{project-root}/_bmad/` directory** → BMad is not installed in this project. Tell the user, point them at the BMad install docs, and stop. Don't pretend to discover skills.
- **`{project-root}/_bmad/scripts/resolve_customization.py` missing** → BMad is present but the resolver isn't. Warn the user that the verification step in Step 6 will fall back to a manual check (read the merged files directly and describe what the override will do). Continue.
- **Both present** → normal path, proceed.
### Config and greet
Load available config from `{project-root}/_bmad/config.yaml` and `{project-root}/_bmad/config.user.yaml` (root level). Defaults if missing: `user_name` (BMad), `communication_language` (English). Greet the user and acknowledge the topic. Load available config from `{project-root}/_bmad/config.yaml` and `{project-root}/_bmad/config.user.yaml` (root level). Defaults if missing: `user_name` (BMad), `communication_language` (English). Greet the user and acknowledge the topic.
Treat the user's invoking message as initial intent. Skip discovery if they already named a target skill AND a specific change — go straight to Step 3. Treat the user's invoking message as initial intent. Skip discovery if they already named a target skill AND a specific change — go straight to Step 3.
@ -38,9 +50,10 @@ Read what the user said on invocation:
- **Directed** — Named a specific skill AND a specific change. Capture the pair, jump to Step 3. - **Directed** — Named a specific skill AND a specific change. Capture the pair, jump to Step 3.
- **Exploratory** — General ask ("what can I customize?"). Go to Step 2. - **Exploratory** — General ask ("what can I customize?"). Go to Step 2.
- **Cross-cutting** — Described a change that could live on multiple surfaces ("I want a compliance check before any planning workflow"). Go to Step 3 with extra routing care. - **Audit / iterate** — Wants to review or modify something already customized ("what have I overridden?", "change my bmad-create-prd gate"). Go to Step 2 with audit framing — lead with skills that already have overrides, and when one is picked, read its existing override first.
- **Cross-cutting** — Described a change that could live on multiple surfaces ("I want a compliance check before any planning workflow", "make every PM response include a risk line"). Go to Step 3 with the explicit goal of choosing agent vs workflow and, if agent, pinning down which one.
### Step 2: Discovery (exploratory only) ### Step 2: Discovery
Run: Run:
@ -48,15 +61,28 @@ Run:
python3 {skill-root}/scripts/list_customizable_skills.py --project-root {project-root} python3 {skill-root}/scripts/list_customizable_skills.py --project-root {project-root}
``` ```
Present the returned list grouped by type (agents, workflows). For each entry show: skill name, one-line description, whether an override already exists in `{project-root}/_bmad/custom/`. Ask the user which one they want to customize. If their initial ask hints at a target, surface the likely match first. The scanner returns JSON with `agents`, `workflows`, `scanned_roots`, and `errors`.
If the scanner returns nothing, the project has no customizable skills installed — tell the user and stop. - **Present the list** grouped by type. For each entry show: skill name, one-line description, whether a team or user override already exists.
- **For audit/iterate intents**, lead with entries where `has_team_override` or `has_user_override` is true.
- **Surface any non-empty `errors[]`** — malformed `customize.toml` files and other scanner issues should be shown to the user, not swallowed.
- **If the list is empty**, show `scanned_roots` so the user can see what was searched. If their IDE stores skills elsewhere, ask for the install path and include it when you read the target's `customize.toml` in Step 3. If the project genuinely has no customizable skills installed, say so and stop.
Ask the user which one they want to customize. If their initial ask hints at a target, surface the likely match first.
### Step 3: Determine the right surface ### Step 3: Determine the right surface
Read the target skill's `customize.toml` live — that file IS the schema. The top-level block (`[agent]` or `[workflow]`) tells you the surface type. Read the target skill's `customize.toml` live — that file IS the schema. The top-level block (`[agent]` or `[workflow]`) tells you the surface type.
When the user's intent could be satisfied at either the agent or the workflow layer, apply this heuristic: **If an override file already exists** (`has_team_override` or `has_user_override` from Step 2's scan — or the file is present on disk), read it before composing. Summarize what's currently overridden so the user knows what they're iterating against, not re-authoring from scratch.
**When the user's intent is Cross-cutting** — it could live at either agent or workflow layer — explicitly walk both surfaces with them:
- If they want the change to apply to every workflow a given agent runs, the agent surface is right (e.g. `bmad-agent-pm.toml` with `persistent_facts` or `principles`).
- If they want it scoped to one workflow, the workflow surface is right (e.g. `bmad-create-prd.toml` with `activation_steps_prepend`).
- If they want it scoped to several specific workflows, that's multiple workflow overrides, not an agent override — say so; multi-surface authoring is fine, do them in sequence.
**When the knob is clearly single-surface**, apply the heuristic:
**Workflow-level is better when:** **Workflow-level is better when:**
@ -77,7 +103,9 @@ If the intent lives outside the exposed surface entirely (core workflow logic, s
### Step 4: Compose the override ### Step 4: Compose the override
Walk the user through the relevant fields from the target's `customize.toml` and translate their plain-English intent into TOML. Apply the merge semantics correctly: Walk the user through the relevant fields from the target's `customize.toml` and translate their plain-English intent into TOML. If an existing override was read in Step 3, frame the conversation as "add/change these fields on top of what's already there" rather than starting blank.
Apply the merge semantics correctly:
- **Scalars** (`icon`, `role`, `*_template`, `on_complete`, etc.) — override wins - **Scalars** (`icon`, `role`, `*_template`, `on_complete`, etc.) — override wins
- **Append-only arrays** (`persistent_facts`, `activation_steps_prepend`, `activation_steps_append`, `principles`) — team/user entries append to base defaults in order - **Append-only arrays** (`persistent_facts`, `activation_steps_prepend`, `activation_steps_append`, `principles`) — team/user entries append to base defaults in order
@ -113,8 +141,23 @@ Default the choice based on the change's character (policy → team, personal
``` ```
Display the merged output and point out the fields that changed so the user sees their override took effect. Display the merged output and point out the fields that changed so the user sees their override took effect.
**If the resolver is missing or fails**, fall back: read the three files (`<install-path>/customize.toml`, the written override, and any sibling `.user.toml`) directly, describe how the merge resolves for the fields the user just changed, and tell them the normal verify path is unavailable in this environment.
**If verification shows the override did not take effect** (field unchanged, resolver reports merge conflict, override file not picked up), do not declare success. Explain what the resolver showed, re-enter Step 4 with the verify output as new context — usually the fix is a field name, merge-mode mismatch (e.g. wrote a scalar where the base expects an array), or wrong placement scope.
5. **Close the loop** — summarize what changed, where the file lives, and how to iterate. For team overrides, remind the user to commit the file to git. 5. **Close the loop** — summarize what changed, where the file lives, and how to iterate. For team overrides, remind the user to commit the file to git.
### Completion
The skill run is complete when all of the following are true:
- The override file exists at the chosen path, or the user explicitly aborted.
- The user has seen the resolver output (or the fallback manual merge summary) showing the intended fields took effect.
- The user has acknowledged the summary from step 6.5 — they know where the file lives and how to iterate.
If any of these is missing, the skill is not done — either finish the remaining part or state explicitly that the user is exiting incomplete.
## When This Skill Can't Help ## When This Skill Can't Help
Say so clearly: Say so clearly:
@ -126,5 +169,5 @@ Say so clearly:
## Notes ## Notes
- Override files are sparse. Everything omitted inherits from the layer below (base → team → user). - Override files are sparse. Everything omitted inherits from the layer below (base → team → user).
- IDE install paths vary (`.claude/skills/`, `.cursor/skills/`, `.cline/skills/`, `.continue/skills/`). The scanner covers these. - IDE install paths vary (`.claude/skills/`, `.cursor/skills/`, `.cline/skills/`, `.continue/skills/`). The scanner covers these; if a user's IDE stores skills elsewhere, Step 2 falls back to asking for the path.
- Full reference on the customization surface, merge rules, and central config lives in `docs/how-to/customize-bmad.md`. - Full reference on the customization surface, merge rules, and central config lives in `docs/how-to/customize-bmad.md`.