From 6a5b8148813a24fdbe03d193f4be7d0a256bc740 Mon Sep 17 00:00:00 2001 From: Brian Madison Date: Sat, 18 Apr 2026 20:14:58 -0500 Subject: [PATCH] refactor(skills): use PEP 723 inline deps + uv run for resolver BMB standard and Anthropic's Agent Skills spec both reference the PEP 723 + uv pattern: declare dependencies in an inline script header, invoke via `uv run` so deps auto-install into a cached isolated environment on first run. - resolve_customization.py: add PEP 723 header declaring pyyaml>=6.0 and requires-python>=3.10. - Remove src/scripts/requirements.txt (superseded by inline metadata). - Update 6 agent SKILL.md files to invoke `uv run` instead of `python3`. - Update docs/how-to/customize-bmad.md to explain the uv requirement and the PEP 723 pattern, with a plain-python3 fallback note. - Refresh the script's ImportError message to point at uv run first. --- docs/how-to/customize-bmad.md | 14 ++++++++----- .../1-analysis/bmad-agent-analyst/SKILL.md | 2 +- .../bmad-agent-tech-writer/SKILL.md | 2 +- .../2-plan-workflows/bmad-agent-pm/SKILL.md | 2 +- .../bmad-agent-ux-designer/SKILL.md | 2 +- .../bmad-agent-architect/SKILL.md | 2 +- .../4-implementation/bmad-agent-dev/SKILL.md | 2 +- src/scripts/requirements.txt | 1 - src/scripts/resolve_customization.py | 20 ++++++++++++------- 9 files changed, 28 insertions(+), 19 deletions(-) delete mode 100644 src/scripts/requirements.txt diff --git a/docs/how-to/customize-bmad.md b/docs/how-to/customize-bmad.md index 2a345a7f3..3a13ce612 100644 --- a/docs/how-to/customize-bmad.md +++ b/docs/how-to/customize-bmad.md @@ -183,31 +183,35 @@ agent: ## How Resolution Works -On activation, the agent's SKILL.md runs a shared Python script that does the three-layer merge and returns the resolved `agent` block as JSON. The script requires Python 3.8+ and PyYAML (`pip install PyYAML`). +On activation, the agent's SKILL.md runs a shared Python script that does the three-layer merge and returns the resolved `agent` block as JSON. The script uses [PEP 723 inline script metadata](https://peps.python.org/pep-0723/) to declare its dependency on PyYAML, and is designed to be invoked via [`uv`](https://docs.astral.sh/uv/): ```bash -python3 {project-root}/_bmad/scripts/resolve_customization.py \ +uv run {project-root}/_bmad/scripts/resolve_customization.py \ --skill {skill-root} \ --key agent ``` +`uv run` reads the inline metadata, creates a cached isolated environment with PyYAML installed, and runs the script. First run takes a few seconds while the env is built; subsequent runs reuse the cache and are instant. + +**Requirements**: Python 3.10+ and `uv` (install via `brew install uv`, `pip install uv`, or [the official installer](https://docs.astral.sh/uv/getting-started/installation/)). If `uv` isn't available, the script can be run with plain `python3` provided PyYAML is already installed (`pip install PyYAML`). + `--skill` points at the skill's installed directory (where `customize.yaml` lives). The skill name is derived from the directory's basename, and the script looks up `_bmad/custom/{skill-name}.yaml` and `{skill-name}.user.yaml` automatically. Useful invocations: ```bash # Resolve the full agent block -python3 {project-root}/_bmad/scripts/resolve_customization.py \ +uv run {project-root}/_bmad/scripts/resolve_customization.py \ --skill /abs/path/to/bmad-agent-pm \ --key agent # Resolve a single field -python3 {project-root}/_bmad/scripts/resolve_customization.py \ +uv run {project-root}/_bmad/scripts/resolve_customization.py \ --skill /abs/path/to/bmad-agent-pm \ --key agent.metadata.name # Full dump (everything under agent plus any other top-level keys) -python3 {project-root}/_bmad/scripts/resolve_customization.py \ +uv run {project-root}/_bmad/scripts/resolve_customization.py \ --skill /abs/path/to/bmad-agent-pm ``` diff --git a/src/bmm-skills/1-analysis/bmad-agent-analyst/SKILL.md b/src/bmm-skills/1-analysis/bmad-agent-analyst/SKILL.md index fd2b059ac..a4ab5eaf4 100644 --- a/src/bmm-skills/1-analysis/bmad-agent-analyst/SKILL.md +++ b/src/bmm-skills/1-analysis/bmad-agent-analyst/SKILL.md @@ -13,7 +13,7 @@ description: Strategic business analyst and requirements expert. Use when the us ### Step 1: Resolve the Agent Block -Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent` +Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent` **If the script fails**, resolve the `agent` block yourself from `customize.yaml`, with `{project-root}/_bmad/custom/{skill-name}.yaml` overriding, and `{skill-name}.user.yaml` overriding both (any missing file is skipped). diff --git a/src/bmm-skills/1-analysis/bmad-agent-tech-writer/SKILL.md b/src/bmm-skills/1-analysis/bmad-agent-tech-writer/SKILL.md index eab98667a..db0be73c2 100644 --- a/src/bmm-skills/1-analysis/bmad-agent-tech-writer/SKILL.md +++ b/src/bmm-skills/1-analysis/bmad-agent-tech-writer/SKILL.md @@ -13,7 +13,7 @@ description: Technical documentation specialist and knowledge curator. Use when ### Step 1: Resolve the Agent Block -Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent` +Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent` **If the script fails**, resolve the `agent` block yourself from `customize.yaml`, with `{project-root}/_bmad/custom/{skill-name}.yaml` overriding, and `{skill-name}.user.yaml` overriding both (any missing file is skipped). diff --git a/src/bmm-skills/2-plan-workflows/bmad-agent-pm/SKILL.md b/src/bmm-skills/2-plan-workflows/bmad-agent-pm/SKILL.md index 23bd5368b..0092bf3bc 100644 --- a/src/bmm-skills/2-plan-workflows/bmad-agent-pm/SKILL.md +++ b/src/bmm-skills/2-plan-workflows/bmad-agent-pm/SKILL.md @@ -13,7 +13,7 @@ description: Product manager for PRD creation and requirements discovery. Use wh ### Step 1: Resolve the Agent Block -Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent` +Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent` **If the script fails**, resolve the `agent` block yourself from `customize.yaml`, with `{project-root}/_bmad/custom/{skill-name}.yaml` overriding, and `{skill-name}.user.yaml` overriding both (any missing file is skipped). diff --git a/src/bmm-skills/2-plan-workflows/bmad-agent-ux-designer/SKILL.md b/src/bmm-skills/2-plan-workflows/bmad-agent-ux-designer/SKILL.md index 8a68b763e..e77b7a05c 100644 --- a/src/bmm-skills/2-plan-workflows/bmad-agent-ux-designer/SKILL.md +++ b/src/bmm-skills/2-plan-workflows/bmad-agent-ux-designer/SKILL.md @@ -13,7 +13,7 @@ description: UX designer and UI specialist. Use when the user asks to talk to Sa ### Step 1: Resolve the Agent Block -Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent` +Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent` **If the script fails**, resolve the `agent` block yourself from `customize.yaml`, with `{project-root}/_bmad/custom/{skill-name}.yaml` overriding, and `{skill-name}.user.yaml` overriding both (any missing file is skipped). diff --git a/src/bmm-skills/3-solutioning/bmad-agent-architect/SKILL.md b/src/bmm-skills/3-solutioning/bmad-agent-architect/SKILL.md index 147308cbb..452261f3f 100644 --- a/src/bmm-skills/3-solutioning/bmad-agent-architect/SKILL.md +++ b/src/bmm-skills/3-solutioning/bmad-agent-architect/SKILL.md @@ -13,7 +13,7 @@ description: System architect and technical design leader. Use when the user ask ### Step 1: Resolve the Agent Block -Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent` +Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent` **If the script fails**, resolve the `agent` block yourself from `customize.yaml`, with `{project-root}/_bmad/custom/{skill-name}.yaml` overriding, and `{skill-name}.user.yaml` overriding both (any missing file is skipped). diff --git a/src/bmm-skills/4-implementation/bmad-agent-dev/SKILL.md b/src/bmm-skills/4-implementation/bmad-agent-dev/SKILL.md index 8b535b4a6..a4e7373f3 100644 --- a/src/bmm-skills/4-implementation/bmad-agent-dev/SKILL.md +++ b/src/bmm-skills/4-implementation/bmad-agent-dev/SKILL.md @@ -13,7 +13,7 @@ description: Senior software engineer for story execution and code implementatio ### Step 1: Resolve the Agent Block -Run: `python3 {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent` +Run: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key agent` **If the script fails**, resolve the `agent` block yourself from `customize.yaml`, with `{project-root}/_bmad/custom/{skill-name}.yaml` overriding, and `{skill-name}.user.yaml` overriding both (any missing file is skipped). diff --git a/src/scripts/requirements.txt b/src/scripts/requirements.txt deleted file mode 100644 index c1a201db2..000000000 --- a/src/scripts/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -PyYAML>=6.0 diff --git a/src/scripts/resolve_customization.py b/src/scripts/resolve_customization.py index 13e961338..91309762e 100644 --- a/src/scripts/resolve_customization.py +++ b/src/scripts/resolve_customization.py @@ -1,4 +1,8 @@ #!/usr/bin/env python3 +# /// script +# requires-python = ">=3.10" +# dependencies = ["pyyaml>=6.0"] +# /// """ Resolve customization for a BMad skill using three-layer YAML merge. @@ -11,10 +15,12 @@ Skill name is derived from the basename of the skill directory. Outputs merged JSON to stdout. Errors go to stderr. -Usage: - python3 resolve_customization.py --skill /abs/path/to/skill-dir - python3 resolve_customization.py --skill ... --key agent - python3 resolve_customization.py --skill ... --key agent --key agent.menu +Dependencies declared inline via PEP 723. Invoke with `uv run` to +auto-install PyYAML into an isolated, cached environment: + + uv run resolve_customization.py --skill /abs/path/to/skill-dir + uv run resolve_customization.py --skill ... --key agent + uv run resolve_customization.py --skill ... --key agent --key agent.menu Merge rules (matches BMad v6.1 semantics where applicable): - metadata: shallow merge (scalar fields override) @@ -25,8 +31,6 @@ Merge rules (matches BMad v6.1 semantics where applicable): - other tables: deep merge - other arrays: atomic replace - scalars: override wins - -Requires PyYAML. Install with: pip install PyYAML """ import argparse @@ -39,7 +43,9 @@ try: except ImportError: sys.stderr.write( "error: PyYAML is required to run this script.\n" - "Install it with: pip install PyYAML\n" + "Invoke via `uv run resolve_customization.py ...` so dependencies\n" + "declared in the PEP 723 header are auto-installed, or run\n" + "`pip install PyYAML` if invoking with plain `python3`.\n" ) sys.exit(3)