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
## 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.
**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.
## Desired Outcomes
@ -26,6 +28,16 @@ Act as a customization guide. Trust the user's domain knowledge; your job is to
## 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.
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.
- **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:
@ -48,15 +61,28 @@ Run:
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
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:**
@ -77,7 +103,9 @@ If the intent lives outside the exposed surface entirely (core workflow logic, s
### 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
- **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.
**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.
### 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
Say so clearly:
@ -126,5 +169,5 @@ Say so clearly:
## Notes
- 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`.