Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"name": "bmad-builder",
"source": "./",
"description": "Build AI agents, workflows, and modules from a conversation. Four skills — Agent Builder, Workflow Builder, Module Builder, and Setup — guide you from idea to production-ready skill structure with built-in quality optimization. Part of the BMad Method ecosystem.",
"version": "2.1.0",
"version": "2.2.0",
"author": {
"name": "Brian (BMad) Madison"
},
Expand All @@ -22,7 +22,7 @@
"name": "sample-plugins",
"source": "./",
"description": "Sample plugins demonstrating how to build BMad agents and skills. Includes a code coach, creative muse, diagram reviewer, dream weaver, sentinel, and excalidraw generator.",
"version": "2.1.0",
"version": "2.2.0",
"author": {
"name": "Brian (BMad) Madison"
},
Expand All @@ -40,7 +40,7 @@
"name": "bmad-dream-weaver-agent",
"source": "./",
"description": "Dream journaling and interpretation agent with lucid dreaming coaching, pattern discovery, symbol analysis, and recall training.",
"version": "2.1.0",
"version": "2.2.0",
"author": {
"name": "Brian (BMad) Madison"
},
Expand Down
208 changes: 114 additions & 94 deletions CHANGELOG.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![Version](https://img.shields.io/npm/v/bmad-builder?color=blue&label=version)](https://www.npmjs.com/package/bmad-builder)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Python Version](https://img.shields.io/badge/python-%3E%3D3.10-blue?logo=python&logoColor=white)](https://www.python.org)
[![Python Version](https://img.shields.io/badge/python-%3E%3D3.11-blue?logo=python&logoColor=white)](https://www.python.org)
[![uv](https://img.shields.io/badge/uv-package%20manager-blueviolet?logo=uv)](https://docs.astral.sh/uv/)
[![Discord](https://img.shields.io/badge/Discord-Join%20Community-7289da?logo=discord&logoColor=white)](https://discord.gg/gk8jAdXWmj)

Expand Down
2 changes: 1 addition & 1 deletion docs/how-to/install-docker-for-evals.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ The Dockerfile contains no tokens, API keys, or credentials. Your authentication

## Tips

- Rebuild the image with `python3 scripts/docker_setup.py --rebuild` if you ever need to reset it
- Rebuild the image with `uv run scripts/docker_setup.py --rebuild` if you ever need to reset it
- Per-eval container resource use is small (a few hundred MB). Parallel workers each spin up their own container.
- If `docker info` works in one terminal but not in your editor's integrated terminal, your shell PATH probably differs. Open a fresh terminal session.

Expand Down
2 changes: 1 addition & 1 deletion docs/how-to/make-a-skill-customizable.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ EOF
Run the resolver directly to confirm your override takes effect:

```bash
python3 _bmad/scripts/resolve_customization.py \
uv run _bmad/scripts/resolve_customization.py \
--skill /path/to/built/skill \
--key workflow.on_complete
```
Expand Down
6 changes: 3 additions & 3 deletions samples/bmad-agent-code-coach/scripts/init-sanctum.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
not depend on the skill bundle location for normal operation.

Usage:
python3 init-sanctum.py <project-root> <skill-path>
uv run init-sanctum.py <project-root> <skill-path>

project-root: The root of the project (where _bmad/ lives)
skill-path: Path to the skill directory (where SKILL.md, references/, assets/ live)

Example:
python3 scripts/init-sanctum.py /Users/me/myproject /path/to/bmad-agent-code-coach
uv run scripts/init-sanctum.py /Users/me/myproject /path/to/bmad-agent-code-coach
"""

import sys
Expand Down Expand Up @@ -192,7 +192,7 @@ def substitute_vars(content: str, variables: dict) -> str:

def main():
if len(sys.argv) < 3:
print("Usage: python3 init-sanctum.py <project-root> <skill-path>")
print("Usage: uv run init-sanctum.py <project-root> <skill-path>")
sys.exit(1)

project_root = Path(sys.argv[1]).resolve()
Expand Down
2 changes: 1 addition & 1 deletion samples/bmad-agent-code-coach/scripts/wake.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
This loads runtime memory only. It never reads or writes config or customize.toml.

Usage:
python3 wake.py <project-root> [--pulse]
uv run wake.py <project-root> [--pulse]

project-root: The root of the project (where _bmad/ lives)
"""
Expand Down
6 changes: 3 additions & 3 deletions samples/bmad-agent-creative-muse/scripts/init-sanctum.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
not depend on the skill bundle location for normal operation.

Usage:
python3 init-sanctum.py <project-root> <skill-path>
uv run init-sanctum.py <project-root> <skill-path>

project-root: The root of the project (where _bmad/ lives)
skill-path: Path to the skill directory (where SKILL.md, references/, assets/ live)

Example:
python3 scripts/init-sanctum.py /Users/me/myproject /path/to/bmad-agent-creative-muse
uv run scripts/init-sanctum.py /Users/me/myproject /path/to/bmad-agent-creative-muse
"""

import sys
Expand Down Expand Up @@ -178,7 +178,7 @@ def substitute_vars(content: str, variables: dict) -> str:

def main():
if len(sys.argv) < 3:
print("Usage: python3 init-sanctum.py <project-root> <skill-path>")
print("Usage: uv run init-sanctum.py <project-root> <skill-path>")
sys.exit(1)

project_root = Path(sys.argv[1]).resolve()
Expand Down
2 changes: 1 addition & 1 deletion samples/bmad-agent-creative-muse/scripts/wake.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
This loads runtime memory only. It never reads or writes config or customize.toml.

Usage:
python3 wake.py <project-root> [--pulse]
uv run wake.py <project-root> [--pulse]

project-root: The root of the project (where _bmad/ lives)
"""
Expand Down
4 changes: 2 additions & 2 deletions samples/bmad-agent-dream-weaver/assets/module-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ Write a temp JSON file with the collected answers structured as `{"core": {...},
In the commands below, replace `{project-root}` in every path argument with the actual project root (e.g. `/home/me/myapp`) before running — these are filesystem paths, not config values.

```bash
python3 ./scripts/merge-config.py --config-path "{project-root}/_bmad/config.yaml" --user-config-path "{project-root}/_bmad/config.user.yaml" --module-yaml ./assets/module.yaml --answers {temp-file}
python3 ./scripts/merge-help-csv.py --target "{project-root}/_bmad/module-help.csv" --source ./assets/module-help.csv --module-code {module-code}
uv run ./scripts/merge-config.py --config-path "{project-root}/_bmad/config.yaml" --user-config-path "{project-root}/_bmad/config.user.yaml" --module-yaml ./assets/module.yaml --answers {temp-file}
uv run ./scripts/merge-help-csv.py --target "{project-root}/_bmad/module-help.csv" --source ./assets/module-help.csv --module-code {module-code}
```

Both scripts output JSON to stdout with results. If either exits non-zero, surface the error and stop.
Expand Down
6 changes: 3 additions & 3 deletions samples/bmad-agent-sentinel/scripts/init-sanctum.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
not depend on the skill bundle location for normal operation.

Usage:
python3 init-sanctum.py <project-root> <skill-path>
uv run init-sanctum.py <project-root> <skill-path>

project-root: The root of the project (where _bmad/ lives)
skill-path: Path to the skill directory (where SKILL.md, references/, assets/ live)

Example:
python3 scripts/init-sanctum.py /Users/me/myproject /path/to/bmad-agent-sentinel
uv run scripts/init-sanctum.py /Users/me/myproject /path/to/bmad-agent-sentinel
"""

import sys
Expand Down Expand Up @@ -189,7 +189,7 @@ def substitute_vars(content: str, variables: dict) -> str:

def main():
if len(sys.argv) < 3:
print("Usage: python3 init-sanctum.py <project-root> <skill-path>")
print("Usage: uv run init-sanctum.py <project-root> <skill-path>")
sys.exit(1)

project_root = Path(sys.argv[1]).resolve()
Expand Down
2 changes: 1 addition & 1 deletion samples/bmad-agent-sentinel/scripts/wake.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
This loads runtime memory only. It never reads or writes config or customize.toml.

Usage:
python3 wake.py <project-root> [--pulse]
uv run wake.py <project-root> [--pulse]

project-root: The root of the project (where _bmad/ lives)
"""
Expand Down
6 changes: 3 additions & 3 deletions samples/bmad-excalidraw/references/diagram-generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ The specification format:
Run the generation script:

```bash
python3 ../scripts/generate_excalidraw.py --spec '<json-spec>' --output '{output_folder}/diagrams/{filename}.excalidraw'
uv run ../scripts/generate_excalidraw.py --spec '<json-spec>' --output '{output_folder}/diagrams/{filename}.excalidraw'
```

Or pipe the spec via stdin:

```bash
echo '<json-spec>' | python3 ../scripts/generate_excalidraw.py --output '{output_folder}/diagrams/{filename}.excalidraw'
echo '<json-spec>' | uv run ../scripts/generate_excalidraw.py --output '{output_folder}/diagrams/{filename}.excalidraw'
```

The script handles:
Expand All @@ -72,7 +72,7 @@ The script handles:
Run validation:

```bash
python3 ../scripts/validate_excalidraw.py '{output_folder}/diagrams/{filename}.excalidraw'
uv run ../scripts/validate_excalidraw.py '{output_folder}/diagrams/{filename}.excalidraw'
```

Fix any critical issues before delivering.
Expand Down
6 changes: 3 additions & 3 deletions samples/bmad-excalidraw/scripts/generate_excalidraw.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
with auto-layout positioning.

Usage:
python generate_excalidraw.py --spec '{"title":"My Diagram",...}' --output diagram.excalidraw
echo '{"title":"My Diagram",...}' | python generate_excalidraw.py --output diagram.excalidraw
python generate_excalidraw.py --spec-file spec.json --output diagram.excalidraw
uv run generate_excalidraw.py --spec '{"title":"My Diagram",...}' --output diagram.excalidraw
echo '{"title":"My Diagram",...}' | uv run generate_excalidraw.py --output diagram.excalidraw
uv run generate_excalidraw.py --spec-file spec.json --output diagram.excalidraw

Spec format:
{
Expand Down
4 changes: 2 additions & 2 deletions samples/bmad-excalidraw/scripts/validate_excalidraw.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
Validates .excalidraw files for structural correctness.

Usage:
python validate_excalidraw.py path/to/diagram.excalidraw
python validate_excalidraw.py path/to/diagram.excalidraw -o report.json
uv run validate_excalidraw.py path/to/diagram.excalidraw
uv run validate_excalidraw.py path/to/diagram.excalidraw -o report.json

Exit codes: 0=pass, 1=fail, 2=error
"""
Expand Down
6 changes: 3 additions & 3 deletions samples/sample-module-setup/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ Write a temp JSON file with the collected answers structured as `{"core": {...},
In the commands below, replace `{project-root}` in every path argument with the actual project root (e.g. `/home/me/myapp`) before running — these are filesystem paths, not config values.

```bash
python3 ./scripts/merge-config.py --config-path "{project-root}/_bmad/config.yaml" --user-config-path "{project-root}/_bmad/config.user.yaml" --module-yaml ./assets/module.yaml --answers {temp-file} --legacy-dir "{project-root}/_bmad"
python3 ./scripts/merge-help-csv.py --target "{project-root}/_bmad/module-help.csv" --source ./assets/module-help.csv --legacy-dir "{project-root}/_bmad" --module-code sam
uv run ./scripts/merge-config.py --config-path "{project-root}/_bmad/config.yaml" --user-config-path "{project-root}/_bmad/config.user.yaml" --module-yaml ./assets/module.yaml --answers {temp-file} --legacy-dir "{project-root}/_bmad"
uv run ./scripts/merge-help-csv.py --target "{project-root}/_bmad/module-help.csv" --source ./assets/module-help.csv --legacy-dir "{project-root}/_bmad" --module-code sam
```

Both scripts output JSON to stdout with results. If either exits non-zero, surface the error and stop. The scripts automatically read legacy config values as fallback defaults, then delete the legacy files after a successful merge. Check `legacy_configs_deleted` and `legacy_csvs_deleted` in the output to confirm cleanup.
Expand All @@ -64,7 +64,7 @@ After both merge scripts complete successfully, remove the installer's package d
As with the merge scripts, replace `{project-root}` in the `--bmad-dir` and `--skills-dir` path arguments with the actual project root before running.

```bash
python3 ./scripts/cleanup-legacy.py --bmad-dir "{project-root}/_bmad" --module-code sam --also-remove _config --skills-dir "{project-root}/.claude/skills"
uv run ./scripts/cleanup-legacy.py --bmad-dir "{project-root}/_bmad" --module-code sam --also-remove _config --skills-dir "{project-root}/.claude/skills"
```

The script verifies that every skill in the legacy directories exists at `.claude/skills/` before removing anything. Directories without skills (like `_config/`) are removed directly. If the script exits non-zero, surface the error and stop. Missing directories (already cleaned by a prior run) are not errors — the script is idempotent.
Expand Down
6 changes: 3 additions & 3 deletions skills/bmad-bmb-setup/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ Write a temp JSON file with the collected answers structured as `{"core": {...},
In the commands below, replace `{project-root}` in every path argument with the actual project root (e.g. `/home/me/myapp`) before running — these are filesystem paths, not config values. Leave `{temp-file}` and `bmb` as-is.

```bash
python3 ./scripts/merge-config.py --config-path "{project-root}/_bmad/config.yaml" --user-config-path "{project-root}/_bmad/config.user.yaml" --module-yaml ./assets/module.yaml --answers {temp-file} --legacy-dir "{project-root}/_bmad"
python3 ./scripts/merge-help-csv.py --target "{project-root}/_bmad/module-help.csv" --source ./assets/module-help.csv --legacy-dir "{project-root}/_bmad" --module-code bmb
uv run ./scripts/merge-config.py --config-path "{project-root}/_bmad/config.yaml" --user-config-path "{project-root}/_bmad/config.user.yaml" --module-yaml ./assets/module.yaml --answers {temp-file} --legacy-dir "{project-root}/_bmad"
uv run ./scripts/merge-help-csv.py --target "{project-root}/_bmad/module-help.csv" --source ./assets/module-help.csv --legacy-dir "{project-root}/_bmad" --module-code bmb
```

Both scripts output JSON to stdout with results. If either exits non-zero, surface the error and stop. The scripts automatically read legacy config values as fallback defaults, then delete the legacy files after a successful merge. Check `legacy_configs_deleted` and `legacy_csvs_deleted` in the output to confirm cleanup.
Expand All @@ -64,7 +64,7 @@ After both merge scripts complete successfully, remove the installer's package d
As with the merge scripts, replace `{project-root}` in the `--bmad-dir` and `--skills-dir` path arguments with the actual project root before running.

```bash
python3 ./scripts/cleanup-legacy.py --bmad-dir "{project-root}/_bmad" --module-code bmb --also-remove _config --skills-dir "{project-root}/.claude/skills"
uv run ./scripts/cleanup-legacy.py --bmad-dir "{project-root}/_bmad" --module-code bmb --also-remove _config --skills-dir "{project-root}/.claude/skills"
```

The script verifies that every skill in the legacy directories exists at `.claude/skills/` before removing anything. Directories without skills (like `_config/`) are removed directly. If the script exits non-zero, surface the error and stop. Missing directories (already cleaned by a prior run) are not errors — the script is idempotent.
Expand Down
6 changes: 3 additions & 3 deletions skills/bmad-eval-runner/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Each case runs in a clean working directory with the skill under test staged int
For baseline, variant, and quality modes:

```
python3 {skill-root}/scripts/run_evals.py \
uv run {skill-root}/scripts/run_evals.py \
--cases <cases-file> --skill-path <skill> --output-dir <dir> \
--mode quality|baseline|variant [--variant-path <skill>] \
[--adapter <adapter.json>] [--runs N]
Expand All @@ -71,7 +71,7 @@ The script stages the skill and any case fixtures, applies any `state_prefix` to
For trigger mode:

```
python3 {skill-root}/scripts/run_triggers.py \
uv run {skill-root}/scripts/run_triggers.py \
--skill-path <skill> --queries <queries-file> --output-dir <dir> \
[--adapter <adapter.json>] [--runs-per-query N]
```
Expand All @@ -80,7 +80,7 @@ It stages a synthetic skill where the runtime discovers skills, sends each query

For quality mode, spawn the grader described in `references/grader.md` per case, passing the case's rubric, transcript path, artifacts dir (the case's `cwd/`), and a `grading_path` of `<case-folder>/grading.json`. The grader writes that file, gives no partial credit, and flags weak or non-discriminating assertions; relay that feedback. If a grader subagent errors, mark that case `grading_error` — never substitute a default verdict.

When `--runs` is greater than one, call `python3 {skill-root}/scripts/aggregate_benchmark.py --baseline <run-dir>/<config-a> --variant <run-dir>/<config-b>` to produce the mean, sample standard deviation, min, max, and the delta between configs (`--runs <run-dir>/<config>` for a single config's spread).
When `--runs` is greater than one, call `uv run {skill-root}/scripts/aggregate_benchmark.py --baseline <run-dir>/<config-a> --variant <run-dir>/<config-b>` to produce the mean, sample standard deviation, min, max, and the delta between configs (`--runs <run-dir>/<config>` for a single config's spread).

When a run fails or comes back weak and the user wants the skill improved from the results, follow `references/self-improvement.md`.

Expand Down
8 changes: 4 additions & 4 deletions skills/bmad-eval-runner/scripts/aggregate_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@

Usage:
Summarize one config across its runs:
python3 aggregate_benchmark.py --runs CONFIG_A.json
python3 aggregate_benchmark.py --runs RUN_DIR/ (reads timing.json files)
uv run aggregate_benchmark.py --runs CONFIG_A.json
uv run aggregate_benchmark.py --runs RUN_DIR/ (reads timing.json files)

Compare two configs (each summarized, then delta = B - A):
python3 aggregate_benchmark.py --baseline A.json --variant B.json
uv run aggregate_benchmark.py --baseline A.json --variant B.json

Self-test on a known fixture (no external input needed):
python3 aggregate_benchmark.py --self-test
uv run aggregate_benchmark.py --self-test

Output is one JSON object on stdout.
"""
Expand Down
2 changes: 1 addition & 1 deletion skills/bmad-eval-runner/scripts/run_evals.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
recorded so the grader sees exactly what ran.

Usage:
python3 run_evals.py \\
uv run run_evals.py \\
--cases CASES.json \\
--skill-path SKILL_DIR \\
--output-dir DIR \\
Expand Down
2 changes: 1 addition & 1 deletion skills/bmad-eval-runner/scripts/run_triggers.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
and records "skipped: no runtime adapter configured" rather than crashing.

Usage:
python3 run_triggers.py \\
uv run run_triggers.py \\
--skill-path SKILL_DIR \\
--queries QUERIES.json \\
--output-dir DIR \\
Expand Down
4 changes: 2 additions & 2 deletions skills/bmad-eval-runner/scripts/tests/test_env_isolation.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
deliberately self-contained); this test pins the contract on both copies:
exactly PATH + fresh HOME + CLAUDE_CONFIG_DIR + auth-var-only-when-set +
declared passthrough keys, nothing else.
Run with: python3 -m pytest test_env_isolation.py
(or plain `python3 test_env_isolation.py` for a lightweight self-check).
Run with: uv run --with pytest -m pytest test_env_isolation.py
(or plain `uv run test_env_isolation.py` for a lightweight self-check).
"""
import sys
from pathlib import Path
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
rate. These tests pin the rule: only tool_use events (a Skill call naming the
synthetic skill, or a Read inside its directory) count as a load, and
substring-style load signals are rejected outright.
Run with: python3 -m pytest test_trigger_detection.py
(or plain `python3 test_trigger_detection.py` for a lightweight self-check).
Run with: uv run --with pytest -m pytest test_trigger_detection.py
(or plain `uv run test_trigger_detection.py` for a lightweight self-check).
"""
import json
import sys
Expand Down
Loading
Loading