bmad-method 6.8.1-next.9 → 6.9.0
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/.claude-plugin/marketplace.json +9 -3
- package/package.json +10 -4
- package/src/bmm-skills/1-analysis/bmad-prfaq/SKILL.md +2 -2
- package/src/bmm-skills/1-analysis/bmad-product-brief/SKILL.md +8 -8
- package/src/bmm-skills/2-plan-workflows/bmad-prd/SKILL.md +7 -7
- package/src/bmm-skills/2-plan-workflows/bmad-prd/assets/headless-schemas.md +2 -2
- package/src/bmm-skills/2-plan-workflows/bmad-prd/customize.toml +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-prd/references/headless.md +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-prd/references/validate.md +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-ux/SKILL.md +8 -8
- package/src/bmm-skills/2-plan-workflows/bmad-ux/assets/design-directions.md +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-ux/assets/headless-schemas.md +2 -2
- package/src/bmm-skills/2-plan-workflows/bmad-ux/assets/key-screens.md +4 -4
- package/src/bmm-skills/2-plan-workflows/bmad-ux/customize.toml +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-ux/references/creative-tools.md +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-ux/references/headless.md +1 -1
- package/src/bmm-skills/2-plan-workflows/bmad-ux/references/validate.md +2 -2
- package/src/bmm-skills/3-solutioning/bmad-agent-architect/customize.toml +2 -2
- package/src/bmm-skills/3-solutioning/bmad-architecture/SKILL.md +85 -0
- package/src/bmm-skills/3-solutioning/bmad-architecture/assets/spine-template.md +79 -0
- package/src/bmm-skills/3-solutioning/bmad-architecture/customize.toml +100 -0
- package/src/bmm-skills/3-solutioning/bmad-architecture/references/headless.md +26 -0
- package/src/bmm-skills/3-solutioning/bmad-architecture/references/reviewer-gate.md +13 -0
- package/src/bmm-skills/3-solutioning/bmad-architecture/scripts/lint_spine.py +257 -0
- package/src/bmm-skills/3-solutioning/bmad-architecture/scripts/tests/test_lint_spine.py +270 -0
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/SKILL.md +16 -60
- package/src/bmm-skills/4-implementation/bmad-retrospective/SKILL.md +15 -0
- package/src/bmm-skills/4-implementation/bmad-sprint-planning/SKILL.md +20 -1
- package/src/bmm-skills/4-implementation/bmad-sprint-planning/checklist.md +2 -1
- package/src/bmm-skills/4-implementation/bmad-sprint-planning/sprint-status-template.yaml +13 -0
- package/src/bmm-skills/4-implementation/bmad-sprint-status/SKILL.md +13 -0
- package/src/bmm-skills/module-help.csv +2 -2
- package/src/core-skills/bmad-brainstorming/SKILL.md +8 -10
- package/src/core-skills/bmad-brainstorming/references/converge.md +1 -1
- package/src/core-skills/bmad-brainstorming/references/finalize.md +1 -1
- package/src/core-skills/bmad-brainstorming/references/headless.md +4 -4
- package/src/core-skills/bmad-brainstorming/references/in-chat-techniques.md +1 -1
- package/src/core-skills/bmad-brainstorming/references/mode-autonomous.md +1 -1
- package/src/core-skills/bmad-brainstorming/scripts/tests/test_brain.py +2 -2
- package/src/core-skills/bmad-customize/scripts/tests/test_list_customizable_skills.py +1 -1
- package/src/core-skills/bmad-forge-idea/SKILL.md +79 -0
- package/src/core-skills/bmad-forge-idea/customize.toml +42 -0
- package/src/core-skills/bmad-forge-idea/scripts/resolve_personas.py +270 -0
- package/src/core-skills/bmad-forge-idea/scripts/tests/test_resolve_personas.py +138 -0
- package/src/core-skills/bmad-party-mode/SKILL.md +39 -56
- package/src/core-skills/bmad-party-mode/customize.toml +175 -0
- package/src/core-skills/bmad-party-mode/references/create-party.md +70 -0
- package/src/core-skills/bmad-party-mode/references/mode-agent-team.md +11 -0
- package/src/core-skills/bmad-party-mode/references/mode-auto.md +13 -0
- package/src/core-skills/bmad-party-mode/references/mode-subagent.md +19 -0
- package/src/core-skills/bmad-party-mode/references/party-memory.md +51 -0
- package/src/core-skills/bmad-party-mode/scripts/resolve_party.py +272 -0
- package/src/core-skills/bmad-party-mode/scripts/tests/test-resolve_party.py +146 -0
- package/src/core-skills/bmad-spec/SKILL.md +5 -3
- package/src/core-skills/bmad-spec/assets/spec-template.md +3 -3
- package/src/core-skills/module-help.csv +1 -0
- package/src/scripts/resolve_config.py +8 -6
- package/src/scripts/resolve_customization.py +8 -6
- package/tools/installer/commands/install.js +3 -0
- package/tools/installer/core/installer.js +3 -0
- package/tools/installer/core/uv-check.js +97 -0
- package/tools/installer/core/wsl-node-check.js +109 -0
- package/tools/installer/ide/platform-codes.yaml +7 -0
- package/tools/installer/install-messages.yaml +4 -0
- package/tools/installer/ui.js +10 -9
- package/evals/bmm-skills/bmad-product-brief/evals.json +0 -237
- package/evals/bmm-skills/bmad-product-brief/files/branfield-memo.md +0 -46
- package/evals/bmm-skills/bmad-product-brief/files/forkbird-brief/addendum.md +0 -40
- package/evals/bmm-skills/bmad-product-brief/files/forkbird-brief/brief.md +0 -56
- package/evals/bmm-skills/bmad-product-brief/files/forkbird-brief/decision-log.md +0 -27
- package/evals/bmm-skills/bmad-product-brief/files/meridian-mobility-report.md +0 -116
- package/evals/bmm-skills/bmad-product-brief/files/mossridge-brief/addendum.md +0 -41
- package/evals/bmm-skills/bmad-product-brief/files/mossridge-brief/brief.md +0 -57
- package/evals/bmm-skills/bmad-product-brief/files/mossridge-brief/decision-log.md +0 -29
- package/evals/bmm-skills/bmad-product-brief/files/pantry-bridge-interviews.md +0 -90
- package/evals/bmm-skills/bmad-product-brief/files/q2-brainstorm.md +0 -101
- package/evals/bmm-skills/bmad-product-brief/triggers.json +0 -18
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/architecture-decision-template.md +0 -12
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/data/domain-complexity.csv +0 -13
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/data/project-types.csv +0 -7
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-01-init.md +0 -153
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-01b-continue.md +0 -173
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-02-context.md +0 -224
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-03-starter.md +0 -329
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-04-decisions.md +0 -318
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-05-patterns.md +0 -359
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-06-structure.md +0 -379
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-07-validation.md +0 -361
- package/src/bmm-skills/3-solutioning/bmad-create-architecture/steps/step-08-complete.md +0 -82
- package/src/core-skills/bmad-brainstorming/scripts/memlog.py +0 -202
- package/src/core-skills/bmad-brainstorming/scripts/tests/test_memlog.py +0 -265
- package/tools/installer/core/python-check.js +0 -199
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# /// script
|
|
2
|
+
# requires-python = ">=3.10"
|
|
3
|
+
# dependencies = ["pytest>=8.0"]
|
|
4
|
+
# ///
|
|
5
|
+
"""Tests for lint_spine.py. Run: uv run --with pytest pytest scripts/tests/test_lint_spine.py
|
|
6
|
+
|
|
7
|
+
The spine under test: a clean spine lints empty; the linter catches exactly the
|
|
8
|
+
mechanical defects a prompt is unreliable at — literal placeholders, AD-n id breakage,
|
|
9
|
+
AD-n blocks missing required fields, and unpinned Stack versions.
|
|
10
|
+
"""
|
|
11
|
+
import importlib.util
|
|
12
|
+
import json
|
|
13
|
+
import re
|
|
14
|
+
import sys
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
import pytest
|
|
18
|
+
|
|
19
|
+
_SPEC = importlib.util.spec_from_file_location(
|
|
20
|
+
"lint_spine", Path(__file__).resolve().parent.parent / "lint_spine.py"
|
|
21
|
+
)
|
|
22
|
+
lint_spine = importlib.util.module_from_spec(_SPEC)
|
|
23
|
+
sys.modules["lint_spine"] = lint_spine
|
|
24
|
+
_SPEC.loader.exec_module(lint_spine)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
CLEAN = """---
|
|
28
|
+
name: 'Demo'
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Invariants & Rules
|
|
32
|
+
|
|
33
|
+
### AD-1 — single write path
|
|
34
|
+
|
|
35
|
+
- **Binds:** all
|
|
36
|
+
- **Prevents:** divergent mutation
|
|
37
|
+
- **Rule:** state changes only through the command bus
|
|
38
|
+
|
|
39
|
+
### AD-2 — layered deps `[ADOPTED]`
|
|
40
|
+
|
|
41
|
+
- **Binds:** all
|
|
42
|
+
- **Prevents:** import cycles
|
|
43
|
+
- **Rule:** ui -> app -> domain, never backward
|
|
44
|
+
|
|
45
|
+
```mermaid
|
|
46
|
+
flowchart LR
|
|
47
|
+
A --> B{decision}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Stack
|
|
51
|
+
|
|
52
|
+
| Name | Version |
|
|
53
|
+
| --- | --- |
|
|
54
|
+
| fastapi | 0.115 |
|
|
55
|
+
| pydantic | 2.9 |
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def cats(result):
|
|
60
|
+
return sorted(f["category"] for f in result["findings"])
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_clean_spine_passes():
|
|
64
|
+
result = lint_spine.lint(CLEAN)
|
|
65
|
+
assert result["ok"] is True
|
|
66
|
+
assert result["total_findings"] == 0
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_mermaid_braces_not_flagged():
|
|
70
|
+
# the {decision} node lives in a fenced block and must not read as a template token
|
|
71
|
+
result = lint_spine.lint(CLEAN)
|
|
72
|
+
assert "placeholder" not in cats(result)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def test_placeholder_markers_caught():
|
|
76
|
+
text = CLEAN.replace("the command bus", "TBD")
|
|
77
|
+
result = lint_spine.lint(text)
|
|
78
|
+
assert "placeholder" in cats(result)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def test_similar_to_caught():
|
|
82
|
+
text = CLEAN.replace("import cycles", "similar to AD-1")
|
|
83
|
+
result = lint_spine.lint(text)
|
|
84
|
+
assert any("cross-reference" in f["detail"] for f in result["findings"])
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def test_unfilled_template_token_caught():
|
|
88
|
+
text = CLEAN.replace("single write path", "{decision}")
|
|
89
|
+
result = lint_spine.lint(text)
|
|
90
|
+
assert any(f["category"] == "placeholder" for f in result["findings"])
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def test_duplicate_ad_id_caught():
|
|
94
|
+
text = CLEAN.replace("### AD-2 — layered deps `[ADOPTED]`", "### AD-1 — layered deps")
|
|
95
|
+
result = lint_spine.lint(text)
|
|
96
|
+
assert "ad_id" in cats(result)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_non_monotonic_ad_id_caught():
|
|
100
|
+
text = CLEAN.replace("### AD-2 — layered deps `[ADOPTED]`", "### AD-5 — layered deps").replace(
|
|
101
|
+
"### AD-1 — single write path", "### AD-9 — single write path"
|
|
102
|
+
)
|
|
103
|
+
result = lint_spine.lint(text)
|
|
104
|
+
assert any("non-monotonic" in f["detail"] for f in result["findings"])
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def test_missing_field_caught():
|
|
108
|
+
text = CLEAN.replace("- **Rule:** state changes only through the command bus\n", "")
|
|
109
|
+
result = lint_spine.lint(text)
|
|
110
|
+
assert any(f["category"] == "ad_fields" and "rule" in f["detail"] for f in result["findings"])
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_unpinned_dep_caught():
|
|
114
|
+
text = CLEAN.replace("| fastapi | 0.115 |", "| fastapi | |")
|
|
115
|
+
result = lint_spine.lint(text)
|
|
116
|
+
assert "version_pin" in cats(result)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_placeholder_version_caught():
|
|
120
|
+
text = CLEAN.replace("| fastapi | 0.115 |", "| fastapi | {pin} |")
|
|
121
|
+
result = lint_spine.lint(text)
|
|
122
|
+
assert any(f["category"] == "version_pin" and "fastapi" in f["detail"] for f in result["findings"])
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def test_no_stack_section_ok():
|
|
126
|
+
text = CLEAN.split("## Stack")[0]
|
|
127
|
+
result = lint_spine.lint(text)
|
|
128
|
+
assert "version_pin" not in cats(result)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def test_stack_skeleton_row_not_version_pinned():
|
|
132
|
+
# a leftover {token} name is the placeholder pass's job, not a double-reported version_pin
|
|
133
|
+
text = CLEAN.replace("| fastapi | 0.115 |", "| {language / framework} | {pinned version} |")
|
|
134
|
+
result = lint_spine.lint(text)
|
|
135
|
+
assert "version_pin" not in cats(result)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def test_stack_html_comment_not_parsed_as_row():
|
|
139
|
+
text = CLEAN.replace("## Stack\n", "## Stack\n\n<!-- SEED — verified current 2026-06 -->\n")
|
|
140
|
+
result = lint_spine.lint(text)
|
|
141
|
+
assert "version_pin" not in cats(result)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def test_template_token_is_low_severity():
|
|
145
|
+
# a bare {token} can be legitimate brace prose; it is flagged, but low (not high) so the
|
|
146
|
+
# mechanical pass stays near-zero false-positive
|
|
147
|
+
text = CLEAN.replace("single write path", "{decision}")
|
|
148
|
+
result = lint_spine.lint(text)
|
|
149
|
+
toks = [f for f in result["findings"] if f["category"] == "placeholder" and "template token" in f["detail"]]
|
|
150
|
+
assert toks and all(f["severity"] == "low" for f in toks)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def test_no_frontmatter_body_still_scanned():
|
|
154
|
+
text = "## Invariants\n\n### AD-1 — x\n\n- **Binds:** all\n- **Prevents:** drift\n- **Rule:** TBD\n"
|
|
155
|
+
result = lint_spine.lint(text)
|
|
156
|
+
assert "placeholder" in cats(result) # TBD caught even with no frontmatter
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def test_frontmatter_value_with_dashes_not_truncated():
|
|
160
|
+
# a value containing '---' must not be read as the closing fence (line-exact close)
|
|
161
|
+
text = ("---\nname: 'x'\nscope: 'phase 1 --- phase 2'\n---\n\n"
|
|
162
|
+
"## Stack\n\n| Name | Version |\n| --- | --- |\n| fastapi | |\n")
|
|
163
|
+
result = lint_spine.lint(text)
|
|
164
|
+
assert any(f["category"] == "version_pin" for f in result["findings"]) # read past the inline ---
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def test_ad_heading_in_fence_not_counted():
|
|
168
|
+
text = (
|
|
169
|
+
"---\nname: 'x'\n---\n\n"
|
|
170
|
+
"### AD-1 — real\n\n- **Binds:** all\n- **Prevents:** drift\n- **Rule:** do x\n\n"
|
|
171
|
+
"## Docs\n\n```text\n### AD-2 — illustrative only, no fields\n```\n"
|
|
172
|
+
)
|
|
173
|
+
result = lint_spine.lint(text)
|
|
174
|
+
assert result["ok"] is True # the fenced AD-2 is not a live AD → no ad_fields/ad_id finding
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def test_stack_table_flags_only_the_unpinned_row():
|
|
178
|
+
text = ("---\nname: 'x'\n---\n\n## Stack\n\n| Name | Version |\n| --- | --- |\n"
|
|
179
|
+
"| fastapi | 0.115 |\n| redis | |\n")
|
|
180
|
+
result = lint_spine.lint(text)
|
|
181
|
+
pins = [f for f in result["findings"] if f["category"] == "version_pin"]
|
|
182
|
+
assert len(pins) == 1 and "redis" in pins[0]["detail"]
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def test_stack_table_all_pinned_ok():
|
|
186
|
+
text = ("---\nname: 'x'\n---\n\n## Stack\n\n| Name | Version |\n| --- | --- |\n"
|
|
187
|
+
"| fastapi | 0.115 |\n")
|
|
188
|
+
result = lint_spine.lint(text)
|
|
189
|
+
assert "version_pin" not in cats(result)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def test_fenced_stack_rows_not_parsed():
|
|
193
|
+
# an illustrative fenced table under ## Stack must not be read as live rows (fences are
|
|
194
|
+
# blanked first, like every other pass) — a blank-version row inside a fence is not a finding
|
|
195
|
+
text = ("---\nname: 'x'\n---\n\n## Stack\n\n| Name | Version |\n| --- | --- |\n"
|
|
196
|
+
"| fastapi | 0.115 |\n\n```text\n| example | |\n```\n")
|
|
197
|
+
result = lint_spine.lint(text)
|
|
198
|
+
assert "version_pin" not in cats(result)
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def test_fenced_stack_heading_not_live():
|
|
202
|
+
# a `## Stack` heading shown inside a code fence is not the live Stack section
|
|
203
|
+
text = ("---\nname: 'x'\n---\n\n## Docs\n\n```md\n## Stack\n\n| foo | |\n```\n")
|
|
204
|
+
result = lint_spine.lint(text)
|
|
205
|
+
assert "version_pin" not in cats(result)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def test_renamed_stack_heading_still_scanned():
|
|
209
|
+
# the heading match is word-boundary, so a varied `## Stack` heading still counts
|
|
210
|
+
text = ("---\nname: 'x'\n---\n\n## Stack & Versions\n\n| Name | Version |\n| --- | --- |\n"
|
|
211
|
+
"| redis | |\n")
|
|
212
|
+
result = lint_spine.lint(text)
|
|
213
|
+
pins = [f for f in result["findings"] if f["category"] == "version_pin"]
|
|
214
|
+
assert len(pins) == 1 and "redis" in pins[0]["detail"]
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def test_reordered_columns_pair_name_to_version():
|
|
218
|
+
# Version-then-Name header: the unpinned row must still be flagged by its real name
|
|
219
|
+
text = ("---\nname: 'x'\n---\n\n## Stack\n\n| Version | Name |\n| --- | --- |\n"
|
|
220
|
+
"| 0.115 | fastapi |\n| | redis |\n")
|
|
221
|
+
result = lint_spine.lint(text)
|
|
222
|
+
pins = [f for f in result["findings"] if f["category"] == "version_pin"]
|
|
223
|
+
assert len(pins) == 1 and "redis" in pins[0]["detail"]
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def test_placeholder_line_number_is_absolute():
|
|
227
|
+
# a TBD after a multi-line fence reports its real file line (fence blanked, not collapsed)
|
|
228
|
+
text = (
|
|
229
|
+
"---\nname: 'x'\n---\n\n"
|
|
230
|
+
"## A\n\n"
|
|
231
|
+
"```text\nf1\nf2\nf3\n```\n\n"
|
|
232
|
+
"TBD here\n"
|
|
233
|
+
)
|
|
234
|
+
result = lint_spine.lint(text)
|
|
235
|
+
ph = next(f for f in result["findings"] if "TBD" in f["detail"])
|
|
236
|
+
n = int(re.search(r"line (\d+)", ph["location"]).group(1))
|
|
237
|
+
assert n == 13
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def test_missing_spine_file_reports_error(tmp_path, capsys):
|
|
241
|
+
rc = lint_spine.main(["--workspace", str(tmp_path)])
|
|
242
|
+
out = json.loads(capsys.readouterr().out)
|
|
243
|
+
assert rc == 0 and out["ok"] is False and "not found" in out["error"]
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def test_frontmatter_unfilled_token_caught():
|
|
247
|
+
# an unfilled {scope}/{paradigm}/{date} in frontmatter is part of the contract and must lint
|
|
248
|
+
text = "---\nname: 'x'\nscope: '{what this spine governs}'\n---\n\n## Invariants\n"
|
|
249
|
+
result = lint_spine.lint(text)
|
|
250
|
+
fm = [f for f in result["findings"] if f["category"] == "placeholder" and "frontmatter" in f["detail"]]
|
|
251
|
+
assert fm and any("template token" in f["detail"] for f in fm)
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def test_frontmatter_tbd_caught():
|
|
255
|
+
text = "---\nname: 'x'\nstatus: TBD\n---\n\n## Invariants\n"
|
|
256
|
+
result = lint_spine.lint(text)
|
|
257
|
+
assert any(f["category"] == "placeholder" and "frontmatter" in f["detail"] and "TBD" in f["detail"]
|
|
258
|
+
for f in result["findings"])
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def test_unreadable_spine_returns_error_not_crash(tmp_path, capsys):
|
|
262
|
+
# a spine that exists but can't be UTF-8 decoded must yield error JSON + exit 0, not a traceback
|
|
263
|
+
(tmp_path / lint_spine.SPINE).write_bytes(b"\xff\xfe bad bytes not utf-8")
|
|
264
|
+
rc = lint_spine.main(["--workspace", str(tmp_path)])
|
|
265
|
+
out = json.loads(capsys.readouterr().out)
|
|
266
|
+
assert rc == 0 and out["ok"] is False and "could not read" in out["error"]
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
if __name__ == "__main__":
|
|
270
|
+
sys.exit(pytest.main([__file__, "-q"]))
|
|
@@ -1,74 +1,30 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bmad-create-architecture
|
|
3
|
-
description: '
|
|
3
|
+
description: 'DEPRECATED — consolidated into bmad-architecture create intent - this skill will be removed in v7 in favor of `bmad-architecture`.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# DEPRECATED — forwards to bmad-architecture (create intent)
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
**Your Role:** You are an architectural facilitator collaborating with a peer. This is a partnership, not a client-vendor relationship. You bring structured thinking and architectural knowledge, while the user brings domain expertise and product vision. Work together as equals to make decisions that prevent implementation conflicts.
|
|
11
|
-
|
|
12
|
-
## Conventions
|
|
13
|
-
|
|
14
|
-
- Bare paths (e.g. `steps/step-01-init.md`) resolve from the skill root.
|
|
15
|
-
- `{skill-root}` resolves to this skill's installed directory (where `customize.toml` lives).
|
|
16
|
-
- `{project-root}`-prefixed paths resolve from the project working directory.
|
|
17
|
-
- `{skill-name}` resolves to the skill directory's basename.
|
|
18
|
-
|
|
19
|
-
## WORKFLOW ARCHITECTURE
|
|
20
|
-
|
|
21
|
-
This uses **micro-file architecture** for disciplined execution:
|
|
22
|
-
|
|
23
|
-
- Each step is a self-contained file with embedded rules
|
|
24
|
-
- Sequential progression with user control at each step
|
|
25
|
-
- Document state tracked in frontmatter
|
|
26
|
-
- Append-only document building through conversation
|
|
27
|
-
- You NEVER proceed to a step file if the current step file indicates the user must approve and indicate continuation.
|
|
8
|
+
This skill was consolidated into `bmad-architecture`. It is retained as a thin compatibility shim so existing invocations by name and `_bmad/custom/bmad-create-architecture.toml` override files keep working. New work should invoke `bmad-architecture` directly — it detects create / update / validate intent from the conversation.
|
|
28
9
|
|
|
29
10
|
## On Activation
|
|
30
11
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`
|
|
34
|
-
|
|
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
|
-
|
|
37
|
-
1. `{skill-root}/customize.toml` — defaults
|
|
38
|
-
2. `{project-root}/_bmad/custom/{skill-name}.toml` — team overrides
|
|
39
|
-
3. `{project-root}/_bmad/custom/{skill-name}.user.toml` — personal overrides
|
|
40
|
-
|
|
41
|
-
Any missing file is skipped. Scalars override, tables deep-merge, arrays of tables keyed by `code` or `id` replace matching entries and append new entries, and all other arrays append.
|
|
42
|
-
|
|
43
|
-
### Step 2: Execute Prepend Steps
|
|
44
|
-
|
|
45
|
-
Execute each entry in `{workflow.activation_steps_prepend}` in order before proceeding.
|
|
46
|
-
|
|
47
|
-
### Step 3: Load Persistent Facts
|
|
48
|
-
|
|
49
|
-
Treat every entry in `{workflow.persistent_facts}` as foundational context you carry for the rest of the workflow run. Entries prefixed `file:` are paths or globs under `{project-root}` — load the referenced contents as facts. All other entries are facts verbatim.
|
|
50
|
-
|
|
51
|
-
### Step 4: Load Config
|
|
52
|
-
|
|
53
|
-
Load config from `{project-root}/_bmad/bmm/config.yaml` and resolve:
|
|
54
|
-
- Use `{user_name}` for greeting
|
|
55
|
-
- Use `{communication_language}` for all communications
|
|
56
|
-
- Use `{document_output_language}` for output documents
|
|
57
|
-
- Use `{planning_artifacts}` for output location and artifact scanning
|
|
58
|
-
- Use `{project_knowledge}` for additional context scanning
|
|
59
|
-
|
|
60
|
-
### Step 5: Greet the User
|
|
61
|
-
|
|
62
|
-
Greet `{user_name}`, speaking in `{communication_language}`.
|
|
12
|
+
1. Resolve customization: `python3 {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`).
|
|
63
13
|
|
|
64
|
-
|
|
14
|
+
2. Load `{project-root}/_bmad/bmm/config.yaml` (and `config.user.yaml` if present) to resolve `{user_name}` and `{communication_language}`.
|
|
65
15
|
|
|
66
|
-
|
|
16
|
+
3. Emit a deprecation notice to the user in `{communication_language}`:
|
|
67
17
|
|
|
68
|
-
|
|
18
|
+
> Notice: `bmad-create-architecture` is deprecated and will be removed in a future release. It now forwards to `bmad-architecture` with create intent. To silence this notice and access the full new customization surface (`spine_template`, `spine_output_path`, `run_folder_pattern`, `doc_standards`, `external_sources`, `external_handoffs`, `finalize_reviewers`), migrate `_bmad/custom/bmad-create-architecture.toml` to `_bmad/custom/bmad-architecture.toml` and invoke `bmad-architecture` directly next time. Customization fields that were in this version still remain in the new version and will be respected if present in `_bmad/custom/bmad-architecture.toml`, but the new version also supports additional fields that you can take advantage of by migrating.
|
|
69
19
|
|
|
70
|
-
|
|
20
|
+
4. Invoke `bmad-architecture` with the following context. Pass these as the activating context so `bmad-architecture` honors them instead of resolving its own customization from scratch:
|
|
71
21
|
|
|
72
|
-
|
|
22
|
+
- **Intent:** `create` — skip `bmad-architecture`'s usual intent detection step.
|
|
23
|
+
- **Pre-resolved legacy customization** — use these in place of resolving from `bmad-architecture`'s own `customize.toml` for the four legacy fields. For everything else (`spine_template`, `spine_output_path`, `run_folder_pattern`, `doc_standards`, `external_sources`, `external_handoffs`, `finalize_reviewers`), use `bmad-architecture`'s own defaults and overrides as normal:
|
|
24
|
+
- `activation_steps_prepend` = the resolved value from step 1
|
|
25
|
+
- `activation_steps_append` = the resolved value from step 1
|
|
26
|
+
- `persistent_facts` = the resolved value from step 1
|
|
27
|
+
- `on_complete` = the resolved value from step 1
|
|
28
|
+
- **Original user input:** forward whatever the user said when invoking this skill verbatim.
|
|
73
29
|
|
|
74
|
-
|
|
30
|
+
`bmad-architecture` takes the workflow from here. Do not execute any further steps in this shim.
|
|
@@ -350,6 +350,7 @@ Amelia (Developer): "I found our retrospectives from Epic {{prev_epic_num}}. Let
|
|
|
350
350
|
|
|
351
351
|
**Action Item Follow-Through:**
|
|
352
352
|
- For each action item from Epic {{prev_epic_num}} retro, check if it was completed
|
|
353
|
+
- Cross-check the action_items section in {sprint_status_file} (if present) for Epic {{prev_epic_num}} entries and their current status
|
|
353
354
|
- Look for evidence in current epic's story records
|
|
354
355
|
- Mark each action item: ✅ Completed, ⏳ In Progress, ❌ Not Addressed
|
|
355
356
|
|
|
@@ -1403,6 +1404,19 @@ Amelia (Developer): "See you all when prep work is done. Meeting adjourned!"
|
|
|
1403
1404
|
<action>Find development_status key "epic-{{epic_number}}-retrospective"</action>
|
|
1404
1405
|
<action>Verify current status (typically "optional" or "pending")</action>
|
|
1405
1406
|
<action>Update development_status["epic-{{epic_number}}-retrospective"] = "done"</action>
|
|
1407
|
+
<action>Append each Epic {{epic_number}} action item to the action_items section, creating the section after development_status if missing. One entry per item:</action>
|
|
1408
|
+
|
|
1409
|
+
```yaml
|
|
1410
|
+
action_items:
|
|
1411
|
+
- epic: {{epic_number}}
|
|
1412
|
+
action: "{{action_description}}"
|
|
1413
|
+
owner: "{{owner}}"
|
|
1414
|
+
status: open
|
|
1415
|
+
```
|
|
1416
|
+
|
|
1417
|
+
<action>Quote action and owner values so punctuation (e.g., "#") cannot break YAML parsing</action>
|
|
1418
|
+
|
|
1419
|
+
<action>Update Epic {{prev_epic_num}} action_items entries based on Step 4 follow-through: ✅ Completed → done, ⏳ In Progress → in-progress, ❌ Not Addressed → keep existing status (do not modify)</action>
|
|
1406
1420
|
<action>Update last_updated field to current date</action>
|
|
1407
1421
|
<action>Save file, preserving ALL comments and structure including STATUS DEFINITIONS</action>
|
|
1408
1422
|
|
|
@@ -1412,6 +1426,7 @@ Amelia (Developer): "See you all when prep work is done. Meeting adjourned!"
|
|
|
1412
1426
|
|
|
1413
1427
|
Retrospective key: epic-{{epic_number}}-retrospective
|
|
1414
1428
|
Status: {{previous_status}} → done
|
|
1429
|
+
Action items recorded: {{action_count}}
|
|
1415
1430
|
</output>
|
|
1416
1431
|
</check>
|
|
1417
1432
|
|
|
@@ -151,6 +151,7 @@ development_status:
|
|
|
151
151
|
|
|
152
152
|
- If existing `{status_file}` exists and has more advanced status, preserve it
|
|
153
153
|
- Never downgrade status (e.g., don't change `done` to `ready-for-dev`)
|
|
154
|
+
- If existing `{status_file}` has an `action_items` section, carry it over unchanged
|
|
154
155
|
|
|
155
156
|
**Status Flow Reference:**
|
|
156
157
|
|
|
@@ -194,12 +195,18 @@ development_status:
|
|
|
194
195
|
# - optional: Can be completed but not required
|
|
195
196
|
# - done: Retrospective has been completed
|
|
196
197
|
#
|
|
198
|
+
# Action Item Status:
|
|
199
|
+
# - open: Committed during a retrospective, not yet addressed
|
|
200
|
+
# - in-progress: Actively being worked on
|
|
201
|
+
# - done: Completed
|
|
202
|
+
#
|
|
197
203
|
# WORKFLOW NOTES:
|
|
198
204
|
# ===============
|
|
199
205
|
# - Epic transitions to 'in-progress' automatically when first story is created
|
|
200
206
|
# - Stories can be worked in parallel if team capacity allows
|
|
201
207
|
# - Developer typically creates next story after previous one is 'done' to incorporate learnings
|
|
202
208
|
# - Dev moves story to 'review', then runs code-review (fresh context, different LLM recommended)
|
|
209
|
+
# - Retrospective appends its action items to action_items; sprint-status surfaces open ones
|
|
203
210
|
|
|
204
211
|
generated: { date }
|
|
205
212
|
last_updated: { date }
|
|
@@ -215,6 +222,7 @@ development_status:
|
|
|
215
222
|
<action>Write the complete sprint status YAML to {status_file}</action>
|
|
216
223
|
<action>CRITICAL: Metadata appears TWICE - once as comments (#) for documentation, once as YAML key:value fields for parsing</action>
|
|
217
224
|
<action>Ensure all items are ordered: epic, its stories, its retrospective, next epic...</action>
|
|
225
|
+
<action>If the existing file had an action_items section, write it back unchanged after development_status</action>
|
|
218
226
|
</step>
|
|
219
227
|
|
|
220
228
|
<step n="5" goal="Validate and report">
|
|
@@ -223,7 +231,8 @@ development_status:
|
|
|
223
231
|
- [ ] Every epic in epic files appears in {status_file}
|
|
224
232
|
- [ ] Every story in epic files appears in {status_file}
|
|
225
233
|
- [ ] Every epic has a corresponding retrospective entry
|
|
226
|
-
- [ ] No items in {status_file} that don't exist in epic files
|
|
234
|
+
- [ ] No development_status items in {status_file} that don't exist in epic files
|
|
235
|
+
- [ ] action_items section (if it existed) carried over unchanged
|
|
227
236
|
- [ ] All status values are legal (match state machine definitions)
|
|
228
237
|
- [ ] File is valid YAML syntax
|
|
229
238
|
|
|
@@ -291,6 +300,16 @@ optional ↔ done
|
|
|
291
300
|
- **optional**: Ready to be conducted but not required
|
|
292
301
|
- **done**: Finished
|
|
293
302
|
|
|
303
|
+
**Action Item Status:**
|
|
304
|
+
|
|
305
|
+
```
|
|
306
|
+
open → in-progress → done
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
- **open**: Committed during a retrospective, not yet addressed
|
|
310
|
+
- **in-progress**: Actively being worked on
|
|
311
|
+
- **done**: Completed
|
|
312
|
+
|
|
294
313
|
### Guidelines
|
|
295
314
|
|
|
296
315
|
1. **Epic Activation**: Mark epic as `in-progress` when starting work on its first story
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
- [ ] Every epic found in epic\*.md files appears in sprint-status.yaml
|
|
8
8
|
- [ ] Every story found in epic\*.md files appears in sprint-status.yaml
|
|
9
9
|
- [ ] Every epic has a corresponding retrospective entry
|
|
10
|
-
- [ ] No items in sprint-status.yaml that don't exist in epic files
|
|
10
|
+
- [ ] No development_status items in sprint-status.yaml that don't exist in epic files
|
|
11
|
+
- [ ] action_items section (if it existed) carried over unchanged
|
|
11
12
|
|
|
12
13
|
### Parsing Verification
|
|
13
14
|
|
|
@@ -26,11 +26,17 @@
|
|
|
26
26
|
# - optional: Can be completed but not required
|
|
27
27
|
# - done: Retrospective has been completed
|
|
28
28
|
#
|
|
29
|
+
# Action Item Status:
|
|
30
|
+
# - open: Committed during a retrospective, not yet addressed
|
|
31
|
+
# - in-progress: Actively being worked on
|
|
32
|
+
# - done: Completed
|
|
33
|
+
#
|
|
29
34
|
# WORKFLOW NOTES:
|
|
30
35
|
# ===============
|
|
31
36
|
# - Mark epic as 'in-progress' when starting work on its first story
|
|
32
37
|
# - Developer typically creates next story ONLY after previous one is 'done' to incorporate learnings
|
|
33
38
|
# - Dev moves story to 'review', then Dev runs code-review (fresh context, ideally different LLM)
|
|
39
|
+
# - Retrospective appends its action items to action_items; sprint-status surfaces open ones
|
|
34
40
|
|
|
35
41
|
# EXAMPLE STRUCTURE (your actual epics/stories will replace these):
|
|
36
42
|
|
|
@@ -54,3 +60,10 @@ development_status:
|
|
|
54
60
|
2-2-chat-interface: backlog
|
|
55
61
|
2-3-llm-integration: backlog
|
|
56
62
|
epic-2-retrospective: optional
|
|
63
|
+
|
|
64
|
+
# Action items committed during retrospectives (section created by the retrospective workflow)
|
|
65
|
+
action_items:
|
|
66
|
+
- epic: 1
|
|
67
|
+
action: "Add error-handling review to the code review checklist"
|
|
68
|
+
owner: "Charlie"
|
|
69
|
+
status: open
|
|
@@ -112,12 +112,14 @@ Run `/bmad:bmm:workflows:sprint-planning` to generate it, then rerun sprint-stat
|
|
|
112
112
|
<action>Map legacy epic status "contexted" → "in-progress"</action>
|
|
113
113
|
<action>Count epic statuses: backlog, in-progress, done</action>
|
|
114
114
|
<action>Count retrospective statuses: optional, done</action>
|
|
115
|
+
<action>Parse action_items list if present. Set open_action_items = entries with status "open" or "in-progress"</action>
|
|
115
116
|
|
|
116
117
|
<action>Validate all statuses against known values:</action>
|
|
117
118
|
|
|
118
119
|
- Valid story statuses: backlog, ready-for-dev, in-progress, review, done, drafted (legacy)
|
|
119
120
|
- Valid epic statuses: backlog, in-progress, done, contexted (legacy)
|
|
120
121
|
- Valid retrospective statuses: optional, done
|
|
122
|
+
- Valid action item statuses: open, in-progress, done
|
|
121
123
|
|
|
122
124
|
<check if="any status is unrecognized">
|
|
123
125
|
<output>
|
|
@@ -132,6 +134,7 @@ Run `/bmad:bmm:workflows:sprint-planning` to generate it, then rerun sprint-stat
|
|
|
132
134
|
- Stories: backlog, ready-for-dev, in-progress, review, done
|
|
133
135
|
- Epics: backlog, in-progress, done
|
|
134
136
|
- Retrospectives: optional, done
|
|
137
|
+
- Action items: open, in-progress, done
|
|
135
138
|
</output>
|
|
136
139
|
<ask>How should these be corrected?
|
|
137
140
|
{{#each invalid_entries}}
|
|
@@ -181,6 +184,14 @@ Enter corrections (e.g., "1=in-progress, 2=backlog") or "skip" to continue witho
|
|
|
181
184
|
|
|
182
185
|
**Next Recommendation:** /bmad:bmm:workflows:{{next_workflow_id}} ({{next_story_id}})
|
|
183
186
|
|
|
187
|
+
{{#if open_action_items}}
|
|
188
|
+
**Open Action Items:**
|
|
189
|
+
{{#each open_action_items}}
|
|
190
|
+
|
|
191
|
+
- {{action}} — {{status}} (epic {{epic}}, owner: {{owner}})
|
|
192
|
+
{{/each}}
|
|
193
|
+
{{/if}}
|
|
194
|
+
|
|
184
195
|
{{#if risks}}
|
|
185
196
|
**Risks:**
|
|
186
197
|
{{#each risks}}
|
|
@@ -243,6 +254,7 @@ If the command targets a story, set `story_key={{next_story_id}}` when prompted.
|
|
|
243
254
|
<template-output>epic_backlog = {{epic_backlog}}</template-output>
|
|
244
255
|
<template-output>epic_in_progress = {{epic_in_progress}}</template-output>
|
|
245
256
|
<template-output>epic_done = {{epic_done}}</template-output>
|
|
257
|
+
<template-output>open_action_items = {{open_action_items}}</template-output>
|
|
246
258
|
<template-output>risks = {{risks}}</template-output>
|
|
247
259
|
<action>Return to caller</action>
|
|
248
260
|
</step>
|
|
@@ -283,6 +295,7 @@ If the command targets a story, set `story_key={{next_story_id}}` when prompted.
|
|
|
283
295
|
- Stories: backlog, ready-for-dev, in-progress, review, done (legacy: drafted)
|
|
284
296
|
- Epics: backlog, in-progress, done (legacy: contexted)
|
|
285
297
|
- Retrospectives: optional, done
|
|
298
|
+
- Action items (if present): open, in-progress, done
|
|
286
299
|
<check if="any invalid status found">
|
|
287
300
|
<template-output>is_valid = false</template-output>
|
|
288
301
|
<template-output>error = "Invalid status values: {{invalid_entries}}"</template-output>
|
|
@@ -17,8 +17,8 @@ BMad Method,bmad-product-brief,Create Brief,CB,An expert guided experience to na
|
|
|
17
17
|
BMad Method,bmad-prfaq,PRFAQ Challenge,WB,Working Backwards guided experience to forge and stress-test your product concept to ensure you have a great product that users will love and need through the PRFAQ gauntlet to determine feasibility and alignment with user needs. alternative to product brief.,,-H,1-analysis,,,false,planning_artifacts,prfaq document
|
|
18
18
|
BMad Method,bmad-prd,Create Edit and Review PRD,PRD,"Facilitated PRD workflow — create a new PRD via coached discovery, update an existing one against a change signal, or validate a finished PRD against a checklist with an HTML findings report.",,,2-planning,bmad-product-brief,,true,planning_artifacts,prd
|
|
19
19
|
BMad Method,bmad-ux,Create UX,CU,"Guidance through realizing the plan for your UX, strongly recommended if a UI is a primary piece of the proposed project.",,,2-planning,bmad-prd,,false,planning_artifacts,ux design
|
|
20
|
-
BMad Method,bmad-
|
|
21
|
-
BMad Method,bmad-create-epics-and-stories,Create Epics and Stories,CE,,,,3-solutioning,bmad-
|
|
20
|
+
BMad Method,bmad-architecture,Architecture,CA,Offer once requirements exist (a PRD or spec; plus UX if present) and the user is ready to move from what to how. Also offer any time independently-built parts risk diverging. Produces the architecture spine: the invariants that keep features epics and stories consistent. Comes before epics and stories and scales from a quick spine to a full architecture (brownfield: ratifies the existing codebase).,,,3-solutioning,,,true,planning_artifacts,architecture
|
|
21
|
+
BMad Method,bmad-create-epics-and-stories,Create Epics and Stories,CE,,,,3-solutioning,bmad-architecture,,true,planning_artifacts,epics and stories
|
|
22
22
|
BMad Method,bmad-check-implementation-readiness,Check Implementation Readiness,IR,Ensure PRD UX Architecture and Epics Stories are aligned.,,,3-solutioning,bmad-create-epics-and-stories,,true,planning_artifacts,readiness report
|
|
23
23
|
BMad Method,bmad-sprint-planning,Sprint Planning,SP,Kicks off implementation by producing a plan the implementation agents will follow in sequence for every story.,,,4-implementation,,,true,implementation_artifacts,sprint status
|
|
24
24
|
BMad Method,bmad-sprint-status,Sprint Status,SS,Anytime: Summarize sprint status and route to next workflow.,,,4-implementation,bmad-sprint-planning,,false,,
|
|
@@ -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: `
|
|
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.
|
|
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. Load `{project-root}/_bmad/core/config.yaml` (and `config.user.yaml` if present); resolve `{user_name}`, `{communication_language}`, `{document_output_language}`, `{output_folder}`, `{project_name}`, `{date}`. Missing → 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. It is the *only* context where you generate ideas yourself; never load it otherwise.
|
|
@@ -34,21 +34,19 @@ These fight your defaults, in every mode; hold them deliberately. The stance you
|
|
|
34
34
|
- **Keep shifting the creative domain** — every 5–10 turns (or ~10 ideas when you're generating), usually by moving to the next technique.
|
|
35
35
|
- **One prompt per message while in dialogue (Facilitator, Creative Partner); no multiple-choice menus.** Don't stack questions into a wall or hand a menu that invites lazy picking — both pull the user out of generating. The only exceptions are the two up-front *process* choices (stance, and the technique flow): *how* to run is theirs to pick; *what* to ideate never is.
|
|
36
36
|
|
|
37
|
-
**The memlog** is the session's memory: the single source every output builds from, and the file a resume reloads. Whatever isn't in it is gone. Log every idea, decision, question, and bit of user direction — anything you'd regret losing if the window closed — one line each, the gist in the user's meaning, in time order; never edit or reorder. Skip your prompts and small talk. All writes
|
|
37
|
+
**The memlog** is the session's memory: the single source every output builds from, and the file a resume reloads. Whatever isn't in it is gone. Log every idea, decision, question, and bit of user direction — anything you'd regret losing if the window closed — one line each, the gist in the user's meaning, in time order; never edit or reorder. Skip your prompts and small talk. All writes to memlog are atomic and use the script `memlog.py` invoked as follows:
|
|
38
38
|
|
|
39
|
-
- `memlog.py init --workspace {doc_workspace} --field topic="<topic>" --field goal="<goal>" --field mode="<facilitator|partner|autonomous>"` — create it once topic, goal, and stance are known.
|
|
40
|
-
- `memlog.py append --workspace {doc_workspace} --type <kind> --text "<one-line gist>"` — log one entry. `--type` ∈ `idea`/`insight`/`question`/`decision`/`direction`/`technique` (a switch: `--text "started <name>"`); omit for a plain note. Add `--by user`/`--by coach` to mark authorship — **required in Creative Partner mode** (renders `(idea by user)`); skip it otherwise.
|
|
41
|
-
- `memlog.py set --workspace {doc_workspace} --key status --value complete` — flip status at wrap-up.
|
|
42
|
-
|
|
43
|
-
(Each is `python3 {skill-root}/scripts/memlog.py …`.)
|
|
39
|
+
- `uv run {project-root}/_bmad/scripts/memlog.py init --workspace {doc_workspace} --field topic="<topic>" --field goal="<goal>" --field mode="<facilitator|partner|autonomous>"` — create it once topic, goal, and stance are known.
|
|
40
|
+
- `uv run {project-root}/_bmad/scripts/memlog.py append --workspace {doc_workspace} --type <kind> --text "<one-line gist>"` — log one entry. `--type` ∈ `idea`/`insight`/`question`/`decision`/`direction`/`technique` (a switch: `--text "started <name>"`); omit for a plain note. Add `--by user`/`--by coach` to mark authorship — **required in Creative Partner mode** (renders `(idea by user)`); skip it otherwise.
|
|
41
|
+
- `uv run {project-root}/_bmad/scripts/memlog.py set --workspace {doc_workspace} --key status --value complete` — flip status at wrap-up.
|
|
44
42
|
|
|
45
43
|
## Run a Session
|
|
46
44
|
|
|
47
|
-
Open with one compound question
|
|
45
|
+
Open with one compound question what are we brainstorming, and what's the goal or why behind it (along with asking if there are any inputs or special requests). The why shapes technique choice and synthesis (*kids' iPhone apps to build with your own kids* vs. *to win market share* point different ways). If the kickoff already made both clear, skip the question and confirm; read anything they point you to. Derive a kebab-case `{topic_slug}` and bind `{doc_workspace} = {workflow.output_dir}/{workflow.output_folder_name}/`.
|
|
48
46
|
|
|
49
47
|
Now set the **stance** and the **technique batch** in one step — the composer page does both, so make it the default.
|
|
50
48
|
|
|
51
|
-
**The composer page (primary).** The file is `{skill-root}/assets/brain-selector.html`. With a customized catalog (overridden `{workflow.brain_methods}` or any `{workflow.additional_techniques}`), regenerate it first: `
|
|
49
|
+
**The composer page (primary).** The file is `{skill-root}/assets/brain-selector.html`. With a customized catalog (overridden `{workflow.brain_methods}` or any `{workflow.additional_techniques}`), regenerate it first: `uv run {skill-root}/scripts/brain.py --file {workflow.brain_methods} [--extra {doc_workspace}/extra-techniques.json] html --out {doc_workspace}/brain-selector.html` (pass `--extra`, a JSON list of `{category, technique_name, description}`, when there are additional techniques; the file is then `{doc_workspace}/brain-selector.html`). Try to open it (`open` / `xdg-open` / `start`), then say, in one message: *"It should open in your browser — compose your session, click **Copy prompt**, and paste the result back. If it didn't open, open `<path>` yourself, or say 'let's do it in chat'."* You can't see their browser, so never claim it opened.
|
|
52
50
|
|
|
53
51
|
Read the pasted block: the **`Facilitation mode:`** line → the stance; the **listed techniques** (full category/name/description, some tagged `(random pick)`) → run them as given, no `list`/`show` needed; **`invent N`** / **`you choose N`** → see `## Choosing Techniques`.
|
|
54
52
|
|
|
@@ -63,7 +61,7 @@ For **Facilitator** and **Creative Partner**. (In **Ideate for me** you pick and
|
|
|
63
61
|
Most sessions arrive with a batch already composed on the page — run it as given (each technique's full text is in the paste; no `list`/`show` needed). Two parts of a paste delegate back to you:
|
|
64
62
|
|
|
65
63
|
- **`invent N`** (Inventive Flow) — invent N brand-new techniques on the fly. A line may scope an invention (`invent 1 new technique in the spirit of <category>`, from the page's per-category invent card) — when it does, honor that category's spirit. Announce the order, log each one's name + description, and offer to save a keeper to `{workflow.additional_techniques}` at wrap-up.
|
|
66
|
-
- **`you choose N`** (Facilitator Chosen) — pick N techniques fitting the goal, `{workflow.favorite_techniques}` first; confirm exact names with a scoped `
|
|
64
|
+
- **`you choose N`** (Facilitator Chosen) — pick N techniques fitting the goal, `{workflow.favorite_techniques}` first; confirm exact names with a scoped `uv run {skill-root}/scripts/brain.py --file {workflow.brain_methods} list --category <cat>`. Never pull the library whole into context.
|
|
67
65
|
|
|
68
66
|
If they didn't use the page, load `references/in-chat-techniques.md` and pick the batch in chat (**3–4 is the sweet spot**).
|
|
69
67
|
|
|
@@ -17,7 +17,7 @@ Pick by what the decision needs:
|
|
|
17
17
|
- **PMI (Plus / Minus / Interesting)** — when one strong candidate needs pressure-testing before commitment: list its pluses, minuses, and the merely-interesting, then judge.
|
|
18
18
|
- **MoSCoW** — when scoping a build: sort into Must / Should / Could / Won't-this-time.
|
|
19
19
|
|
|
20
|
-
Log the surviving directions and the reasoning with `
|
|
20
|
+
Log the surviving directions and the reasoning with `uv run {project-root}/_bmad/scripts/memlog.py append --workspace {doc_workspace} --type decision --text "<one-line gist>"` (use `--by` in Creative Partner mode). Two or three convergence moves chained is fine (e.g. cluster → score the clusters); more than that is usually over-processing.
|
|
21
21
|
|
|
22
22
|
## Then finalize
|
|
23
23
|
|
|
@@ -9,7 +9,7 @@ In Facilitator mode this is the one place your own creative contribution is welc
|
|
|
9
9
|
1. **Hand them the mirror first.** Reflect a vivid sampling of *their* ideas back — deliberately include the odd, random, or buried ones from earlier, not just the recent obvious ones (in Creative Partner mode the `(... by user)` tags tell you which were theirs). Ask what they see now: conclusions, synergies, themes, the few that actually matter. Let them connect first; their own pattern-recognition is the point.
|
|
10
10
|
2. **Then add the connections they would miss.** Lean in creatively — not new raw ideas, but the non-obvious links: this idea from technique one quietly solves that tension from technique four; these three are one idea wearing three hats; this wildcard is the real breakthrough.
|
|
11
11
|
|
|
12
|
-
Record the insights and chosen directions with `memlog.py append --type insight`. **Then run `
|
|
12
|
+
Record the insights and chosen directions with `uv run {project-root}/_bmad/scripts/memlog.py append --workspace {doc_workspace} --type insight --text "<insights + chosen directions>"`. **Then run `uv run {project-root}/_bmad/scripts/memlog.py set --workspace {doc_workspace} --key status --value complete`** — the session is done and must stop being offered for resume. Do this even if the user declines every artifact below.
|
|
13
13
|
|
|
14
14
|
## Artifacts
|
|
15
15
|
|