bmad-method 6.11.1-next.34 → 6.11.1-next.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/bmm-skills/agents/bmad-agent-analyst/SKILL.md +1 -1
- package/src/bmm-skills/agents/bmad-agent-architect/SKILL.md +1 -1
- package/src/bmm-skills/agents/bmad-agent-dev/SKILL.md +1 -1
- package/src/bmm-skills/agents/bmad-agent-pm/SKILL.md +1 -1
- package/src/bmm-skills/agents/bmad-agent-ux-designer/SKILL.md +1 -1
- package/src/bmm-skills/plan/bmad-architecture/SKILL.md +1 -1
- package/src/bmm-skills/plan/bmad-create-epics-and-stories/SKILL.md +1 -1
- package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-04-final-validation.md +1 -1
- package/src/bmm-skills/plan/bmad-prd/SKILL.md +1 -1
- package/src/bmm-skills/plan/bmad-prfaq/SKILL.md +1 -1
- package/src/bmm-skills/plan/bmad-prfaq/references/verdict.md +1 -1
- package/src/bmm-skills/plan/bmad-product-brief/SKILL.md +1 -1
- package/src/bmm-skills/plan/bmad-project-context/SKILL.md +1 -1
- package/src/bmm-skills/plan/bmad-spec/SKILL.md +1 -1
- package/src/bmm-skills/plan/bmad-sprint-planning/SKILL.md +1 -1
- package/src/bmm-skills/plan/bmad-sprint-planning/scripts/__pycache__/sprint_plan.cpython-311.pyc +0 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/scripts/tests/__pycache__/test_sprint_plan.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/plan/bmad-ux/SKILL.md +1 -1
- package/src/bmm-skills/ship/bmad-code-review/SKILL.md +1 -1
- package/src/bmm-skills/ship/bmad-code-review/steps/step-04-present.md +1 -1
- package/src/bmm-skills/ship/bmad-correct-course/SKILL.md +2 -2
- package/src/bmm-skills/ship/bmad-qa-generate-e2e-tests/SKILL.md +2 -2
- package/src/bmm-skills/ship/bmad-retrospective/SKILL.md +1 -1
- package/src/bmm-skills/ship/bmad-retrospective/scripts/__pycache__/sprint_status.cpython-311.pyc +0 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_git_evidence.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_sprint_status.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/ship/bmad-walkthrough/SKILL.md +1 -1
- package/src/bmm-skills/ship/bmad-walkthrough/step-05-wrapup.md +1 -1
- package/src/bmm-skills/v6-shims/bmad-create-architecture/SKILL.md +1 -1
- package/src/bmm-skills/v6-shims/bmad-create-prd/SKILL.md +1 -1
- package/src/bmm-skills/v6-shims/bmad-create-story/SKILL.md +2 -2
- package/src/bmm-skills/v6-shims/bmad-dev-story/SKILL.md +2 -2
- package/src/bmm-skills/v6-shims/bmad-domain-research/SKILL.md +1 -1
- package/src/bmm-skills/v6-shims/bmad-edit-prd/SKILL.md +1 -1
- package/src/bmm-skills/v6-shims/bmad-market-research/SKILL.md +1 -1
- package/src/bmm-skills/v6-shims/bmad-sprint-status/SKILL.md +1 -1
- package/src/bmm-skills/v6-shims/bmad-technical-research/SKILL.md +1 -1
- package/src/bmm-skills/v6-shims/bmad-validate-prd/SKILL.md +1 -1
- package/src/core-skills/bmad-advanced-elicitation/SKILL.md +1 -1
- package/src/core-skills/bmad-brainstorming/SKILL.md +1 -1
- package/src/core-skills/bmad-customize/SKILL.md +1 -1
- package/src/core-skills/bmad-deep-recon/SKILL.md +1 -1
- package/src/core-skills/bmad-forge-idea/SKILL.md +1 -1
- package/src/core-skills/bmad-forge-idea/scripts/resolve_personas.py +3 -1
- package/src/core-skills/bmad-forge-idea/scripts/tests/test_resolve_personas.py +22 -0
- package/src/core-skills/bmad-party-mode/SKILL.md +1 -1
- package/src/core-skills/bmad-party-mode/references/create-party.md +1 -1
- package/src/core-skills/bmad-party-mode/scripts/resolve_party.py +3 -1
- package/src/core-skills/bmad-party-mode/scripts/tests/test_resolve_party.py +22 -0
- package/src/core-skills/bmad-review/SKILL.md +1 -1
- package/src/scripts/__pycache__/config_utils.cpython-311.pyc +0 -0
- package/src/scripts/resolve_customization.py +72 -7
- package/src/scripts/tests/__pycache__/test_config_utils.cpython-311.pyc +0 -0
- package/src/scripts/tests/__pycache__/test_resolve_config.cpython-311.pyc +0 -0
- package/src/scripts/tests/__pycache__/test_resolve_customization.cpython-311.pyc +0 -0
- package/src/scripts/tests/test_resolve_customization.py +102 -0
package/package.json
CHANGED
|
@@ -20,7 +20,7 @@ You are Mary, the Business Analyst. You bring deep expertise in market research,
|
|
|
20
20
|
|
|
21
21
|
### Step 1: Resolve the Agent Block
|
|
22
22
|
|
|
23
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
|
|
23
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key agent`
|
|
24
24
|
|
|
25
25
|
**If the script fails**, resolve the `agent` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
|
|
26
26
|
|
|
@@ -20,7 +20,7 @@ You are Winston, the System Architect. You turn product requirements and UX into
|
|
|
20
20
|
|
|
21
21
|
### Step 1: Resolve the Agent Block
|
|
22
22
|
|
|
23
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
|
|
23
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key agent`
|
|
24
24
|
|
|
25
25
|
**If the script fails**, resolve the `agent` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
|
|
26
26
|
|
|
@@ -20,7 +20,7 @@ You are Amelia, the Senior Software Engineer. You execute approved stories with
|
|
|
20
20
|
|
|
21
21
|
### Step 1: Resolve the Agent Block
|
|
22
22
|
|
|
23
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
|
|
23
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key agent`
|
|
24
24
|
|
|
25
25
|
**If the script fails**, resolve the `agent` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
|
|
26
26
|
|
|
@@ -20,7 +20,7 @@ You are John, the Product Manager. You drive PRD creation through user interview
|
|
|
20
20
|
|
|
21
21
|
### Step 1: Resolve the Agent Block
|
|
22
22
|
|
|
23
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
|
|
23
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key agent`
|
|
24
24
|
|
|
25
25
|
**If the script fails**, resolve the `agent` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
|
|
26
26
|
|
|
@@ -20,7 +20,7 @@ You are Sally, the UX Designer. You translate user needs into interaction design
|
|
|
20
20
|
|
|
21
21
|
### Step 1: Resolve the Agent Block
|
|
22
22
|
|
|
23
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent`
|
|
23
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key agent`
|
|
24
24
|
|
|
25
25
|
**If the script fails**, resolve the `agent` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
|
|
26
26
|
|
|
@@ -50,7 +50,7 @@ Writes go through the shared script (don't read the file back except on resume):
|
|
|
50
50
|
|
|
51
51
|
**Forwarded activation:** if a caller invoked you with a stated intent and pre-resolved customization fields, honor them verbatim — skip your own intent inference, use the supplied values for those named fields, and resolve only the remaining fields from your own `customize.toml`.
|
|
52
52
|
|
|
53
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow` (on failure read `{skill-root}/customize.toml`, use defaults). Run `{workflow.activation_steps_prepend}`, then `{workflow.activation_steps_append}`. Hold `{workflow.persistent_facts}` as standing context — empty unless the user opted in — and consult `{workflow.external_sources}` on demand.
|
|
53
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow` (on failure read `{skill-root}/customize.toml`, use defaults). Run `{workflow.activation_steps_prepend}`, then `{workflow.activation_steps_append}`. Hold `{workflow.persistent_facts}` as standing context — empty unless the user opted in — and consult `{workflow.external_sources}` on demand.
|
|
54
54
|
2. Resolve config: `uv run {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root}` (merges `_bmad/config.toml`, `_bmad/config.user.toml`, and the `_bmad/custom/` overrides). From the merged JSON resolve `{user_name}`, `{communication_language}`, `{document_output_language}`, `{project_name}` (under `core`), `{planning_artifacts}` (under `modules.bmm`), and `{date}`; missing keys take neutral defaults, never block.
|
|
55
55
|
3. Headless (no interactive user) → follow `references/headless.md` for the whole run. Otherwise greet `{user_name}` in `{communication_language}`. Detect the intent from the conversation and input — **create** (the default), **update** an existing spine, or **validate** one (see those sections). If the real ask is requirements / UX / a capability contract / epic breakdown / an agent, invoke the `bmad-prd`, `bmad-ux`, `bmad-spec`, `bmad-create-epics-and-stories`, or `bmad-workflow-builder` (if the BMad Builder module is installed) skill instead.
|
|
56
56
|
4. If a run folder for this target already exists under `{workflow.spine_output_path}`, offer to resume from its memlog rather than restart.
|
|
@@ -51,7 +51,7 @@ This uses **step-file architecture** for disciplined execution:
|
|
|
51
51
|
|
|
52
52
|
### Step 1: Resolve the Workflow Block
|
|
53
53
|
|
|
54
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
|
|
54
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`
|
|
55
55
|
|
|
56
56
|
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
|
|
57
57
|
|
|
@@ -138,6 +138,6 @@ Upon Completion of task output: offer to answer any questions about the Epics an
|
|
|
138
138
|
|
|
139
139
|
## On Complete
|
|
140
140
|
|
|
141
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete`
|
|
141
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow.on_complete`
|
|
142
142
|
|
|
143
143
|
If the resolved `workflow.on_complete` is non-empty, follow it as the final terminal instruction before exiting.
|
|
@@ -17,7 +17,7 @@ You are a master facilitator and coach helping the user create, edit, or validat
|
|
|
17
17
|
|
|
18
18
|
**Forwarded activation:** if a caller invoked you with a stated intent and pre-resolved customization fields (e.g. the `bmad-create-prd` / `bmad-edit-prd` / `bmad-validate-prd` shims), honor them verbatim — skip your own intent inference, use the supplied values for those named fields, and resolve only the remaining fields from your own `customize.toml`.
|
|
19
19
|
|
|
20
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults.
|
|
20
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults.
|
|
21
21
|
2. Run `{workflow.activation_steps_prepend}`. Treat `{workflow.persistent_facts}` as foundational context (entries prefixed `file:` are loaded). `{workflow.external_sources}` is an org-configured registry of internal tools (knowledge bases, MCP tools); consult them alongside generic web research on the same triggers, org tools preferred when their directive matches. Research itself fires during Discovery — see **Research subagents**.
|
|
22
22
|
3. Load `{project-root}/_bmad/bmm/config.yaml` (+ `config.user.yaml` if present). Resolve `{user_name}`, `{communication_language}`, `{document_output_language}`, `{planning_artifacts}`, `{project_name}`, `{date}`. Missing keys → neutral defaults; never block.
|
|
23
23
|
4. If headless, follow `references/headless.md` for the whole run. Otherwise greet the user **by name** using `{user_name}` and **in their language** using `{communication_language}` — and stay in `{communication_language}` for every turn for the entire run, not just the greeting. In the greeting, let the user know that at any point they can invoke `bmad-party-mode` for multi-agent perspectives or `bmad-advanced-elicitation` for deeper exploration on a specific section. Then scan for misroute on the first message: if the signal points elsewhere (game → BMad GDS; express build → `bmad-build`; one-pager → `bmad-product-brief`; vet product idea → `bmad-prfaq`; agent skill or custom agent → `bmad-workflow-builder`), suggest they might want the other options before continuing.
|
|
@@ -30,7 +30,7 @@ The PRFAQ forces customer-first clarity: write the press release announcing the
|
|
|
30
30
|
|
|
31
31
|
### Step 1: Resolve the Workflow Block
|
|
32
32
|
|
|
33
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
|
|
33
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`
|
|
34
34
|
|
|
35
35
|
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
|
|
36
36
|
|
|
@@ -78,6 +78,6 @@ purpose: "Token-efficient context for downstream PRD creation"
|
|
|
78
78
|
|
|
79
79
|
This is the terminal stage. If the user wants to revise, loop back to the relevant stage. Otherwise, the workflow is done.
|
|
80
80
|
|
|
81
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete`
|
|
81
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow.on_complete`
|
|
82
82
|
|
|
83
83
|
If the resolved `workflow.on_complete` is non-empty, follow it as the final terminal instruction before exiting.
|
|
@@ -15,7 +15,7 @@ At the opening greeting, let the user know they can invoke `bmad-party-mode` for
|
|
|
15
15
|
|
|
16
16
|
## On Activation
|
|
17
17
|
|
|
18
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults.
|
|
18
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults.
|
|
19
19
|
2. Execute each entry in `{workflow.activation_steps_prepend}` in order.
|
|
20
20
|
3. Treat every entry in `{workflow.persistent_facts}` as foundational context for the rest of the run. Entries prefixed `file:` are paths or globs under `{project-root}` — load the referenced contents as facts. All other entries are facts verbatim.
|
|
21
21
|
4. `{workflow.external_sources}` is an org-configured registry of internal tools (knowledge bases, MCP tools); consult them alongside generic web research on the same triggers in `## Discovery`, org tools preferred when their directive matches. If a named tool is unavailable at runtime, fall back to standard behavior and note the gap when relevant.
|
|
@@ -19,7 +19,7 @@ Conversational always; the user approves every write.
|
|
|
19
19
|
|
|
20
20
|
## On Activation
|
|
21
21
|
|
|
22
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults. Execute `{workflow.activation_steps_prepend}`; treat `{workflow.persistent_facts}` entries as standing context (`file:` = paths/globs to load, others verbatim).
|
|
22
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults. Execute `{workflow.activation_steps_prepend}`; treat `{workflow.persistent_facts}` entries as standing context (`file:` = paths/globs to load, others verbatim).
|
|
23
23
|
2. Config: if `{project-root}/_bmad` exists, `uv run {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root}` and read `{user_name}`, `{communication_language}` (use it every turn), `{output_folder}`. Standalone: skip.
|
|
24
24
|
3. **Load `references/best-practices.md` and `references/template.md` before anything else.** Every decision below is made against them.
|
|
25
25
|
4. Detect intent and greet `{user_name}`: **setup** (no instruction file in the target carries meaningful content — scaffolding alone, empty headings, a comment, a lone import line, is not meaningful; when unsure, adopt, since adopting a near-empty file costs one small ledger while setting up a meaningful one loses instructions), **adopt** (an instruction file has content but no managed block, whatever its state and whoever wrote it — the migration form of refresh; that file is the baseline and every instruction in it enters the ledger of step 1), **refresh** (a managed block exists), **record** (the user reports a mistake agents made), **audit** (re-verify and prune). A supplied intent that contradicts what detection finds — e.g. `setup` against a file with content — is surfaced and confirmed, never silently obeyed. Fold `{workflow.external_sources}` into the source list. Execute `{workflow.activation_steps_append}`.
|
|
@@ -18,7 +18,7 @@ Multiple skills may call to update the same spec over time.
|
|
|
18
18
|
|
|
19
19
|
## On Activation
|
|
20
20
|
|
|
21
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly.
|
|
21
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly.
|
|
22
22
|
2. Run `{workflow.activation_steps_prepend}`. Treat `{workflow.persistent_facts}` as foundational context (`file:` entries are loaded).
|
|
23
23
|
3. Resolve config: `uv run {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root}` (merges `_bmad/config.toml`, `_bmad/config.user.toml`, and the `_bmad/custom/` overrides). From the merged JSON resolve `{user_name}`, `{communication_language}`, `{document_output_language}`, `{project_name}`, `{output_folder}` (under `core`), and `{date}`.
|
|
24
24
|
4. Detect mode. **Headless** when any of: no TTY, programmatic caller (another skill or non-interactive runner), or the first message pre-supplies all inputs and asks for an artifact path back. **Interactive** otherwise. In interactive mode, greet by `{user_name}` in `{communication_language}`, stay in that language, and mention that `bmad-party-mode` and `bmad-advanced-elicitation` are available for deeper exploration on any field.
|
|
@@ -9,7 +9,7 @@ You are a senior developer about to commit to this plan. Two moves, in order: fi
|
|
|
9
9
|
|
|
10
10
|
## On Activation
|
|
11
11
|
|
|
12
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults.
|
|
12
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults.
|
|
13
13
|
2. Execute each entry in `{workflow.activation_steps_prepend}` in order.
|
|
14
14
|
3. Treat every entry in `{workflow.persistent_facts}` as foundational context for the rest of the run. Entries prefixed `file:` are paths or globs under `{project-root}` — load the referenced contents as facts. All other entries are facts verbatim.
|
|
15
15
|
4. Load `{project-root}/_bmad/bmm/config.yaml` (and `config.user.yaml` if present). Resolve `{user_name}`, `{communication_language}`, `{document_output_language}`, `{project_name}`, `{planning_artifacts}`, `{implementation_artifacts}`, `{project_knowledge}` (skip gracefully if unset), `{date}`. Stay in `{communication_language}` for every turn, not just the greeting.
|
package/src/bmm-skills/plan/bmad-sprint-planning/scripts/__pycache__/sprint_plan.cpython-311.pyc
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -30,7 +30,7 @@ UX may lead, follow, or stand alone. Inherit `sources:` by reference; the spines
|
|
|
30
30
|
|
|
31
31
|
## On Activation
|
|
32
32
|
|
|
33
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults.
|
|
33
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults.
|
|
34
34
|
2. Run `{workflow.activation_steps_prepend}`. Treat `{workflow.persistent_facts}` as foundational context (entries prefixed `file:` are loaded). `{workflow.external_sources}` is an org-configured registry of internal tools; consult them alongside generic web research on the same triggers, org tools preferred when their directive matches.
|
|
35
35
|
3. Load `{project-root}/_bmad/bmm/config.yaml` (+ `config.user.yaml` if present). Resolve `{user_name}`, `{communication_language}`, `{document_output_language}`, `{planning_artifacts}`, `{project_name}`, `{date}`. Missing keys → neutral defaults; never block.
|
|
36
36
|
4. If headless, follow `references/headless.md` for the whole run. Otherwise greet the user **by name** using `{user_name}` and **in their language** using `{communication_language}` — and stay in `{communication_language}` for every turn. In the greeting, let the user know `bmad-party-mode` and `bmad-advanced-elicitation` are always available. Then scan for misroute on the first message: PRD → `bmad-prd`; architecture → `bmad-architecture`; game UX → BMad GDS; agent/skill → `bmad-workflow-builder`; brief → `bmad-product-brief`.
|
|
@@ -21,7 +21,7 @@ If you need an explicit user instruction to run them, ask once now for the whole
|
|
|
21
21
|
|
|
22
22
|
### Step 1: Resolve the Workflow Block
|
|
23
23
|
|
|
24
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
|
|
24
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`
|
|
25
25
|
|
|
26
26
|
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
|
|
27
27
|
|
|
@@ -129,6 +129,6 @@ Present the user with follow-up options:
|
|
|
129
129
|
|
|
130
130
|
## On Complete
|
|
131
131
|
|
|
132
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete`
|
|
132
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow.on_complete`
|
|
133
133
|
|
|
134
134
|
If the resolved `workflow.on_complete` is non-empty, follow it as the final terminal instruction before exiting.
|
|
@@ -20,7 +20,7 @@ description: 'Assess the impact of a significant change during sprint execution
|
|
|
20
20
|
|
|
21
21
|
### Step 1: Resolve the Workflow Block
|
|
22
22
|
|
|
23
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
|
|
23
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`
|
|
24
24
|
|
|
25
25
|
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
|
|
26
26
|
|
|
@@ -302,7 +302,7 @@ Activation is complete. If `activation_steps_prepend` or `activation_steps_appen
|
|
|
302
302
|
|
|
303
303
|
<action>Report workflow completion to user with personalized message: "Correct Course workflow complete, {user_name}!"</action>
|
|
304
304
|
<action>Remind user of success criteria and next steps for Developer agent</action>
|
|
305
|
-
<action>Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.</action>
|
|
305
|
+
<action>Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.</action>
|
|
306
306
|
</step>
|
|
307
307
|
|
|
308
308
|
</workflow>
|
|
@@ -20,7 +20,7 @@ description: 'Generate automated API and end-to-end tests for implemented featur
|
|
|
20
20
|
|
|
21
21
|
### Step 1: Resolve the Workflow Block
|
|
22
22
|
|
|
23
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
|
|
23
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`
|
|
24
24
|
|
|
25
25
|
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
|
|
26
26
|
|
|
@@ -171,6 +171,6 @@ Save summary to: `{default_output_file}`
|
|
|
171
171
|
|
|
172
172
|
## On Complete
|
|
173
173
|
|
|
174
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete`
|
|
174
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow.on_complete`
|
|
175
175
|
|
|
176
176
|
If the resolved `workflow.on_complete` is non-empty, follow it as the final terminal instruction before exiting.
|
|
@@ -25,7 +25,7 @@ For automation, `-H <epic>` — an explicit epic in headless mode — is the sta
|
|
|
25
25
|
|
|
26
26
|
Run these in order before the retrospective begins:
|
|
27
27
|
|
|
28
|
-
1. **Resolve the workflow block.** Run `uv run --no-cache {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. If it fails, resolve `{workflow.*}` yourself by reading `{skill-root}/customize.toml`, then `{project-root}/_bmad/custom/{skill-name}.toml`, then `.user.toml` in that order, merging base → team → user (scalars override, keyed arrays-of-tables merge by `code`/`id`, other arrays append).
|
|
28
|
+
1. **Resolve the workflow block.** Run `uv run --no-cache {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. If it fails, resolve `{workflow.*}` yourself by reading `{skill-root}/customize.toml`, then `{project-root}/_bmad/custom/{skill-name}.toml`, then `.user.toml` in that order, merging base → team → user (scalars override, keyed arrays-of-tables merge by `code`/`id`, other arrays append).
|
|
29
29
|
2. **Run prepend steps** — execute each entry in `{workflow.activation_steps_prepend}` in order.
|
|
30
30
|
3. **Load persistent facts** — treat every `{workflow.persistent_facts}` entry as standing context. `file:` entries are paths/globs under `{project-root}` whose contents load as facts; all others are literal facts.
|
|
31
31
|
4. **Load config** from `{project-root}/_bmad/bmm/config.yaml`: `project_name`, `user_name`, `communication_language`, `document_output_language`, `user_skill_level`, `planning_artifacts`, `implementation_artifacts`, and `date` (system datetime), plus `output_folder` from `{project-root}/_bmad/core/config.yaml`. Speak all output in `{communication_language}`; write all documents in `{document_output_language}`. Never state time estimates — AI has changed development speed, so hour/day/week predictions are noise.
|
package/src/bmm-skills/ship/bmad-retrospective/scripts/__pycache__/sprint_status.cpython-311.pyc
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -20,7 +20,7 @@ description: 'Walk the user through reviewing a change: what it is for, what to
|
|
|
20
20
|
|
|
21
21
|
### Step 1: Resolve the Workflow Block
|
|
22
22
|
|
|
23
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
|
|
23
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`
|
|
24
24
|
|
|
25
25
|
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
|
|
26
26
|
|
|
@@ -25,6 +25,6 @@ HALT — do not proceed until the user makes their choice.
|
|
|
25
25
|
|
|
26
26
|
## On Complete
|
|
27
27
|
|
|
28
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete`
|
|
28
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow.on_complete`
|
|
29
29
|
|
|
30
30
|
If the resolved `workflow.on_complete` is non-empty, follow it as the final terminal instruction before exiting.
|
|
@@ -11,7 +11,7 @@ This skill was consolidated into `bmad-architecture`. It is retained as a thin c
|
|
|
11
11
|
|
|
12
12
|
## On Activation
|
|
13
13
|
|
|
14
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-create-architecture.toml` and `bmad-create-architecture.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
14
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-create-architecture.toml` and `bmad-create-architecture.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
15
15
|
|
|
16
16
|
2. Load `{project-root}/_bmad/bmm/config.yaml` (and `config.user.yaml` if present) to resolve `{user_name}` and `{communication_language}`.
|
|
17
17
|
|
|
@@ -11,7 +11,7 @@ This skill was consolidated into `bmad-prd`. It is retained as a thin compatibil
|
|
|
11
11
|
|
|
12
12
|
## On Activation
|
|
13
13
|
|
|
14
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-create-prd.toml` and `bmad-create-prd.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
14
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-create-prd.toml` and `bmad-create-prd.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
15
15
|
|
|
16
16
|
2. Load `{project-root}/_bmad/bmm/config.yaml` (and `config.user.yaml` if present) to resolve `{user_name}` and `{communication_language}`.
|
|
17
17
|
|
|
@@ -32,7 +32,7 @@ If you need an explicit user instruction to run them, ask once now for the whole
|
|
|
32
32
|
|
|
33
33
|
### Step 1: Resolve the Workflow Block
|
|
34
34
|
|
|
35
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
|
|
35
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`
|
|
36
36
|
|
|
37
37
|
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
|
|
38
38
|
|
|
@@ -430,7 +430,7 @@ Activation is complete. If `activation_steps_prepend` or `activation_steps_appen
|
|
|
430
430
|
|
|
431
431
|
**The developer now has everything needed for flawless implementation!**
|
|
432
432
|
</output>
|
|
433
|
-
<action>Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.</action>
|
|
433
|
+
<action>Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.</action>
|
|
434
434
|
</step>
|
|
435
435
|
|
|
436
436
|
</workflow>
|
|
@@ -29,7 +29,7 @@ metadata:
|
|
|
29
29
|
|
|
30
30
|
### Step 1: Resolve the Workflow Block
|
|
31
31
|
|
|
32
|
-
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
|
|
32
|
+
Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`
|
|
33
33
|
|
|
34
34
|
**If the script fails**, resolve the `workflow` block yourself by reading these three files in base → team → user order and applying the same structural merge rules as the resolver:
|
|
35
35
|
|
|
@@ -498,7 +498,7 @@ Activation is complete. If `activation_steps_prepend` or `activation_steps_appen
|
|
|
498
498
|
<action>Suggest checking {sprint_status} to see project progress</action>
|
|
499
499
|
</check>
|
|
500
500
|
<action>Remain flexible - allow user to choose their own path or ask for other assistance</action>
|
|
501
|
-
<action>Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.</action>
|
|
501
|
+
<action>Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow.on_complete` — if the resolved value is non-empty, follow it as the final terminal instruction before exiting.</action>
|
|
502
502
|
</step>
|
|
503
503
|
|
|
504
504
|
</workflow>
|
|
@@ -11,6 +11,6 @@ This skill was consolidated into `bmad-deep-recon`. It is retained as a thin com
|
|
|
11
11
|
|
|
12
12
|
## On Activation
|
|
13
13
|
|
|
14
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-domain-research.toml` and `bmad-domain-research.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
14
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-domain-research.toml` and `bmad-domain-research.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
15
15
|
2. Emit a deprecation notice to the user (in their configured communication language): `bmad-domain-research` is deprecated and forwards to `bmad-deep-recon` with the domain type. To silence this notice and access the full new surface (draft/process/run modes, research types, verification levels, HTML briefing, handoffs), migrate `_bmad/custom/bmad-domain-research.toml` to `_bmad/custom/bmad-deep-recon.toml` and invoke `bmad-deep-recon` directly.
|
|
16
16
|
3. Invoke `bmad-deep-recon` with: **research type** `domain` (skip its type inference), the four legacy fields above as pre-resolved values, and the user's original input verbatim. `bmad-deep-recon` takes the workflow from here — do not execute any further steps in this shim.
|
|
@@ -11,7 +11,7 @@ This skill was consolidated into `bmad-prd`. It is retained as a thin compatibil
|
|
|
11
11
|
|
|
12
12
|
## On Activation
|
|
13
13
|
|
|
14
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-edit-prd.toml` and `bmad-edit-prd.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
14
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-edit-prd.toml` and `bmad-edit-prd.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
15
15
|
|
|
16
16
|
2. Load `{project-root}/_bmad/bmm/config.yaml` (and `config.user.yaml` if present) to resolve `{user_name}` and `{communication_language}`.
|
|
17
17
|
|
|
@@ -11,6 +11,6 @@ This skill was consolidated into `bmad-deep-recon`. It is retained as a thin com
|
|
|
11
11
|
|
|
12
12
|
## On Activation
|
|
13
13
|
|
|
14
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-market-research.toml` and `bmad-market-research.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
14
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-market-research.toml` and `bmad-market-research.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
15
15
|
2. Emit a deprecation notice to the user (in their configured communication language): `bmad-market-research` is deprecated and forwards to `bmad-deep-recon` with the market type. To silence this notice and access the full new surface (draft/process/run modes, research types, verification levels, HTML briefing, handoffs), migrate `_bmad/custom/bmad-market-research.toml` to `_bmad/custom/bmad-deep-recon.toml` and invoke `bmad-deep-recon` directly.
|
|
16
16
|
3. Invoke `bmad-deep-recon` with: **research type** `market` (skip its type inference), the four legacy fields above as pre-resolved values, and the user's original input verbatim. `bmad-deep-recon` takes the workflow from here — do not execute any further steps in this shim.
|
|
@@ -11,7 +11,7 @@ This skill was consolidated into `bmad-sprint-planning`, which now owns the whol
|
|
|
11
11
|
|
|
12
12
|
## On Activation
|
|
13
13
|
|
|
14
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-sprint-status.toml` and `bmad-sprint-status.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
14
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-sprint-status.toml` and `bmad-sprint-status.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
15
15
|
|
|
16
16
|
2. Load `{project-root}/_bmad/bmm/config.yaml` (and `config.user.yaml` if present) to resolve `{user_name}` and `{communication_language}`.
|
|
17
17
|
|
|
@@ -11,6 +11,6 @@ This skill was consolidated into `bmad-deep-recon`. It is retained as a thin com
|
|
|
11
11
|
|
|
12
12
|
## On Activation
|
|
13
13
|
|
|
14
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-technical-research.toml` and `bmad-technical-research.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
14
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-technical-research.toml` and `bmad-technical-research.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
15
15
|
2. Emit a deprecation notice to the user (in their configured communication language): `bmad-technical-research` is deprecated and forwards to `bmad-deep-recon` with the technical type. To silence this notice and access the full new surface (draft/process/run modes, research types, verification levels, HTML briefing, handoffs), migrate `_bmad/custom/bmad-technical-research.toml` to `_bmad/custom/bmad-deep-recon.toml` and invoke `bmad-deep-recon` directly.
|
|
16
16
|
3. Invoke `bmad-deep-recon` with: **research type** `technical` (skip its type inference), the four legacy fields above as pre-resolved values, and the user's original input verbatim. `bmad-deep-recon` takes the workflow from here — do not execute any further steps in this shim.
|
|
@@ -11,7 +11,7 @@ This skill was consolidated into `bmad-prd`. It is retained as a thin compatibil
|
|
|
11
11
|
|
|
12
12
|
## On Activation
|
|
13
13
|
|
|
14
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-validate-prd.toml` and `bmad-validate-prd.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
14
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. This picks up any `{project-root}/_bmad/custom/bmad-validate-prd.toml` and `bmad-validate-prd.user.toml` overrides for the legacy fields (`activation_steps_prepend`, `activation_steps_append`, `persistent_facts`, `on_complete`).
|
|
15
15
|
|
|
16
16
|
2. Load `{project-root}/_bmad/bmm/config.yaml` (and `config.user.yaml` if present) to resolve `{user_name}` and `{communication_language}`.
|
|
17
17
|
|
|
@@ -14,7 +14,7 @@ You are BMad's shared refinement checkpoint: other skills invoke you at natural
|
|
|
14
14
|
|
|
15
15
|
## On Activation
|
|
16
16
|
|
|
17
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults.
|
|
17
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults.
|
|
18
18
|
2. Hold every `{workflow.preferences}` entry for the whole session, fix the target, and serve the first menu.
|
|
19
19
|
|
|
20
20
|
## Serving the Catalog
|
|
@@ -18,7 +18,7 @@ The session runs in one of three stances, chosen by the user — set explicitly
|
|
|
18
18
|
|
|
19
19
|
## On Activation
|
|
20
20
|
|
|
21
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, use a subagent to read `{skill-root}/customize.toml` directly with defaults.
|
|
21
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. On failure, use a subagent to read `{skill-root}/customize.toml` directly with defaults.
|
|
22
22
|
2. Run each `{workflow.activation_steps_prepend}` entry. Treat each `{workflow.persistent_facts}` entry as foundational context (`file:`-prefixed entries are paths/globs under `{project-root}` — load their contents; others are facts verbatim).
|
|
23
23
|
3. Resolve central config: `uv run {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root} --key core` (merges `_bmad/config.toml`, `_bmad/config.user.toml`, and the `_bmad/custom/` overrides); from the merged JSON resolve `{user_name}`, `{communication_language}`, `{document_output_language}`, `{output_folder}`, `{project_name}`; `{date}` is today. On failure or missing values → neutral defaults; never block.
|
|
24
24
|
4. **If launched headless** (a machine signal, not a human asking for output — `references/headless.md` lists them): load `references/headless.md` and follow it for the whole run; never load it otherwise. Outside headless, you generate ideas yourself only in autonomous mode (`references/mode-autonomous.md`) — never in facilitator or partner mode.
|
|
@@ -87,7 +87,7 @@ Default by character (policy → team, personal → user), confirm before writin
|
|
|
87
87
|
3. Write. Create `{project-root}/_bmad/custom/` if needed.
|
|
88
88
|
4. Verify:
|
|
89
89
|
```
|
|
90
|
-
uv run {project-root}/_bmad/scripts/resolve_customization.py --skill <install-path> --key <agent-or-workflow>
|
|
90
|
+
uv run {project-root}/_bmad/scripts/resolve_customization.py --skill <install-path> --project-root {project-root} --key <agent-or-workflow>
|
|
91
91
|
```
|
|
92
92
|
Show the merged output, point out the changed fields.
|
|
93
93
|
|
|
@@ -37,7 +37,7 @@ Three services, freely combined — each detailed in its reference: **Draft** a
|
|
|
37
37
|
|
|
38
38
|
**Forwarded activation:** if a caller invoked you with a stated intent, research type, or pre-resolved customization fields (the legacy research shims and Mary's menu do), honor them verbatim — skip your own inference for those values and resolve only the rest.
|
|
39
39
|
|
|
40
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow` (on failure read `{skill-root}/customize.toml`, use defaults). Run `{workflow.activation_steps_prepend}`, then `{workflow.activation_steps_append}`.
|
|
40
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow` (on failure read `{skill-root}/customize.toml`, use defaults). Run `{workflow.activation_steps_prepend}`, then `{workflow.activation_steps_append}`.
|
|
41
41
|
2. Resolve config: `uv run {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root}`. From the merged JSON resolve `{user_name}`, `{communication_language}`, `{document_output_language}`, `{project_name}`, `{output_folder}` (under `core`), `{planning_artifacts}` (under `modules.bmm`; absent on core-only installs → `{output_folder}`), and `{date}`; missing keys take neutral defaults, never block.
|
|
42
42
|
3. Headless (no interactive user) → see `## Headless Mode`. Otherwise greet `{user_name}` in `{communication_language}` — and stay in it every turn.
|
|
43
43
|
4. Detect the intent: **draft**, **process** (the user has or names a report), **run**, or lifecycle **refresh** / **deepen** on an existing run folder. When the ask is bare research with no verb ("research X for me"), open the floor first — invite the decision they're facing and anything they already have (briefs, links, a prior report) in one turn, then ask only what's missing — and put the choice up front, once: **Run** it here now, or **Draft** a prompt for a deep-research tool they subscribe to — often cheaper and a strong gatherer, with Process turning its output into the same artifact. State the trade honestly (tokens and minutes here vs. one manual round-trip there); their call, remembered for the session.
|
|
@@ -22,7 +22,7 @@ Lead by questioning, not lecturing. Ask one question at a time, press on weak po
|
|
|
22
22
|
|
|
23
23
|
## On Activation
|
|
24
24
|
|
|
25
|
-
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly with defaults. Apply the resolved `{workflow.*}` values throughout.
|
|
25
|
+
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly with defaults. Apply the resolved `{workflow.*}` values throughout.
|
|
26
26
|
2. Run each `{workflow.activation_steps_prepend}` entry; treat each `{workflow.persistent_facts}` entry as foundational context (`file:` entries load their contents, `skill:` names a skill to consult, others are facts verbatim).
|
|
27
27
|
3. Resolve central config: `uv run {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root} --key core`; from the merged JSON read `{user_name}`, `{communication_language}`, `{output_folder}`. On failure use neutral defaults; never block. Greet `{user_name}` in `{communication_language}` and stay in it.
|
|
28
28
|
4. Note whether a BMad persona is already active in this conversation — the user loaded one (e.g. the analyst, the storyteller) and invoked the forge from within it. If so, that persona leads the session, in voice, throughout.
|
|
@@ -110,7 +110,9 @@ def find_party_skill(project_root: Path, skill_root: Path):
|
|
|
110
110
|
def load_party_workflow(project_root: Path, party_skill: Path):
|
|
111
111
|
"""Merged [workflow] table for bmad-party-mode (base + user overrides)."""
|
|
112
112
|
resolver = project_root / "_bmad" / "scripts" / "resolve_customization.py"
|
|
113
|
-
data = _run_json(
|
|
113
|
+
data = _run_json(
|
|
114
|
+
[sys.executable, str(resolver), "--skill", str(party_skill), "--project-root", str(project_root), "--key", "workflow"]
|
|
115
|
+
)
|
|
114
116
|
if data is not None and isinstance(data.get("workflow"), dict):
|
|
115
117
|
return data["workflow"]
|
|
116
118
|
# Fallback: base customize.toml directly, no override merge.
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
"""Unit tests for resolve_personas.py — pool merge, alias, party resolution."""
|
|
6
6
|
|
|
7
7
|
import sys
|
|
8
|
+
import tempfile
|
|
8
9
|
import unittest
|
|
9
10
|
from pathlib import Path
|
|
10
11
|
|
|
@@ -134,5 +135,26 @@ class TestOverrideMergeFallback(unittest.TestCase):
|
|
|
134
135
|
self.assertEqual([m["code"] for m in wf["party_members"]], ["x", "y"]) # appended
|
|
135
136
|
|
|
136
137
|
|
|
138
|
+
class TestResolverInvocation(unittest.TestCase):
|
|
139
|
+
"""The wrapper knows the project root, so it must not let the resolver
|
|
140
|
+
infer one from the working directory (#2796)."""
|
|
141
|
+
|
|
142
|
+
def _captured_command(self, tmp):
|
|
143
|
+
captured = []
|
|
144
|
+
original = rp._run_json
|
|
145
|
+
rp._run_json = lambda cmd: captured.append(cmd) or {"workflow": {}}
|
|
146
|
+
try:
|
|
147
|
+
rp.load_party_workflow(Path(tmp) / "project", Path(tmp) / "skill")
|
|
148
|
+
finally:
|
|
149
|
+
rp._run_json = original
|
|
150
|
+
return captured[0]
|
|
151
|
+
|
|
152
|
+
def test_passes_project_root_to_the_customization_resolver(self):
|
|
153
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
154
|
+
cmd = self._captured_command(tmp)
|
|
155
|
+
self.assertIn("--project-root", cmd)
|
|
156
|
+
self.assertEqual(cmd[cmd.index("--project-root") + 1], str(Path(tmp) / "project"))
|
|
157
|
+
|
|
158
|
+
|
|
137
159
|
if __name__ == "__main__":
|
|
138
160
|
unittest.main()
|
|
@@ -16,7 +16,7 @@ Run a round-table where these agents talk to each other and to the user like rea
|
|
|
16
16
|
|
|
17
17
|
## On Activation
|
|
18
18
|
|
|
19
|
-
1. **Resolve customization:** `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults. Then run each `{workflow.activation_steps_prepend}` entry, and hold each `{workflow.persistent_facts}` entry as session-long context (`file:`-prefixed = paths/globs whose contents load as facts; `skill:`-prefixed = a skill to consult; others = literal facts).
|
|
19
|
+
1. **Resolve customization:** `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults. Then run each `{workflow.activation_steps_prepend}` entry, and hold each `{workflow.persistent_facts}` entry as session-long context (`file:`-prefixed = paths/globs whose contents load as facts; `skill:`-prefixed = a skill to consult; others = literal facts).
|
|
20
20
|
2. **Resolve core config:** `uv run {project-root}/_bmad/scripts/resolve_config.py --project-root {project-root}`. From the merged JSON's `core` table: greet with `{user_name}`, speak in `{communication_language}`, and resolve `{output_folder}`; `{date}` is today's date.
|
|
21
21
|
3. **Detect intent and route.** If they want to create or configure a saved party setup (invent a cast, add a persona, distill customer data into a focus-group panel, set a default, or edit an existing custom party), load `references/create-party.md` and follow it. Otherwise run a party — continue below.
|
|
22
22
|
4. **Resolve the roster:** `uv run {skill-root}/scripts/resolve_party.py --project-root {project-root} --skill {skill-root}`. It returns the active roster (`{workflow.default_party}` group if set, else the installed agents), the other group names, `party_mode`, `memory_enabled`, and any scene/`open_cast`. Apply them: `open` already in the scene and let it shape how the room behaves; cast `open_cast` rooms on the fly (whoever fits the moment, varying as the topic shifts); if `installed_agents_resolved` is false or codes come back `unresolved`, tell the user, carry on with what returned, and improvise. Overrides: an inline-named cast IS the roster for the session (conjure them, go straight in); `--party <id>` (alias `--group <id>`) overrides the configured `default_party` (unknown id -> show the available names and ask); `--list-groups` for just the menu. Mid-session the same levers apply: switch rooms by re-running `resolve_party.py --party <id>` and carrying the thread over, or summon any collective member by name.
|
|
@@ -30,7 +30,7 @@ Ask which they're after if it isn't obvious, then proceed.
|
|
|
30
30
|
|
|
31
31
|
## Editing an existing party
|
|
32
32
|
|
|
33
|
-
When the user wants to change a party that already exists (retune a member's persona, add someone to a group, swap the default), read the current state first so you change rather than clobber: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow` returns the merged `party_members`, `party_groups`, and `default_party`. Show the member or group being touched, capture only the delta with the user, and hand that sparse change to `bmad-customize` — it replaces a `party_members`/`party_groups` entry whose `code`/`id` matches and appends the rest, so an edit is just the changed entry, never a full rewrite.
|
|
33
|
+
When the user wants to change a party that already exists (retune a member's persona, add someone to a group, swap the default), read the current state first so you change rather than clobber: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow` returns the merged `party_members`, `party_groups`, and `default_party`. Show the member or group being touched, capture only the delta with the user, and hand that sparse change to `bmad-customize` — it replaces a `party_members`/`party_groups` entry whose `code`/`id` matches and appends the rest, so an edit is just the changed entry, never a full rewrite.
|
|
34
34
|
|
|
35
35
|
## Keeping new faces from a session
|
|
36
36
|
|
|
@@ -71,7 +71,9 @@ def load_agents(project_root: Path):
|
|
|
71
71
|
def load_workflow(project_root: Path, skill_root: Path):
|
|
72
72
|
"""Merged [workflow] table. Falls back to the skill's base customize.toml."""
|
|
73
73
|
script = project_root / "_bmad" / "scripts" / "resolve_customization.py"
|
|
74
|
-
data = _run_json(
|
|
74
|
+
data = _run_json(
|
|
75
|
+
[sys.executable, str(script), "--skill", str(skill_root), "--project-root", str(project_root), "--key", "workflow"]
|
|
76
|
+
)
|
|
75
77
|
if data is not None and "workflow" in data:
|
|
76
78
|
return data["workflow"]
|
|
77
79
|
# Fallback: read the skill's base customize.toml directly (no override merge).
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
"""Unit tests for resolve_party.py — merge, alias, override, group resolution."""
|
|
6
6
|
|
|
7
7
|
import sys
|
|
8
|
+
import tempfile
|
|
8
9
|
import unittest
|
|
9
10
|
from pathlib import Path
|
|
10
11
|
|
|
@@ -142,5 +143,26 @@ class TestInstalledCodesIsDefaultRoom(unittest.TestCase):
|
|
|
142
143
|
self.assertEqual(col["bmad-agent-analyst"]["name"], "Mary-Custom")
|
|
143
144
|
|
|
144
145
|
|
|
146
|
+
class TestResolverInvocation(unittest.TestCase):
|
|
147
|
+
"""The wrapper knows the project root, so it must not let the resolver
|
|
148
|
+
infer one from the working directory (#2796)."""
|
|
149
|
+
|
|
150
|
+
def _captured_command(self, tmp):
|
|
151
|
+
captured = []
|
|
152
|
+
original = rp._run_json
|
|
153
|
+
rp._run_json = lambda cmd: captured.append(cmd) or {"workflow": {}}
|
|
154
|
+
try:
|
|
155
|
+
rp.load_workflow(Path(tmp) / "project", Path(tmp) / "skill")
|
|
156
|
+
finally:
|
|
157
|
+
rp._run_json = original
|
|
158
|
+
return captured[0]
|
|
159
|
+
|
|
160
|
+
def test_passes_project_root_to_the_customization_resolver(self):
|
|
161
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
162
|
+
cmd = self._captured_command(tmp)
|
|
163
|
+
self.assertIn("--project-root", cmd)
|
|
164
|
+
self.assertEqual(cmd[cmd.index("--project-root") + 1], str(Path(tmp) / "project"))
|
|
165
|
+
|
|
166
|
+
|
|
145
167
|
if __name__ == "__main__":
|
|
146
168
|
unittest.main()
|
|
@@ -25,7 +25,7 @@ The lens set is whatever `{workflow.lenses}` resolves to, not a fixed list — o
|
|
|
25
25
|
|
|
26
26
|
## Execution
|
|
27
27
|
|
|
28
|
-
1. **Resolve customization:** `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults. **Forwarded activation:** if a caller invoked you with pre-resolved customization fields (e.g. the `bmad-editorial-review` shim), honor them verbatim for those named fields — they already carry the user's overrides — and resolve only the remaining fields from your own `customize.toml`. Then execute each `{workflow.activation_steps_prepend}` entry in order, hold `{workflow.persistent_facts}` as standing context for the session, and treat `{workflow.review_guidance}` entries as standing review directives for every lens.
|
|
28
|
+
1. **Resolve customization:** `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --project-root {project-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults. **Forwarded activation:** if a caller invoked you with pre-resolved customization fields (e.g. the `bmad-editorial-review` shim), honor them verbatim for those named fields — they already carry the user's overrides — and resolve only the remaining fields from your own `customize.toml`. Then execute each `{workflow.activation_steps_prepend}` entry in order, hold `{workflow.persistent_facts}` as standing context for the session, and treat `{workflow.review_guidance}` entries as standing review directives for every lens.
|
|
29
29
|
2. **Load the content.** Stage it once as a file: when the content is a branch, uncommitted work, or a commit range, use the repository's version-control tooling to write the unified diff to a uniquely-named file in the system temp directory and take that file's absolute path as the content. A branch means its diff against the merge base with its base branch; uncommitted work includes untracked files. Stage `claims` to its own file the same way — it is input for one lens, staged separately precisely so the other lenses never see it. If the content is empty or cannot be decoded as text: when the caller expects the raw findings JSON array (e.g. the legacy edge-case forwarder), return `[{"location":"N/A","trigger_condition":"Input empty or undecodable","guard_snippet":"Provide valid content to review","potential_consequence":"Review skipped — no analysis performed"}]` (no `lens` field) and stop; otherwise say what's wrong and ask for reviewable content. Classify the content — diff, source file, function, or document — and whether it is **code** or **docs**; scope rules and lens applicability both depend on it. A document that defines behavior (spec, requirements, plan, story) is `docs` that a behavioral lens may still apply to; judge by `when`.
|
|
30
30
|
3. **Select lenses** from `{workflow.lenses}`. A lens with an empty `instruction` is disabled. If the user or caller named lenses, run exactly those only — `applies_to` and `when` do not filter an explicit request. Otherwise run every enabled lens whose `applies_to` covers the content class (`any` always covers) and whose `when` applies.
|
|
31
31
|
4. **Announce the plan** in one line before running anything: the content class, the lenses about to run, and — when any lens has `after` set — that it runs on top of the named lens's findings. Skip the announcement entirely when the caller pinned an exact output contract (the legacy forwarders that demand raw JSON or one exact line) — their contract covers everything you emit, not just the findings block. Then execute each `{workflow.activation_steps_append}` entry in order.
|
|
Binary file
|
|
@@ -25,15 +25,77 @@ _MISSING = object()
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
def find_project_root(start: Path) -> Path | None:
|
|
28
|
+
"""Nearest ancestor holding `_bmad/`, falling back to the nearest holding `.git`.
|
|
29
|
+
|
|
30
|
+
`_bmad/` outranks `.git` at every depth: a submodule or nested repo carries
|
|
31
|
+
`.git` without being the BMad project, so treating the two as equal stops the
|
|
32
|
+
walk short of the root that owns `_bmad/custom/`.
|
|
33
|
+
"""
|
|
34
|
+
git_root: Path | None = None
|
|
28
35
|
current = start.resolve()
|
|
29
36
|
while True:
|
|
30
|
-
if (current / "_bmad").
|
|
37
|
+
if (current / "_bmad").is_dir():
|
|
31
38
|
return current
|
|
39
|
+
if git_root is None and (current / ".git").exists():
|
|
40
|
+
git_root = current
|
|
32
41
|
if current.parent == current:
|
|
33
|
-
return
|
|
42
|
+
return git_root
|
|
34
43
|
current = current.parent
|
|
35
44
|
|
|
36
45
|
|
|
46
|
+
def script_project_root() -> Path | None:
|
|
47
|
+
"""Project root implied by this script's own install path.
|
|
48
|
+
|
|
49
|
+
Skills invoke `{project-root}/_bmad/scripts/resolve_customization.py`, so when
|
|
50
|
+
this file sits at that path its grandparent is a project root the caller already
|
|
51
|
+
resolved.
|
|
52
|
+
"""
|
|
53
|
+
parents = Path(__file__).resolve().parents
|
|
54
|
+
if len(parents) >= 3 and parents[0].name == "scripts" and parents[1].name == "_bmad":
|
|
55
|
+
return parents[2]
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def candidate_project_roots(skill_dir: Path) -> list[Path]:
|
|
60
|
+
"""Plausible project roots, most trustworthy first.
|
|
61
|
+
|
|
62
|
+
The working directory leads because the project is where the user is working,
|
|
63
|
+
not where the skill happens to be installed — a home-installed skill walks up to
|
|
64
|
+
`~`, and any `~/_bmad` there would otherwise mask the real project's overrides.
|
|
65
|
+
"""
|
|
66
|
+
ordered: list[Path] = []
|
|
67
|
+
for root in (
|
|
68
|
+
find_project_root(Path.cwd()),
|
|
69
|
+
script_project_root(),
|
|
70
|
+
find_project_root(skill_dir),
|
|
71
|
+
):
|
|
72
|
+
if root is not None and root not in ordered:
|
|
73
|
+
ordered.append(root)
|
|
74
|
+
return ordered
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def has_override(root: Path, skill_name: str) -> bool:
|
|
78
|
+
custom_dir = root / "_bmad" / "custom"
|
|
79
|
+
return any(
|
|
80
|
+
(custom_dir / name).is_file()
|
|
81
|
+
for name in (f"{skill_name}.toml", f"{skill_name}.user.toml")
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def warn_on_masked_override(chosen: Path, rejected: list[Path], skill_name: str) -> None:
|
|
86
|
+
"""Break the silence when a real override exists under a root we did not pick."""
|
|
87
|
+
if has_override(chosen, skill_name):
|
|
88
|
+
return
|
|
89
|
+
for root in rejected:
|
|
90
|
+
if has_override(root, skill_name):
|
|
91
|
+
sys.stderr.write(
|
|
92
|
+
f"note: resolved project root {chosen} has no customization for "
|
|
93
|
+
f"`{skill_name}`, but {root} does. Using {chosen}; pass "
|
|
94
|
+
f"--project-root to select the other explicitly.\n"
|
|
95
|
+
)
|
|
96
|
+
return
|
|
97
|
+
|
|
98
|
+
|
|
37
99
|
def extract_key(data, dotted_key: str):
|
|
38
100
|
current = data
|
|
39
101
|
for part in dotted_key.split("."):
|
|
@@ -73,11 +135,14 @@ def main() -> int:
|
|
|
73
135
|
args = parser.parse_args()
|
|
74
136
|
|
|
75
137
|
skill_dir = Path(args.skill).resolve()
|
|
76
|
-
project_root
|
|
77
|
-
Path(args.project_root).resolve()
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
138
|
+
if args.project_root:
|
|
139
|
+
project_root = Path(args.project_root).resolve()
|
|
140
|
+
else:
|
|
141
|
+
candidates = candidate_project_roots(skill_dir)
|
|
142
|
+
project_root = candidates[0] if candidates else None
|
|
143
|
+
if project_root is not None:
|
|
144
|
+
warn_on_masked_override(project_root, candidates[1:], skill_dir.name)
|
|
145
|
+
|
|
81
146
|
try:
|
|
82
147
|
merged = load_customization(project_root, skill_dir)
|
|
83
148
|
except ConfigError as error:
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -73,5 +73,107 @@ class ResolveCustomizationStdoutTests(unittest.TestCase):
|
|
|
73
73
|
self.assertEqual(resolved["agent"]["icon"], "🧭")
|
|
74
74
|
|
|
75
75
|
|
|
76
|
+
def write(path: Path, body: str) -> None:
|
|
77
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
78
|
+
path.write_text(body, encoding="utf-8")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def facts(*entries: str) -> str:
|
|
82
|
+
listed = ", ".join(f'"{entry}"' for entry in entries)
|
|
83
|
+
return f"[workflow]\npersistent_facts = [{listed}]\n"
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def resolve(skill_dir: Path, cwd: Path, *extra: str):
|
|
87
|
+
return subprocess.run(
|
|
88
|
+
[sys.executable, str(SCRIPT), "--skill", str(skill_dir), "--key", "workflow", *extra],
|
|
89
|
+
text=True,
|
|
90
|
+
stdout=subprocess.PIPE,
|
|
91
|
+
stderr=subprocess.PIPE,
|
|
92
|
+
cwd=str(cwd),
|
|
93
|
+
check=False,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class ProjectRootResolutionTests(unittest.TestCase):
|
|
98
|
+
"""Regression cover for #2796 — the project is where the user works, not
|
|
99
|
+
where the skill is installed."""
|
|
100
|
+
|
|
101
|
+
def test_home_installed_skill_reads_project_override_not_home_bmad(self):
|
|
102
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
103
|
+
home = Path(temp_dir) / "home"
|
|
104
|
+
project = Path(temp_dir) / "project"
|
|
105
|
+
skill = home / ".claude" / "skills" / "demo-skill"
|
|
106
|
+
write(skill / "customize.toml", facts("shipped default"))
|
|
107
|
+
(home / "_bmad" / "custom").mkdir(parents=True)
|
|
108
|
+
write(project / "_bmad" / "custom" / "demo-skill.toml", facts("team override"))
|
|
109
|
+
|
|
110
|
+
result = resolve(skill, project)
|
|
111
|
+
|
|
112
|
+
self.assertEqual(result.returncode, 0, msg=result.stderr)
|
|
113
|
+
resolved = json.loads(result.stdout)["workflow"]["persistent_facts"]
|
|
114
|
+
self.assertEqual(resolved, ["shipped default", "team override"])
|
|
115
|
+
|
|
116
|
+
def test_project_installed_skill_still_resolves(self):
|
|
117
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
118
|
+
project = Path(temp_dir) / "project"
|
|
119
|
+
skill = project / ".claude" / "skills" / "demo-skill"
|
|
120
|
+
write(skill / "customize.toml", facts("shipped default"))
|
|
121
|
+
write(project / "_bmad" / "custom" / "demo-skill.toml", facts("team override"))
|
|
122
|
+
|
|
123
|
+
result = resolve(skill, project)
|
|
124
|
+
|
|
125
|
+
self.assertEqual(result.returncode, 0, msg=result.stderr)
|
|
126
|
+
resolved = json.loads(result.stdout)["workflow"]["persistent_facts"]
|
|
127
|
+
self.assertEqual(resolved, ["shipped default", "team override"])
|
|
128
|
+
|
|
129
|
+
def test_walk_prefers_bmad_over_a_nearer_git_directory(self):
|
|
130
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
131
|
+
project = Path(temp_dir) / "project"
|
|
132
|
+
submodule = project / "vendor" / "sub"
|
|
133
|
+
skill = Path(temp_dir) / "skills" / "demo-skill"
|
|
134
|
+
write(skill / "customize.toml", facts("shipped default"))
|
|
135
|
+
write(project / "_bmad" / "custom" / "demo-skill.toml", facts("team override"))
|
|
136
|
+
(submodule / ".git").mkdir(parents=True)
|
|
137
|
+
|
|
138
|
+
result = resolve(skill, submodule)
|
|
139
|
+
|
|
140
|
+
self.assertEqual(result.returncode, 0, msg=result.stderr)
|
|
141
|
+
resolved = json.loads(result.stdout)["workflow"]["persistent_facts"]
|
|
142
|
+
self.assertEqual(resolved, ["shipped default", "team override"])
|
|
143
|
+
|
|
144
|
+
def test_notes_when_a_rejected_root_holds_the_only_override(self):
|
|
145
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
146
|
+
home = Path(temp_dir) / "home"
|
|
147
|
+
project = Path(temp_dir) / "project"
|
|
148
|
+
skill = home / ".claude" / "skills" / "demo-skill"
|
|
149
|
+
write(skill / "customize.toml", facts("shipped default"))
|
|
150
|
+
write(home / "_bmad" / "custom" / "demo-skill.toml", facts("home override"))
|
|
151
|
+
(project / "_bmad" / "custom").mkdir(parents=True)
|
|
152
|
+
|
|
153
|
+
result = resolve(skill, project)
|
|
154
|
+
|
|
155
|
+
self.assertEqual(result.returncode, 0, msg=result.stderr)
|
|
156
|
+
resolved = json.loads(result.stdout)["workflow"]["persistent_facts"]
|
|
157
|
+
self.assertEqual(resolved, ["shipped default"])
|
|
158
|
+
self.assertIn("demo-skill", result.stderr)
|
|
159
|
+
self.assertIn("--project-root", result.stderr)
|
|
160
|
+
|
|
161
|
+
def test_explicit_project_root_wins_and_stays_quiet(self):
|
|
162
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
163
|
+
home = Path(temp_dir) / "home"
|
|
164
|
+
project = Path(temp_dir) / "project"
|
|
165
|
+
skill = home / ".claude" / "skills" / "demo-skill"
|
|
166
|
+
write(skill / "customize.toml", facts("shipped default"))
|
|
167
|
+
write(home / "_bmad" / "custom" / "demo-skill.toml", facts("home override"))
|
|
168
|
+
(project / "_bmad" / "custom").mkdir(parents=True)
|
|
169
|
+
|
|
170
|
+
result = resolve(skill, project, "--project-root", str(home))
|
|
171
|
+
|
|
172
|
+
self.assertEqual(result.returncode, 0, msg=result.stderr)
|
|
173
|
+
resolved = json.loads(result.stdout)["workflow"]["persistent_facts"]
|
|
174
|
+
self.assertEqual(resolved, ["shipped default", "home override"])
|
|
175
|
+
self.assertEqual(result.stderr, "")
|
|
176
|
+
|
|
177
|
+
|
|
76
178
|
if __name__ == "__main__":
|
|
77
179
|
unittest.main()
|