Compare commits

...

3 Commits

Author SHA1 Message Date
Brian Madison 6a56d2eb11 fix(bmad-prd): utf-8 encoding on render script, correct workflow-map outputs
- render-validation-html.py reads findings/template and writes HTML/MD with
  explicit utf-8 encoding so non-ASCII content (smart quotes, em-dashes,
  non-English text under {document_output_language}) does not break on
  platforms whose default encoding is not utf-8.
- workflow-map.md 'Produces' column for bmad-prd now distinguishes
  Create/Update outputs from the Validate intent's validation-report
  artifacts.
2026-05-13 16:35:36 -05:00
Brian Madison e7f80909fa docs(expand): refresh "five recipes" copy to reflect Recipe 6
Recipe 6 (Advanced Integration Patterns) was added but three earlier
mentions still said "five": the frontmatter description, the intro
sentence at line 8, and the "Combining Recipes" paragraph. Update all
three to "six" and extend the Combining-Recipes example to call out
Recipe 6 (external_sources / external_handoffs) alongside the others.

Addresses coderabbitai review comment 3235107194 and the two
outside-diff observations on lines 3 and 8.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 16:17:03 -05:00
Brian Madison 45b168f015 fix(bmad-prd): normalize status casing and add friendly file errors
- compute_stats: lower-case `status` before bucketing so findings with
  any casing (e.g. "Pass") feed the stat buckets and the score bar
  fills correctly. Matches the .lower() pattern already used in
  render_finding and render_finding_md.
- main: wrap findings/template read_text calls; emit a one-line error
  to stderr and return 1 on FileNotFoundError or JSONDecodeError
  instead of dumping a raw traceback. Script is LLM-invoked, so a
  clean diagnostic is the contract.

Addresses augmentcode review comments 3235100013 and 3235100018.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 16:16:17 -05:00
3 changed files with 20 additions and 9 deletions

View File

@ -1,11 +1,11 @@
---
title: 'How to Expand BMad for Your Organization'
description: Five customization patterns that reshape BMad without forking — agent-wide rules, workflow conventions, external publishing, template swaps, and agent roster changes
description: Six customization patterns that reshape BMad without forking — agent-wide rules, workflow conventions, external publishing, template swaps, agent roster changes, and advanced integration patterns
sidebar:
order: 9
---
BMad's customization surface lets an organization reshape behavior without editing installed files or forking skills. This guide walks through five recipes that cover most enterprise needs.
BMad's customization surface lets an organization reshape behavior without editing installed files or forking skills. This guide walks through six recipes that cover most enterprise needs.
:::note[Prerequisites]
@ -299,7 +299,7 @@ The agent adapts to whatever structure the template defines. Keep templates unde
## Combining Recipes
All five recipes compose. A realistic enterprise override for `bmad-product-brief` might set `persistent_facts` (Recipe 2), `on_complete` (Recipe 3), and `brief_template` (Recipe 4) in one file. The agent-level rule (Recipe 1) lives in a separate file under the agent's name, central config (Recipe 5) pins the shared roster and team settings, and all four apply in parallel.
All six recipes compose. A realistic enterprise override for `bmad-product-brief` might set `persistent_facts` (Recipe 2), `on_complete` (Recipe 3), and `brief_template` (Recipe 4) in one file. The agent-level rule (Recipe 1) lives in a separate file under the agent's name, central config (Recipe 5) pins the shared roster and team settings, advanced integration patterns (Recipe 6) configure external sources and handoffs, and all layers apply in parallel.
```toml
# _bmad/custom/bmad-product-brief.toml (workflow-level)

View File

@ -46,7 +46,7 @@ Define what to build and for whom.
| Workflow | Purpose | Produces |
|-------------------------|-------------------------------------------------------------------------------------|---------------------------------------------------|
| `bmad-prd` | Create, update, or validate a PRD — facilitated discovery, three intents in one skill | `prd.md`, `addendum.md`, `decision-log.md` |
| `bmad-prd` | Create, update, or validate a PRD — facilitated discovery, three intents in one skill | Create/Update: `prd.md`, `addendum.md`, `decision-log.md`; Validate: `validation-report.html` + `.md` |
| `bmad-create-ux-design` | Design user experience (when UX matters) | `ux-spec.md` |
:::tip[Three intents in one skill]

View File

@ -46,7 +46,7 @@ def compute_stats(findings: list[dict]) -> dict:
failed_critical = 0
failed_high = 0
for f in findings:
status = f.get("status", "n/a")
status = (f.get("status") or "n/a").lower()
if status in by_status:
by_status[status] += 1
if status == "fail":
@ -219,8 +219,19 @@ def main(argv: list[str]) -> int:
template_path = Path(args.template)
output_path = Path(args.output)
data = json.loads(findings_path.read_text())
template = template_path.read_text()
try:
data = json.loads(findings_path.read_text(encoding="utf-8"))
except FileNotFoundError:
print(f"error: findings file not found: {findings_path}", file=sys.stderr)
return 1
except json.JSONDecodeError as e:
print(f"error: findings file is not valid JSON ({findings_path}): {e}", file=sys.stderr)
return 1
try:
template = template_path.read_text(encoding="utf-8")
except FileNotFoundError:
print(f"error: template file not found: {template_path}", file=sys.stderr)
return 1
findings = data.get("findings", []) or []
@ -257,10 +268,10 @@ def main(argv: list[str]) -> int:
}
rendered = string.Template(template).safe_substitute(substitutions)
output_path.write_text(rendered)
output_path.write_text(rendered, encoding="utf-8")
md_path = output_path.with_suffix(".md")
md_path.write_text(render_markdown_report(data, findings, stats, grade))
md_path.write_text(render_markdown_report(data, findings, stats, grade), encoding="utf-8")
print(json.dumps({
"output": str(output_path),