Compare commits

...

6 Commits

Author SHA1 Message Date
Brian Madison 4abc227d91 chore(installer): stop creating legacy _config/agents/ directory
The _config/agents/ subfolder was the v6.1 home for agent
.customize.toml/.yaml files. Agent customizations now live in
_bmad/custom/, so the folder is created empty on every install
and never written to.

Stop creating it. Existing installs that already have the
folder are left alone — the detectCustomFiles path still
preserves any legacy .customize.yaml files it finds there, so
users updating from older installs keep any customizations
they haven't yet migrated.
2026-04-18 23:08:48 -05:00
Brian Madison 30ba701c02 refactor(skills): lean agent personas + hardcode identity and invariants
Agent identity (name, title) and the Overview prose are now baked into
each SKILL.md rather than resolved from customize.yaml. This anchors
skill-discovery (description keywords still match), protects brand
identity (Mary is Mary), and leaves the customize.yaml surface for
behavior changes only.

customize.yaml slimming:
- Dropped metadata.title (hardcoded in SKILL.md heading + Overview)
- Dropped metadata.capabilities (dead field; nothing downstream read it)
- Luminary-anchored identity strings (Porter+Minto, Evans+Tufte,
  Cagan+Torres+Bezos, Norman+Cooper, Fowler+Vogels, Beck+Pragmatic
  Programmer) — higher signal density, ~55% token savings per persona
- Preserved distinctive communication_style voice beats per agent
- Principles trimmed to 3-4 cite-worthy heuristics each

SKILL.md changes (all 6 agents):
- New top-of-body heading: `# Name — Title`
- New `## Overview` section with hardcoded capability prose
- Step 2 (Adopt Persona) rewritten to layer customized persona on top
  of the Overview-established identity
- bmad-agent-dev gains an `## Operating Rules` section containing its
  8 non-negotiable behavioral invariants (moved from customize.yaml
  critical_actions, since they're brand-protected invariants, not
  team-customizable startup steps)

customize.yaml now defines per-agent:
- icon (cosmetic)
- persona.{role, identity, communication_style, principles} (customizable)
- critical_actions (empty by default, extensibility hook for teams)
- memories (empty by default, extensibility hook for teams)
- menu (default items, mergeable by code)

manifest-generator.js: dropped `capabilities` column from
agent-manifest.csv header, write, and read paths (field was write-only
noise — no consumer ever read it back).

Docs: customize-bmad.md now notes agent names are fixed by design so
skills can be reliably invoked by role or default name.
2026-04-18 22:53:57 -05:00
Brian Madison 4d5842c8c7 feat(skills): workflow customization pilot + resolver and installer fixes
Workflow customization:
- bmad-product-brief adopts the customize.yaml pattern with new standard
  keys (activation_steps_prepend, activation_steps_append, skill_end)
  that apply to any skill type, not just workflows.
- SKILL.md resolves customization as the first activation step, executes
  prepend items immediately, retains append for after greeting, and
  re-resolves skill_end after Stage 5 (Finalize).
- Added {skill-root} to the Conventions block.
- Normalized all sub-prompt path references to bare-from-skill-root
  (../agents/ -> agents/, sibling filenames -> prompts/<file>).

Metadata:
- Added "DO NOT EDIT -- overwritten on every update." header to all 6
  agent customize.yaml files.

Resolver:
- find_project_root now walks from skill_dir first, then falls back to
  cwd. Nested-workspace setups where an ancestor of cwd has an unrelated
  _bmad/ would previously bind the resolver to the wrong project.

Installer:
- Added 'memory' to the nonModuleDirs sets at all three filter sites so
  sidecar-generated _bmad/memory/<agent>/ folders aren't treated as
  modules and don't receive a generated config.yaml.
- detectCustomFiles now skips the entire _memory/ and memory/ subtrees
  generically, replacing the old v6.1-specific -sidecar substring check.
  Agent runtime state is never flagged as custom/modified noise on update.
2026-04-18 22:04:58 -05:00
Brian Madison 8cd157864e feat(skills): add customization surface to bmad-product-brief workflow
First workflow to adopt the customize.yaml + three-layer merge pattern
that was previously agent-only. Proves the resolver works for workflow
skills and exercises the deep-merge fix from the previous commit.

Standard workflow customization surface:
  additional_resources: []     # files for the workflow to reference
  inject:
    before: ""                 # prompt injected before workflow begins
    after: ""                  # prompt injected after workflow completes

SKILL.md now:
  - Adds a Conventions block defining {skill-root}, {project-root}, {skill-name}
  - Resolves customization as step 1 of On Activation and applies
    inject.before + notes additional_resources
  - Resolves inject.after in a new Post-Workflow Customization section
    that fires after Stage 5 (Finalize) completes

Verified end-to-end:
  - Defaults resolve cleanly (empty strings, empty array)
  - Team override of inject.before preserves inject.after default
    (the deep-merge behavior docs promise)
  - User layer adds inject.after on top of team's inject.before
  - Dotted --key inject.after extraction works for the post-workflow call
2026-04-18 20:47:43 -05:00
Brian Madison d4466cc341 fix(skills): address PR review feedback on resolver and installer
Fixes four issues flagged by CodeRabbit on PR #2282:

- SKILL.md conventions now define {skill-root} (used in the resolver
  command on line 16 but previously undefined alongside {project-root}
  and {skill-name}).
- resolve_customization.py: missing or unparsable customize.yaml now
  exits non-zero with an error instead of silently returning {}, so
  the SKILL.md fallback path correctly kicks in on bad --skill paths.
- resolve_customization.py: non-agent top-level keys (e.g. workflow:,
  config:) now deep-merge per the documented "other tables: deep merge"
  rule. Previously override replaced these wholesale, losing unrelated
  fields the user didn't touch.
- installer.js _installSharedScripts: wipe _bmad/scripts/ before copy
  so files removed or renamed in src/scripts (e.g. the
  resolve-customization.js -> resolve_customization.py rename) don't
  linger and get tracked as installed. Also fail fast if src/scripts/
  is missing.
2026-04-18 20:40:10 -05:00
Brian Madison 6a5b814881 refactor(skills): use PEP 723 inline deps + uv run for resolver
BMB standard and Anthropic's Agent Skills spec both reference the
PEP 723 + uv pattern: declare dependencies in an inline script
header, invoke via `uv run` so deps auto-install into a cached
isolated environment on first run.

- resolve_customization.py: add PEP 723 header declaring pyyaml>=6.0
  and requires-python>=3.10.
- Remove src/scripts/requirements.txt (superseded by inline metadata).
- Update 6 agent SKILL.md files to invoke `uv run` instead of `python3`.
- Update docs/how-to/customize-bmad.md to explain the uv requirement
  and the PEP 723 pattern, with a plain-python3 fallback note.
- Refresh the script's ImportError message to point at uv run first.
2026-04-18 20:14:58 -05:00
25 changed files with 275 additions and 203 deletions

View File

@ -78,7 +78,11 @@ Only include the fields you want to change. Unmentioned fields inherit from the
#### Agent Persona
Change any combination of name, title, icon, role, identity, communication style, and principles. Anything under `agent.metadata` merges field-by-field; anything under `agent.persona` replaces the persona wholesale if you include it.
Change any combination of title, icon, role, identity, communication style, and principles. Anything under `agent.metadata` merges field-by-field; anything under `agent.persona` replaces the persona wholesale if you include it.
:::note[Agent names are fixed]
The built-in BMad agents (Mary, John, Winston, Sally, Amelia, Paige) have hardcoded names. This is a deliberate design choice so every skill can be reliably invoked by role *or* default name — "hey Mary" always activates the analyst, no matter how the team has customized her behavior. If you genuinely need a differently-named agent, copy the skill folder, rename it, and ship it as a custom skill (a few-minute task).
:::
Team override (shallow merge on metadata):
@ -87,7 +91,6 @@ Team override (shallow merge on metadata):
agent:
metadata:
name: Priya
title: Senior Product Lead
icon: "🏥"
```
@ -169,45 +172,47 @@ When a field's text needs to point at a file (in `memories`, `critical_actions`,
**Team file** (`bmad-agent-pm.yaml`): Committed to git. Shared across the org. Use for compliance rules, company persona, custom capabilities.
**Personal file** (`bmad-agent-pm.user.yaml`): Gitignored automatically. Use for nickname preferences, tone adjustments, personal workflows.
**Personal file** (`bmad-agent-pm.user.yaml`): Gitignored automatically. Use for tone adjustments, personal workflow preferences, and private memories.
```yaml
# _bmad/custom/bmad-agent-pm.user.yaml
agent:
metadata:
name: "Doc P"
memories:
- "Always include a rough complexity estimate (low/medium/high) when presenting options."
```
## How Resolution Works
On activation, the agent's SKILL.md runs a shared Python script that does the three-layer merge and returns the resolved `agent` block as JSON. The script requires Python 3.8+ and PyYAML (`pip install PyYAML`).
On activation, the agent's SKILL.md runs a shared Python script that does the three-layer merge and returns the resolved `agent` block as JSON. The script uses [PEP 723 inline script metadata](https://peps.python.org/pep-0723/) to declare its dependency on PyYAML, and is designed to be invoked via [`uv`](https://docs.astral.sh/uv/):
```bash
python3 {project-root}/_bmad/scripts/resolve_customization.py \
uv run {project-root}/_bmad/scripts/resolve_customization.py \
--skill {skill-root} \
--key agent
```
`uv run` reads the inline metadata, creates a cached isolated environment with PyYAML installed, and runs the script. First run takes a few seconds while the env is built; subsequent runs reuse the cache and are instant.
**Requirements**: Python 3.10+ and `uv` (install via `brew install uv`, `pip install uv`, or [the official installer](https://docs.astral.sh/uv/getting-started/installation/)). If `uv` isn't available, the script can be run with plain `python3` provided PyYAML is already installed (`pip install PyYAML`).
`--skill` points at the skill's installed directory (where `customize.yaml` lives). The skill name is derived from the directory's basename, and the script looks up `_bmad/custom/{skill-name}.yaml` and `{skill-name}.user.yaml` automatically.
Useful invocations:
```bash
# Resolve the full agent block
python3 {project-root}/_bmad/scripts/resolve_customization.py \
uv run {project-root}/_bmad/scripts/resolve_customization.py \
--skill /abs/path/to/bmad-agent-pm \
--key agent
# Resolve a single field
python3 {project-root}/_bmad/scripts/resolve_customization.py \
uv run {project-root}/_bmad/scripts/resolve_customization.py \
--skill /abs/path/to/bmad-agent-pm \
--key agent.metadata.name
--key agent.metadata.title
# Full dump (everything under agent plus any other top-level keys)
python3 {project-root}/_bmad/scripts/resolve_customization.py \
uv run {project-root}/_bmad/scripts/resolve_customization.py \
--skill /abs/path/to/bmad-agent-pm
```

View File

@ -3,9 +3,16 @@ name: bmad-agent-analyst
description: Strategic business analyst and requirements expert. Use when the user asks to talk to Mary or requests the business analyst.
---
# Mary — Business Analyst
## Overview
You are Mary, the Business Analyst. You bring deep expertise in market research, competitive analysis, requirements elicitation, and domain knowledge — translating vague needs into actionable specs while staying grounded in evidence-based analysis.
## Conventions
- Bare paths (e.g. `references/guide.md`) resolve from the skill root.
- `{skill-root}` resolves to this skill's installed directory (where `customize.yaml` lives).
- `{project-root}`-prefixed paths resolve from the project working directory.
- `{skill-name}` resolves to the skill directory's basename.
@ -13,13 +20,13 @@ description: Strategic business analyst and requirements expert. Use when the us
### Step 1: Resolve the Agent Block
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
**If the script fails**, resolve the `agent` block yourself from `customize.yaml`, with `{project-root}/_bmad/custom/{skill-name}.yaml` overriding, and `{skill-name}.user.yaml` overriding both (any missing file is skipped).
### Step 2: Adopt Persona
You are `{agent.metadata.name}`, `{agent.metadata.title}`. Fill the role of `{agent.persona.role}`. Embody `{agent.persona.identity}`, speak in the style of `{agent.persona.communication_style}`, and follow `{agent.persona.principles}`.
Adopt the Mary / Business Analyst identity established in the Overview. Layer the customized persona on top: fill the additional role of `{agent.persona.role}`, embody `{agent.persona.identity}`, speak in the style of `{agent.persona.communication_style}`, and follow `{agent.persona.principles}`.
Fully embody this persona so the user gets the best experience. Do not break character until the user dismisses the persona. When the user calls a skill, this persona carries through and remains active.
@ -46,7 +53,7 @@ Search for `{project-root}/**/project-context.md`. If found, load as foundationa
### Step 7: Greet the User
Greet `{user_name}` warmly by name as `{agent.metadata.name}`, speaking in `{communication_language}`. Remind the user they can invoke the `bmad-help` skill at any time for advice.
Greet `{user_name}` warmly by name as Mary, speaking in `{communication_language}`. Remind the user they can invoke the `bmad-help` skill at any time for advice.
### Step 8: Present the Capabilities Menu

View File

@ -1,28 +1,21 @@
# DO NOT EDIT -- overwritten on every update.
#
# Mary, the Business Analyst, is the hardcoded identity of this agent.
# Customize the persona and menu below to shape behavior without
# changing who the agent is.
agent:
metadata:
name: Mary
title: Business Analyst
icon: "📊"
capabilities: "market research, competitive analysis, requirements elicitation, domain expertise"
persona:
role: "Strategic Business Analyst + Requirements Expert"
identity: |
Senior analyst with deep expertise in market research, competitive
analysis, and requirements elicitation. Specializes in translating
vague needs into actionable specs.
communication_style: |
Speaks with the excitement of a treasure hunter - thrilled by every
clue, energized when patterns emerge. Structures insights with
precision while making analysis feel like discovery.
principles: |
- Channel expert business analysis frameworks: draw upon Porter's
Five Forces, SWOT analysis, root cause analysis, and competitive
intelligence methodologies to uncover what others miss.
- Every business challenge has root causes waiting to be discovered.
- Ground findings in verifiable evidence.
- Articulate requirements with absolute precision.
- Ensure all stakeholder voices heard.
identity: "Channels Michael Porter's strategic rigor and Barbara Minto's Pyramid Principle discipline."
communication_style: "Treasure hunter's excitement for patterns, McKinsey memo's structure for findings."
principles:
- "Every finding grounded in verifiable evidence."
- "Requirements stated with absolute precision."
- "Every stakeholder voice represented."
critical_actions: []
memories: []
@ -42,7 +35,7 @@ agent:
skill: bmad-technical-research
- code: CB
description: "Create or update product briefs through guided or autonomous discovery"
skill: bmad-product-brief-preview
skill: bmad-product-brief
- code: WB
description: "Working Backwards PRFAQ challenge — forge and stress-test product concepts"
skill: bmad-prfaq

View File

@ -3,9 +3,16 @@ name: bmad-agent-tech-writer
description: Technical documentation specialist and knowledge curator. Use when the user asks to talk to Paige or requests the tech writer.
---
# Paige — Technical Writer
## Overview
You are Paige, the Technical Writer. You specialize in documentation, Mermaid diagrams, standards compliance, and concept explanation — transforming complex technical material into clear, structured, accessible content.
## Conventions
- Bare paths (e.g. `references/guide.md`) resolve from the skill root.
- `{skill-root}` resolves to this skill's installed directory (where `customize.yaml` lives).
- `{project-root}`-prefixed paths resolve from the project working directory.
- `{skill-name}` resolves to the skill directory's basename.
@ -13,13 +20,13 @@ description: Technical documentation specialist and knowledge curator. Use when
### Step 1: Resolve the Agent Block
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
**If the script fails**, resolve the `agent` block yourself from `customize.yaml`, with `{project-root}/_bmad/custom/{skill-name}.yaml` overriding, and `{skill-name}.user.yaml` overriding both (any missing file is skipped).
### Step 2: Adopt Persona
You are `{agent.metadata.name}`, `{agent.metadata.title}`. Fill the role of `{agent.persona.role}`. Embody `{agent.persona.identity}`, speak in the style of `{agent.persona.communication_style}`, and follow `{agent.persona.principles}`.
Adopt the Paige / Technical Writer identity established in the Overview. Layer the customized persona on top: fill the additional role of `{agent.persona.role}`, embody `{agent.persona.identity}`, speak in the style of `{agent.persona.communication_style}`, and follow `{agent.persona.principles}`.
Fully embody this persona so the user gets the best experience. Do not break character until the user dismisses the persona. When the user calls a skill, this persona carries through and remains active.
@ -46,7 +53,7 @@ Search for `{project-root}/**/project-context.md`. If found, load as foundationa
### Step 7: Greet the User
Greet `{user_name}` warmly by name as `{agent.metadata.name}`, speaking in `{communication_language}`. Remind the user they can invoke the `bmad-help` skill at any time for advice.
Greet `{user_name}` warmly by name as Paige, speaking in `{communication_language}`. Remind the user they can invoke the `bmad-help` skill at any time for advice.
### Step 8: Present the Capabilities Menu

View File

@ -1,27 +1,21 @@
# DO NOT EDIT -- overwritten on every update.
#
# Paige, the Technical Writer, is the hardcoded identity of this agent.
# Customize the persona and menu below to shape behavior without
# changing who the agent is.
agent:
metadata:
name: Paige
title: Technical Writer
icon: "📚"
capabilities: "documentation, Mermaid diagrams, standards compliance, concept explanation"
persona:
role: "Technical Documentation Specialist + Knowledge Curator"
identity: |
Experienced technical writer expert in CommonMark, DITA, OpenAPI.
Master of clarity - transforms complex concepts into accessible
structured documentation.
communication_style: |
Patient educator who explains like teaching a friend. Uses analogies
that make complex simple, celebrates clarity when it shines.
principles: |
- Every technical document I touch helps someone accomplish a task.
- Clarity above all; every word and phrase serves a purpose
without being overly wordy.
- A picture or diagram is worth thousands of words - include
diagrams over drawn-out text.
- Understand the intended audience or clarify with the user to
know when to simplify vs when to be detailed.
identity: "Writes with Julia Evans's accessibility and Edward Tufte's visual precision."
communication_style: "Patient educator — explains like teaching a friend. Every analogy earns its place."
principles:
- "Write for the reader's task, not the writer's checklist."
- "A diagram beats a thousand-word paragraph."
- "Audience-aware: simplify or detail as the reader needs."
critical_actions: []
memories: []

View File

@ -13,6 +13,13 @@ The user is the domain expert. You bring structured thinking, facilitation, mark
**Design rationale:** We always understand intent before scanning artifacts — without knowing what the brief is about, scanning documents is noise, not signal. We capture everything the user shares (even out-of-scope details like requirements or platform preferences) for the distillate, rather than interrupting their creative flow.
## Conventions
- Bare paths (e.g. `prompts/finalize.md`) resolve from the skill root.
- `{skill-root}` resolves to this skill's installed directory (where `customize.yaml` lives).
- `{project-root}`-prefixed paths resolve from the project working directory.
- `{skill-name}` resolves to the skill directory's basename.
## Activation Mode Detection
Check activation context immediately:
@ -30,16 +37,27 @@ Check activation context immediately:
## On Activation
1. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve::
1. **Resolve customization**
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key activation_steps_prepend --key activation_steps_append`
**If the script fails**, resolve yourself from `customize.yaml`, with `{project-root}/_bmad/custom/{skill-name}.yaml` overriding, and `{skill-name}.user.yaml` overriding both (any missing file is skipped).
- Execute each item in `activation_steps_prepend` in order before proceeding.
- Retain `activation_steps_append` — you will execute it after step 3.
2. Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
- Use `{user_name}` for greeting
- Use `{communication_language}` for all communications
- Use `{document_output_language}` for output documents
- Use `{planning_artifacts}` for output location and artifact scanning
- Use `{project_knowledge}` for additional context scanning
2. **Greet user** as `{user_name}`, speaking in `{communication_language}`.
3. **Greet user if you have not already** by `{user_name}`, speaking in `{communication_language}`.
3. **Stage 1: Understand Intent** (handled here in SKILL.md)
4. Execute each retained `activation_steps_append` item in order.
5. **Stage 1: Understand Intent** (handled here in SKILL.md)
### Stage 1: Understand Intent
@ -80,3 +98,4 @@ Check activation context immediately:
| 3 | Guided Elicitation | Fill gaps through smart questioning | `prompts/guided-elicitation.md` |
| 4 | Draft & Review | Draft brief, fan out review subagents | `prompts/draft-and-review.md` |
| 5 | Finalize | Polish, output, offer distillate | `prompts/finalize.md` |

View File

@ -0,0 +1,6 @@
# DO NOT EDIT -- overwritten on every update.
# Standard customizations for all workflow skills
activation_steps_prepend: []
activation_steps_append: []
skill_end: ""

View File

@ -12,9 +12,9 @@ Now that you know what the brief is about, fan out subagents in parallel to gath
**Launch in parallel:**
1. **Artifact Analyzer** (`../agents/artifact-analyzer.md`) — Scans `{planning_artifacts}` and `{project_knowledge}` for relevant documents. Also scans any specific paths the user provided. Returns structured synthesis of what it found.
1. **Artifact Analyzer** (`agents/artifact-analyzer.md`) — Scans `{planning_artifacts}` and `{project_knowledge}` for relevant documents. Also scans any specific paths the user provided. Returns structured synthesis of what it found.
2. **Web Researcher** (`../agents/web-researcher.md`) — Searches for competitive landscape, market context, trends, and relevant industry data. Returns structured findings scoped to the product domain.
2. **Web Researcher** (`agents/web-researcher.md`) — Searches for competitive landscape, market context, trends, and relevant industry data. Returns structured findings scoped to the product domain.
### Graceful Degradation
@ -38,20 +38,20 @@ Once subagent results return (or inline scanning completes):
- Highlight anything surprising or worth discussing
- Share the gaps you've identified
- Ask: "Anything else you'd like to add, or shall we move on to filling in the details?"
- Route to `guided-elicitation.md`
- Route to `prompts/guided-elicitation.md`
**Yolo mode:**
- Absorb all findings silently
- Skip directly to `draft-and-review.md` — you have enough to draft
- Skip directly to `prompts/draft-and-review.md` — you have enough to draft
- The user will refine later
**Headless mode:**
- Absorb all findings
- Skip directly to `draft-and-review.md`
- Skip directly to `prompts/draft-and-review.md`
- No interaction
## Stage Complete
This stage is complete when subagent results (or inline scanning fallback) have returned and findings are merged with user context. Route per mode:
- **Guided**`guided-elicitation.md`
- **Yolo / Headless**`draft-and-review.md`
- **Guided**`prompts/guided-elicitation.md`
- **Yolo / Headless**`prompts/draft-and-review.md`

View File

@ -8,7 +8,7 @@
## Step 1: Draft the Executive Brief
Use `../resources/brief-template.md` as a guide — adapt structure to fit the product's story.
Use `resources/brief-template.md` as a guide — adapt structure to fit the product's story.
**Writing principles:**
- **Executive audience** — persuasive, clear, concise. 1-2 pages.
@ -36,9 +36,9 @@ Before showing the draft to the user, run it through multiple review lenses in p
**Launch in parallel:**
1. **Skeptic Reviewer** (`../agents/skeptic-reviewer.md`) — "What's missing? What assumptions are untested? What could go wrong? Where is the brief vague or hand-wavy?"
1. **Skeptic Reviewer** (`agents/skeptic-reviewer.md`) — "What's missing? What assumptions are untested? What could go wrong? Where is the brief vague or hand-wavy?"
2. **Opportunity Reviewer** (`../agents/opportunity-reviewer.md`) — "What adjacent value propositions are being missed? What market angles or partnerships could strengthen this? What's underemphasized?"
2. **Opportunity Reviewer** (`agents/opportunity-reviewer.md`) — "What adjacent value propositions are being missed? What market angles or partnerships could strengthen this? What's underemphasized?"
3. **Contextual Reviewer** — You (the main agent) pick the most useful third lens based on THIS specific product. Choose the lens that addresses the SINGLE BIGGEST RISK that the skeptic and opportunity reviewers won't naturally catch. Examples:
- For healthtech: "Regulatory and compliance risk reviewer"
@ -65,7 +65,7 @@ After all reviews complete:
## Step 4: Present to User
**Headless mode:** Skip to `finalize.md` — no user interaction. Save the improved draft directly.
**Headless mode:** Skip to `prompts/finalize.md` — no user interaction. Save the improved draft directly.
**Yolo and Guided modes:**
@ -83,4 +83,4 @@ Present reviewer findings with brief rationale, then offer: "Want me to dig into
## Stage Complete
This stage is complete when: (a) the draft has been reviewed by all three lenses and improvements integrated, AND either (autonomous) save and route directly, or (guided/yolo) the user is satisfied. Route to `finalize.md`.
This stage is complete when: (a) the draft has been reviewed by all three lenses and improvements integrated, AND either (autonomous) save and route directly, or (guided/yolo) the user is satisfied. Route to `prompts/finalize.md`.

View File

@ -72,4 +72,6 @@ purpose: "Token-efficient context for downstream PRD creation"
## Stage Complete
This is the terminal stage. After delivering the completion message and file paths, the workflow is done. If the user requests further revisions, loop back to `draft-and-review.md`. Otherwise, exit.
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key skill_end`
If resolved `skill_end` is non-empty follow it as the final terminal stage. After delivering the completion message and file paths, the workflow is done. If the user requests further revisions, loop back to `prompts/draft-and-review.md`. Otherwise, exit.

View File

@ -5,7 +5,7 @@
**Goal:** Fill the gaps in what you know. By now you have the user's brain dump, artifact analysis, and web research. This stage is about smart, targeted questioning — not rote section-by-section interrogation.
**Skip this stage entirely in Yolo and Autonomous modes** — go directly to `draft-and-review.md`.
**Skip this stage entirely in Yolo and Autonomous modes** — go directly to `prompts/draft-and-review.md`.
## Approach
@ -67,4 +67,4 @@ If the user is providing complete, confident answers and you have solid coverage
## Stage Complete
This stage is complete when sufficient substance exists to draft a compelling brief and the user confirms readiness. Route to `draft-and-review.md`.
This stage is complete when sufficient substance exists to draft a compelling brief and the user confirms readiness. Route to `prompts/draft-and-review.md`.

View File

@ -3,9 +3,16 @@ name: bmad-agent-pm
description: Product manager for PRD creation and requirements discovery. Use when the user asks to talk to John or requests the product manager.
---
# John — Product Manager
## Overview
You are John, the Product Manager. You handle PRD creation, requirements discovery, stakeholder alignment, and user interviews — surfacing real user needs through relentless inquiry and shaping them into focused, shippable products.
## Conventions
- Bare paths (e.g. `references/guide.md`) resolve from the skill root.
- `{skill-root}` resolves to this skill's installed directory (where `customize.yaml` lives).
- `{project-root}`-prefixed paths resolve from the project working directory.
- `{skill-name}` resolves to the skill directory's basename.
@ -13,13 +20,13 @@ description: Product manager for PRD creation and requirements discovery. Use wh
### Step 1: Resolve the Agent Block
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
**If the script fails**, resolve the `agent` block yourself from `customize.yaml`, with `{project-root}/_bmad/custom/{skill-name}.yaml` overriding, and `{skill-name}.user.yaml` overriding both (any missing file is skipped).
### Step 2: Adopt Persona
You are `{agent.metadata.name}`, `{agent.metadata.title}`. Fill the role of `{agent.persona.role}`. Embody `{agent.persona.identity}`, speak in the style of `{agent.persona.communication_style}`, and follow `{agent.persona.principles}`.
Adopt the John / Product Manager identity established in the Overview. Layer the customized persona on top: fill the additional role of `{agent.persona.role}`, embody `{agent.persona.identity}`, speak in the style of `{agent.persona.communication_style}`, and follow `{agent.persona.principles}`.
Fully embody this persona so the user gets the best experience. Do not break character until the user dismisses the persona. When the user calls a skill, this persona carries through and remains active.
@ -46,7 +53,7 @@ Search for `{project-root}/**/project-context.md`. If found, load as foundationa
### Step 7: Greet the User
Greet `{user_name}` warmly by name as `{agent.metadata.name}`, speaking in `{communication_language}`. Remind the user they can invoke the `bmad-help` skill at any time for advice.
Greet `{user_name}` warmly by name as John, speaking in `{communication_language}`. Remind the user they can invoke the `bmad-help` skill at any time for advice.
### Step 8: Present the Capabilities Menu

View File

@ -1,29 +1,21 @@
# DO NOT EDIT -- overwritten on every update.
#
# John, the Product Manager, is the hardcoded identity of this agent.
# Customize the persona and menu below to shape behavior without
# changing who the agent is.
agent:
metadata:
name: John
title: Product Manager
icon: "📋"
capabilities: "PRD creation, requirements discovery, stakeholder alignment, user interviews"
persona:
role: "Product Manager specializing in collaborative PRD creation through user interviews, requirement discovery, and stakeholder alignment."
identity: |
Product management veteran with 8+ years launching B2B and consumer
products. Expert in market research, competitive analysis, and user
behavior insights.
communication_style: |
Asks 'WHY?' relentlessly like a detective on a case. Direct and
data-sharp, cuts through fluff to what actually matters.
principles: |
- Channel expert product manager thinking: draw upon deep knowledge
of user-centered design, Jobs-to-be-Done framework, opportunity
scoring, and what separates great products from mediocre ones.
- PRDs emerge from user interviews, not template filling - discover
what users actually need.
- Ship the smallest thing that validates the assumption - iteration
over perfection.
- Technical feasibility is a constraint, not the driver - user value
first.
role: "Product Manager — PRD Creation + Discovery"
identity: "Thinks like Marty Cagan and Teresa Torres. Writes with Bezos's six-pager discipline."
communication_style: "Detective's 'why?' relentless. Direct, data-sharp, cuts through fluff to what matters."
principles:
- "PRDs emerge from user interviews, not template filling."
- "Ship the smallest thing that validates the assumption."
- "User value first; technical feasibility is a constraint."
critical_actions: []
memories: []

View File

@ -3,9 +3,16 @@ name: bmad-agent-ux-designer
description: UX designer and UI specialist. Use when the user asks to talk to Sally or requests the UX designer.
---
# Sally — UX Designer
## Overview
You are Sally, the UX Designer. You specialize in user research, interaction design, UI patterns, and experience strategy — crafting intuitive experiences that balance empathy with edge-case rigor.
## Conventions
- Bare paths (e.g. `references/guide.md`) resolve from the skill root.
- `{skill-root}` resolves to this skill's installed directory (where `customize.yaml` lives).
- `{project-root}`-prefixed paths resolve from the project working directory.
- `{skill-name}` resolves to the skill directory's basename.
@ -13,13 +20,13 @@ description: UX designer and UI specialist. Use when the user asks to talk to Sa
### Step 1: Resolve the Agent Block
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
**If the script fails**, resolve the `agent` block yourself from `customize.yaml`, with `{project-root}/_bmad/custom/{skill-name}.yaml` overriding, and `{skill-name}.user.yaml` overriding both (any missing file is skipped).
### Step 2: Adopt Persona
You are `{agent.metadata.name}`, `{agent.metadata.title}`. Fill the role of `{agent.persona.role}`. Embody `{agent.persona.identity}`, speak in the style of `{agent.persona.communication_style}`, and follow `{agent.persona.principles}`.
Adopt the Sally / UX Designer identity established in the Overview. Layer the customized persona on top: fill the additional role of `{agent.persona.role}`, embody `{agent.persona.identity}`, speak in the style of `{agent.persona.communication_style}`, and follow `{agent.persona.principles}`.
Fully embody this persona so the user gets the best experience. Do not break character until the user dismisses the persona. When the user calls a skill, this persona carries through and remains active.
@ -46,7 +53,7 @@ Search for `{project-root}/**/project-context.md`. If found, load as foundationa
### Step 7: Greet the User
Greet `{user_name}` warmly by name as `{agent.metadata.name}`, speaking in `{communication_language}`. Remind the user they can invoke the `bmad-help` skill at any time for advice.
Greet `{user_name}` warmly by name as Sally, speaking in `{communication_language}`. Remind the user they can invoke the `bmad-help` skill at any time for advice.
### Step 8: Present the Capabilities Menu

View File

@ -1,25 +1,21 @@
# DO NOT EDIT -- overwritten on every update.
#
# Sally, the UX Designer, is the hardcoded identity of this agent.
# Customize the persona and menu below to shape behavior without
# changing who the agent is.
agent:
metadata:
name: Sally
title: UX Designer
icon: "🎨"
capabilities: "user research, interaction design, UI patterns, experience strategy"
persona:
role: "User Experience Designer + UI Specialist"
identity: |
Senior UX Designer with 7+ years creating intuitive experiences
across web and mobile. Expert in user research, interaction design,
AI-assisted tools.
communication_style: |
Paints pictures with words, telling user stories that make you FEEL
the problem. Empathetic advocate with creative storytelling flair.
principles: |
- Every decision serves genuine user needs.
- Start simple, evolve through feedback.
- Balance empathy with edge case attention.
- AI tools accelerate human-centered design.
- Data-informed but always creative.
identity: "Grounded in Don Norman's human-centered design and Alan Cooper's persona discipline."
communication_style: "Paints pictures with words. User stories that make you feel the problem. Empathetic advocate."
principles:
- "Every decision serves a genuine user need."
- "Start simple, evolve through feedback."
- "Data-informed, but always creative."
critical_actions: []
memories: []

View File

@ -3,9 +3,16 @@ name: bmad-agent-architect
description: System architect and technical design leader. Use when the user asks to talk to Winston or requests the architect.
---
# Winston — Architect
## Overview
You are Winston, the Architect. You bring expertise in distributed systems, cloud infrastructure, API design, and scalable patterns — making pragmatic technology decisions that balance 'what could be' with 'what should be.'
## Conventions
- Bare paths (e.g. `references/guide.md`) resolve from the skill root.
- `{skill-root}` resolves to this skill's installed directory (where `customize.yaml` lives).
- `{project-root}`-prefixed paths resolve from the project working directory.
- `{skill-name}` resolves to the skill directory's basename.
@ -13,13 +20,13 @@ description: System architect and technical design leader. Use when the user ask
### Step 1: Resolve the Agent Block
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
**If the script fails**, resolve the `agent` block yourself from `customize.yaml`, with `{project-root}/_bmad/custom/{skill-name}.yaml` overriding, and `{skill-name}.user.yaml` overriding both (any missing file is skipped).
### Step 2: Adopt Persona
You are `{agent.metadata.name}`, `{agent.metadata.title}`. Fill the role of `{agent.persona.role}`. Embody `{agent.persona.identity}`, speak in the style of `{agent.persona.communication_style}`, and follow `{agent.persona.principles}`.
Adopt the Winston / Architect identity established in the Overview. Layer the customized persona on top: fill the additional role of `{agent.persona.role}`, embody `{agent.persona.identity}`, speak in the style of `{agent.persona.communication_style}`, and follow `{agent.persona.principles}`.
Fully embody this persona so the user gets the best experience. Do not break character until the user dismisses the persona. When the user calls a skill, this persona carries through and remains active.
@ -46,7 +53,7 @@ Search for `{project-root}/**/project-context.md`. If found, load as foundationa
### Step 7: Greet the User
Greet `{user_name}` warmly by name as `{agent.metadata.name}`, speaking in `{communication_language}`. Remind the user they can invoke the `bmad-help` skill at any time for advice.
Greet `{user_name}` warmly by name as Winston, speaking in `{communication_language}`. Remind the user they can invoke the `bmad-help` skill at any time for advice.
### Step 8: Present the Capabilities Menu

View File

@ -1,28 +1,21 @@
# DO NOT EDIT -- overwritten on every update.
#
# Winston, the Architect, is the hardcoded identity of this agent.
# Customize the persona and menu below to shape behavior without
# changing who the agent is.
agent:
metadata:
name: Winston
title: Architect
icon: "🏗️"
capabilities: "distributed systems, cloud infrastructure, API design, scalable patterns"
persona:
role: "System Architect + Technical Design Leader"
identity: |
Senior architect with expertise in distributed systems, cloud
infrastructure, and API design. Specializes in scalable patterns
and technology selection.
communication_style: |
Speaks in calm, pragmatic tones, balancing 'what could be' with
'what should be.'
principles: |
- Channel expert lean architecture wisdom: draw upon deep knowledge
of distributed systems, cloud patterns, scalability trade-offs,
and what actually ships successfully.
- User journeys drive technical decisions.
- Embrace boring technology for stability.
- Design simple solutions that scale when needed.
- Developer productivity is architecture.
- Connect every decision to business value and user impact.
identity: "Channels Martin Fowler's pragmatism and Werner Vogels's cloud-scale realism."
communication_style: "Calm and pragmatic. Balances 'what could be' with 'what should be.' Answers with trade-offs, not verdicts."
principles:
- "Rule of Three before abstraction."
- "Boring technology for stability."
- "Developer productivity is architecture."
critical_actions: []
memories: []

View File

@ -3,9 +3,29 @@ name: bmad-agent-dev
description: Senior software engineer for story execution and code implementation. Use when the user asks to talk to Amelia or requests the developer agent.
---
# Amelia — Developer Agent
## Overview
You are Amelia, the Developer Agent. You execute approved stories with strict adherence to story details, team standards, and test-driven practices — writing citable, precise code that passes every test before calling anything done.
## Operating Rules
These rules are non-negotiable and apply to every task you perform:
- READ the entire story file BEFORE any implementation — the tasks/subtasks sequence is your authoritative implementation guide.
- Execute tasks/subtasks IN ORDER as written — no skipping, no reordering.
- Mark task/subtask `[x]` ONLY when both implementation AND tests are complete and passing.
- Run the full test suite after each task — NEVER proceed with failing tests.
- Execute continuously without pausing until all tasks/subtasks are complete.
- Document in the story file's Dev Agent Record what was implemented, tests created, and decisions made.
- Update the story file's File List with ALL changed files after each task completion.
- NEVER lie about tests being written or passing — tests must actually exist and pass 100%.
## Conventions
- Bare paths (e.g. `references/guide.md`) resolve from the skill root.
- `{skill-root}` resolves to this skill's installed directory (where `customize.yaml` lives).
- `{project-root}`-prefixed paths resolve from the project working directory.
- `{skill-name}` resolves to the skill directory's basename.
@ -13,13 +33,13 @@ description: Senior software engineer for story execution and code implementatio
### Step 1: Resolve the Agent Block
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
**If the script fails**, resolve the `agent` block yourself from `customize.yaml`, with `{project-root}/_bmad/custom/{skill-name}.yaml` overriding, and `{skill-name}.user.yaml` overriding both (any missing file is skipped).
### Step 2: Adopt Persona
You are `{agent.metadata.name}`, `{agent.metadata.title}`. Fill the role of `{agent.persona.role}`. Embody `{agent.persona.identity}`, speak in the style of `{agent.persona.communication_style}`, and follow `{agent.persona.principles}`.
Adopt the Amelia / Developer Agent identity established in the Overview. Layer the customized persona on top: fill the additional role of `{agent.persona.role}`, embody `{agent.persona.identity}`, speak in the style of `{agent.persona.communication_style}`, and follow `{agent.persona.principles}`.
Fully embody this persona so the user gets the best experience. Do not break character until the user dismisses the persona. When the user calls a skill, this persona carries through and remains active.
@ -46,7 +66,7 @@ Search for `{project-root}/**/project-context.md`. If found, load as foundationa
### Step 7: Greet the User
Greet `{user_name}` warmly by name as `{agent.metadata.name}`, speaking in `{communication_language}`. Remind the user they can invoke the `bmad-help` skill at any time for advice.
Greet `{user_name}` warmly by name as Amelia, speaking in `{communication_language}`. Remind the user they can invoke the `bmad-help` skill at any time for advice.
### Step 8: Present the Capabilities Menu

View File

@ -1,34 +1,23 @@
# DO NOT EDIT -- overwritten on every update.
#
# Amelia, the Developer Agent, is the hardcoded identity of this agent.
# Customize the persona and menu below to shape behavior without
# changing who the agent is.
agent:
metadata:
name: Amelia
title: Developer Agent
icon: "💻"
capabilities: "story execution, test-driven development, code implementation"
persona:
role: "Senior Software Engineer"
identity: |
Executes approved stories with strict adherence to story details
and team standards and practices.
communication_style: |
Ultra-succinct. Speaks in file paths and AC IDs - every statement
citable. No fluff, all precision.
principles: |
- All existing and new tests must pass 100% before story is ready
for review.
- Every task and subtask must be covered by comprehensive unit
tests before marking an item complete.
critical_actions:
- "READ the entire story file BEFORE any implementation — tasks/subtasks sequence is your authoritative implementation guide."
- "Execute tasks/subtasks IN ORDER as written in the story file — no skipping, no reordering."
- "Mark task/subtask [x] ONLY when both implementation AND tests are complete and passing."
- "Run full test suite after each task — NEVER proceed with failing tests."
- "Execute continuously without pausing until all tasks/subtasks are complete."
- "Document in story file Dev Agent Record what was implemented, tests created, and any decisions made."
- "Update story file File List with ALL changed files after each task completion."
- "NEVER lie about tests being written or passing — tests must actually exist and pass 100%."
identity: "Disciplined in Kent Beck's TDD and the Pragmatic Programmer's precision."
communication_style: "Ultra-succinct. Speaks in file paths and AC IDs — every statement citable. No fluff, all precision."
principles:
- "No task complete without passing tests."
- "Red, green, refactor — in that order."
- "Tasks executed in the sequence written."
critical_actions: []
memories: []
menu:

View File

@ -1 +0,0 @@
PyYAML>=6.0

View File

@ -1,4 +1,8 @@
#!/usr/bin/env python3
# /// script
# requires-python = ">=3.10"
# dependencies = ["pyyaml>=6.0"]
# ///
"""
Resolve customization for a BMad skill using three-layer YAML merge.
@ -11,10 +15,12 @@ Skill name is derived from the basename of the skill directory.
Outputs merged JSON to stdout. Errors go to stderr.
Usage:
python3 resolve_customization.py --skill /abs/path/to/skill-dir
python3 resolve_customization.py --skill ... --key agent
python3 resolve_customization.py --skill ... --key agent --key agent.menu
Dependencies declared inline via PEP 723. Invoke with `uv run` to
auto-install PyYAML into an isolated, cached environment:
uv run resolve_customization.py --skill /abs/path/to/skill-dir
uv run resolve_customization.py --skill ... --key agent
uv run resolve_customization.py --skill ... --key agent --key agent.menu
Merge rules (matches BMad v6.1 semantics where applicable):
- metadata: shallow merge (scalar fields override)
@ -25,8 +31,6 @@ Merge rules (matches BMad v6.1 semantics where applicable):
- other tables: deep merge
- other arrays: atomic replace
- scalars: override wins
Requires PyYAML. Install with: pip install PyYAML
"""
import argparse
@ -39,7 +43,9 @@ try:
except ImportError:
sys.stderr.write(
"error: PyYAML is required to run this script.\n"
"Install it with: pip install PyYAML\n"
"Invoke via `uv run resolve_customization.py ...` so dependencies\n"
"declared in the PEP 723 header are auto-installed, or run\n"
"`pip install PyYAML` if invoking with plain `python3`.\n"
)
sys.exit(3)
@ -58,15 +64,26 @@ def find_project_root(start: Path):
current = parent
def load_yaml(file_path: Path) -> dict:
def load_yaml(file_path: Path, required: bool = False) -> dict:
if not file_path.exists():
if required:
sys.stderr.write(f"error: required customization file not found: {file_path}\n")
sys.exit(1)
return {}
try:
with file_path.open("r", encoding="utf-8") as f:
parsed = yaml.safe_load(f)
return parsed if isinstance(parsed, dict) else {}
if not isinstance(parsed, dict):
if required:
sys.stderr.write(f"error: {file_path} did not parse to a mapping\n")
sys.exit(1)
return {}
return parsed
except Exception as error:
sys.stderr.write(f"warning: failed to parse {file_path}: {error}\n")
level = "error" if required else "warning"
sys.stderr.write(f"{level}: failed to parse {file_path}: {error}\n")
if required:
sys.exit(1)
return {}
@ -123,8 +140,10 @@ def deep_merge(base, override):
def merge_agent_block(base: dict, override: dict) -> dict:
"""Apply v6.1-compatible per-field merge semantics to the `agent` block,
then deep-merge everything else normally."""
base_agent = (base or {}).get("agent") or {}
over_agent = (override or {}).get("agent") or {}
base_obj = base if isinstance(base, dict) else {}
override_obj = override if isinstance(override, dict) else {}
base_agent = base_obj.get("agent") or {}
over_agent = override_obj.get("agent") or {}
merged_agent = dict(base_agent)
@ -157,7 +176,12 @@ def merge_agent_block(base: dict, override: dict) -> dict:
else:
merged_agent[key] = over_val
return {**(base or {}), **(override or {}), "agent": merged_agent}
# Deep-merge all non-agent top-level keys so tables like `workflow:` or
# `config:` follow the documented `other tables: deep merge` rule. Then
# overlay the specially-merged agent block.
merged = deep_merge(base_obj, override_obj)
merged["agent"] = merged_agent
return merged
def extract_key(data, dotted_key: str):
@ -190,11 +214,13 @@ def main():
skill_name = skill_dir.name
defaults_path = skill_dir / "customize.yaml"
defaults = load_yaml(defaults_path)
if not defaults:
sys.stderr.write(f"warning: no defaults found at {defaults_path}\n")
defaults = load_yaml(defaults_path, required=True)
project_root = find_project_root(Path.cwd()) or find_project_root(skill_dir)
# Prefer the project that contains this skill. Only fall back to cwd if
# the skill isn't inside a recognizable project tree (unusual but possible
# for standalone skills invoked directly). Using cwd first is unsafe when
# an ancestor of cwd happens to have a stray _bmad/ from another project.
project_root = find_project_root(skill_dir) or find_project_root(Path.cwd())
team = {}
user = {}

View File

@ -19,7 +19,6 @@ class InstallPaths {
const isUpdate = await fs.pathExists(bmadDir);
const configDir = path.join(bmadDir, '_config');
const agentsDir = path.join(configDir, 'agents');
const coreDir = path.join(bmadDir, 'core');
const scriptsDir = path.join(bmadDir, 'scripts');
const customDir = path.join(bmadDir, 'custom');
@ -27,7 +26,6 @@ class InstallPaths {
for (const [dir, label] of [
[bmadDir, 'bmad directory'],
[configDir, 'config directory'],
[agentsDir, 'agents config directory'],
[coreDir, 'core module directory'],
[scriptsDir, 'shared scripts directory'],
[customDir, 'customizations directory'],
@ -41,7 +39,6 @@ class InstallPaths {
projectRoot,
bmadDir,
configDir,
agentsDir,
coreDir,
scriptsDir,
customDir,

View File

@ -568,18 +568,24 @@ class Installer {
}
/**
* Recursively copy src/scripts/* _bmad/scripts/ so shared Python
* scripts (e.g. resolve_customization.py) are available at install time.
* Also seeds _bmad/custom/.gitignore on fresh installs so *.user.yaml
* overrides stay out of version control by default.
* Sync src/scripts/* _bmad/scripts/ so shared Python scripts
* (e.g. resolve_customization.py) are available at install time.
* Wipes the destination first so files removed or renamed in source
* (e.g. resolve-customization.js resolve_customization.py) don't
* linger and get recorded as installed. Also seeds _bmad/custom/.gitignore
* on fresh installs so *.user.yaml overrides stay out of version control.
*/
async _installSharedScripts(paths) {
const srcScriptsDir = path.join(paths.srcDir, 'src', 'scripts');
if (await fs.pathExists(srcScriptsDir)) {
await fs.copy(srcScriptsDir, paths.scriptsDir, { overwrite: true });
await this._trackFilesRecursive(paths.scriptsDir);
if (!(await fs.pathExists(srcScriptsDir))) {
throw new Error(`Shared scripts source directory not found: ${srcScriptsDir}`);
}
await fs.remove(paths.scriptsDir);
await fs.ensureDir(paths.scriptsDir);
await fs.copy(srcScriptsDir, paths.scriptsDir, { overwrite: true });
await this._trackFilesRecursive(paths.scriptsDir);
const customGitignore = path.join(paths.customDir, '.gitignore');
if (!(await fs.pathExists(customGitignore))) {
await fs.writeFile(customGitignore, '*.user.yaml\n', 'utf8');
@ -712,8 +718,11 @@ class Installer {
const customFiles = [];
const modifiedFiles = [];
// Memory is always in _bmad/_memory
const bmadMemoryPath = '_memory';
// Memory subtrees (v6.1: _bmad/_memory, current: _bmad/memory) hold
// per-user runtime data generated by agents with sidecars. These files
// aren't installer-managed and must never be reported as "custom" or
// "modified" — they're user state, not user overrides.
const bmadMemoryPaths = ['_memory', 'memory'];
// Check if the manifest has hashes - if not, we can't detect modifications
let manifestHasHashes = false;
@ -779,7 +788,7 @@ class Installer {
continue;
}
if (relativePath.startsWith(bmadMemoryPath + '/') && path.dirname(relativePath).includes('-sidecar')) {
if (bmadMemoryPaths.some((mp) => relativePath === mp || relativePath.startsWith(mp + '/'))) {
continue;
}
@ -830,7 +839,7 @@ class Installer {
// Get all installed module directories
const entries = await fs.readdir(bmadDir, { withFileTypes: true });
const nonModuleDirs = new Set(['_config', '_memory', 'docs', 'scripts', 'custom']);
const nonModuleDirs = new Set(['_config', '_memory', 'memory', 'docs', 'scripts', 'custom']);
const installedModules = entries.filter((entry) => entry.isDirectory() && !nonModuleDirs.has(entry.name)).map((entry) => entry.name);
// Generate config.yaml for each installed module
@ -957,7 +966,7 @@ class Installer {
// Get all installed module directories
const entries = await fs.readdir(bmadDir, { withFileTypes: true });
const nonModuleDirs = new Set(['_config', '_memory', 'docs', 'scripts', 'custom']);
const nonModuleDirs = new Set(['_config', '_memory', 'memory', 'docs', 'scripts', 'custom']);
const installedModules = entries.filter((entry) => entry.isDirectory() && !nonModuleDirs.has(entry.name)).map((entry) => entry.name);
// Add core module to scan (it's installed at root level as _config, but we check src/core-skills)

View File

@ -329,7 +329,6 @@ class ManifestGenerator {
displayName: m.displayName || m.name || entry.name,
title: m.title || '',
icon: m.icon || '',
capabilities: m.capabilities ? this.cleanForCSV(m.capabilities) : '',
role: m.role ? this.cleanForCSV(m.role) : '',
identity: m.identity ? this.cleanForCSV(m.identity) : '',
communicationStyle: m.communicationStyle ? this.cleanForCSV(m.communicationStyle) : '',
@ -499,7 +498,7 @@ class ManifestGenerator {
}
// Create CSV header with persona fields and canonicalId
let csvContent = 'name,displayName,title,icon,capabilities,role,identity,communicationStyle,principles,module,path,canonicalId\n';
let csvContent = 'name,displayName,title,icon,role,identity,communicationStyle,principles,module,path,canonicalId\n';
// Combine existing and new agents, preferring new data for duplicates
const allAgents = new Map();
@ -517,7 +516,6 @@ class ManifestGenerator {
displayName: agent.displayName,
title: agent.title,
icon: agent.icon,
capabilities: agent.capabilities,
role: agent.role,
identity: agent.identity,
communicationStyle: agent.communicationStyle,
@ -535,7 +533,6 @@ class ManifestGenerator {
escapeCsv(record.displayName),
escapeCsv(record.title),
escapeCsv(record.icon),
escapeCsv(record.capabilities),
escapeCsv(record.role),
escapeCsv(record.identity),
escapeCsv(record.communicationStyle),

View File

@ -820,7 +820,7 @@ class OfficialModules {
let foundAny = false;
const entries = await fs.readdir(bmadDir, { withFileTypes: true });
const nonModuleDirs = new Set(['_config', '_memory', 'docs', 'scripts', 'custom']);
const nonModuleDirs = new Set(['_config', '_memory', 'memory', 'docs', 'scripts', 'custom']);
for (const entry of entries) {
if (entry.isDirectory()) {
if (nonModuleDirs.has(entry.name)) {