Commit Graph

10 Commits

Author SHA1 Message Date
Alex Verkhovsky 7701cbea62 feat(quick-dev): render templates via stdlib Python at skill entry
Move compile-time variable substitution out of the LLM and into a
deterministic Python step. SKILL.md becomes a two-line stdout-dispatch
shim that runs render.py and follows the instruction it prints. The
renderer reads BMad configuration from the central four-layer TOML
surface introduced in #2285 (_bmad/config.toml plus config.user.toml
and the two _bmad/custom/ overrides), with a fallback to the legacy
per-module _bmad/bmm/config.yaml for pre-#2285 installs.

Compile-time refs ({{.var}}) get substituted at render time. LLM-runtime
refs ({var}) pass through untouched.

Renderer (render.py)
- Python 3 stdlib only (tomllib, already bundled since 3.11). UTF-8 I/O.
  Every invocation rebuilds from scratch — no hash, no cache.
- find_project_root walks up from cwd; HALT to stdout if no _bmad/
  is found anywhere on the path.
- load_central_config deep-merges the four TOML layers in priority
  order (base-team → base-user → custom-team → custom-user) so user
  overrides in _bmad/custom/config.user.toml win over installer-
  regenerated base values. flatten_central_config lifts scalar keys
  from [core] and [modules.bmm] into the renderer's flat namespace;
  module keys beat core on collision (matches the installer's own
  core-key-stripping behavior).
- When _bmad/config.toml is absent, falls through to the legacy
  flat-YAML parser for _bmad/bmm/config.yaml — the renderer keeps
  working across the #2285 transition.
- {{.var}} substitution; unresolved refs emit empty string (Go
  missingkey=zero semantics).
- Smart defaults for planning_artifacts / implementation_artifacts /
  communication_language applied after config load. Derives
  sprint_status / deferred_work_file from implementation_artifacts.
  {{.main_config}} points at whichever surface was actually read.
- Renders every .md in the skill dir except SKILL.md to
  {project-root}/_bmad/render/bmad-quick-dev/.
- On success, stderr summary plus a single stdout line:
  "read and follow {workflow_md}". On failure, stdout HALT directive —
  per the Anthropic skills spec, script stdout is the defined agent-
  communication channel.

Skill entry (SKILL.md)
- Two-line shim: run python render.py, follow stdout. No template
  tokens in SKILL.md itself.

Template conversions
- workflow.md, step-01..05, step-oneshot, sync-sprint-status: convert
  every compile-time {var} reference to {{.var}}. Runtime refs
  preserved.
- spec-template.md untouched (single-curly comment hint stays as
  documentation).

Skill-prose cleanups bundled in
- Remove dead step-file frontmatter: empty-string variable declarations
  (spec_file, story_key, diff_output, review_mode) in quick-dev step-01
  and code-review step-01; empty --- --- blocks in step-03 and step-05;
  the specLoopIteration counter init moved from step-04 frontmatter into
  the step body where first-entry vs loopback semantics are explicit.
- Unify the language rule across all six quick-dev step files plus
  workflow.md.

Tooling
- tools/validate-skills.js: add TPL-01 rule. Files whose name contains
  "template" must not contain compile-time {{.var}} substitutions.
  Template files seed durable, version-controlled artifacts that
  execute on other machines; baking a value at render time would
  freeze a machine-local path into every downstream artifact.
- tools/validate-file-refs.js: add render/ to INSTALL_ONLY_PATHS so
  the validator recognizes the runtime-generated buffer.
- tools/skill-validator.md: document TPL-01; deterministic rule count
  bumped from 14 to 15.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 09:15:16 -07:00
Brian 0dbfae675b
feat(skills): TOML-based agent and workflow customization (#2284)
* feat(skills): TOML-based agent customization with stdlib Python resolver

Re-applies PR #2282's three-layer customization model (skill defaults →
team → user) but swaps YAML for TOML and uv for stdlib tomllib. Users
no longer need uv, pip, or a virtualenv — plain python3 (3.11+) is
sufficient, since tomllib shipped in the standard library.

## Schema changes vs PR #2282

- Flat agent schema: fields live directly under [agent], no nested
  metadata/persona sub-tables. Easier to author, less indentation.
- Non-configurable identity: name and title are declared in
  customize.toml as source-of-truth metadata (for future skill-manifest
  generation) but SKILL.md ignores overrides there — identity is
  hardcoded to preserve brand recognition.
- role redefined: now describes what the skill does for the user
  within its module phase, not a restatement of the title.
- persistent_facts replaces the activation-time file-context load AND
  the old memories concept. Entries can be literal sentences or
  file: prefixed paths/globs; avoids collision with the upcoming
  runtime memory sidecar.
- activation_steps_prepend / activation_steps_append harmonized across
  agents and workflows (replaces agent-specific critical_actions).
- [workflow] namespace mirrors [agent] for workflow customization.
  Same four structural rules, same field vocabulary.

## Resolver (src/scripts/resolve_customization.py)

Four purely structural merge rules, zero field-name hardcoding:

  - Scalars: override wins
  - Tables: deep merge
  - Arrays of tables where every item has `code` or `id`: merge by
    that key (matching keys replace, new keys append)
  - Any other array: append

No removal mechanism — overrides cannot delete base items. Fork the
skill or override by code with a no-op value to suppress defaults.

## Agents ported (6)

All six BMad agents now ship customize.toml + rewritten SKILL.md:
analyst (Mary), tech-writer (Paige), pm (John), ux-designer (Sally),
architect (Winston), dev (Amelia). Each uses the same 8-step
activation template: resolve → execute prepend → adopt persona →
load persistent facts → load config → greet (with {agent.icon}) →
execute append → dispatch or present menu.

Step 8 supports fast-path invocation: "hey Mary, let's brainstorm"
dispatches the matching menu item directly after greeting, skipping
the menu render when intent is clear. Chat, clarifying questions,
and bmad-help remain available when nothing on the menu fits.

## Installer + tooling

- _bmad/scripts/ provisioned on install (copies src/scripts/)
- _bmad/custom/ seeded with .gitignore for *.user.toml on fresh install
- Non-module-dir filter extended to skip _memory, memory, docs,
  scripts, and custom when scanning for modules
- Dead _config/agents/ directory no longer created
- metadata.capabilities removed from agent-manifest.csv and schema
- eslint config extended to cover src/scripts/**
- validate-file-refs.js knows about custom/ as install-only

## Deferred for follow-up

- bmad-product-brief workflow port (the pilot that demonstrates
  [workflow] + on_complete)
- Translated docs (cs/fr/vi-vn/zh-cn) — regenerate from English

* feat(skills): port bmad-product-brief to TOML workflow customization

Completes the customization surface rollout by giving the product-brief
workflow the same override model as the six BMad agents, under the
[workflow] namespace instead of [agent].

## customize.toml

Mirrors the agent shape under [workflow] with:
- activation_steps_prepend / activation_steps_append (harmonized across
  agents and workflows — same field names, same append semantics)
- persistent_facts with the file: convention, seeded with
  file:{project-root}/**/project-context.md
- on_complete scalar (renamed from PR #2282's skill_end for clarity —
  reads cleaner as "what runs when the workflow completes")

## SKILL.md

7-step workflow activation:
  1. Resolve workflow block
  2. Execute prepend steps
  3. Load persistent facts (file: or literal)
  4. Load config
  5. Greet if not already
  6. Execute append steps
  7. Stage 1 — Understand Intent

python3 + stdlib tomllib invocation; no uv required.

## Prompt file changes

- Path normalization: ../agents/ → agents/, ../resources/ → resources/,
  bare foo.md → prompts/foo.md. All references now resolve from the
  skill root (matches the convention documented in SKILL.md).
- Paths: meta-line added to each of the 4 prompt files that reference
  other files, reinforcing "bare paths resolve from skill root" so the
  LLM doesn't lose the convention when operating two hops into a
  prompt chain.
- finalize.md terminal stage now calls the resolver for
  workflow.on_complete — non-empty values run as the final step.

## Validation

- Resolver output verified: 4 workflow fields returned cleanly.
- validate-file-refs.js: 254 files scanned, 139 refs checked, 0 broken.
- test:refs: passing.

* docs(skills): enterprise customization recipes + workflow template variable

Three independent improvements bundled because they share the same
surface (workflow/agent customization) and landed from the same design
discussion:

## Fallback sentence disambiguated (7 SKILL.md files)

The "if the script fails" fallback used to say `{project-root}/_bmad/
custom/{skill-name}.toml` for the team override and then just `{skill-
name}.user.toml` for the user override, leaving the user file's
location implicit. LLMs could reasonably guess skill root or project
root instead. Replaced with an unambiguous numbered list that spells
out the full path for every file in the merge chain.

## Product-brief: stage promotion + brief_template variable

- Promoted `## Stage 1: Understand Intent` from a nested step inside
  "On Activation" to a top-level section. The previous "Step 7: Stage
  1 — Understand Intent → Proceed to Stage 1 below" was mechanical
  numbering pretending to be a step. Activation now ends cleanly at
  Step 6; Stage 1 is a peer section.
- Added `brief_template` as a workflow-level scalar customization
  defaulting to `resources/brief-template.md`. Stage 4 reads
  `{workflow.brief_template}` instead of the hardcoded path, so orgs
  can point at their own template under `{project-root}/...` without
  forking the skill.

## New doc: docs/how-to/extend-bmad-for-your-org.md

Four worked recipes that together cover most enterprise scenarios:

1. Shape an agent across every workflow it dispatches (dev agent +
   Context7 MCP + Linear search — the highest-leverage pattern)
2. Enforce org conventions inside a specific workflow (product-brief
   + compliance-field persistent_facts)
3. Publish completed outputs to external systems (product-brief +
   Confluence + Jira via MCP, gated on user confirmation for Jira)
4. Swap in your own output template (product-brief + brief_template
   variable swap)

Opens with the two-layer mental model (agent spans workflows,
workflow is local) so readers pick the right granularity before
reading any recipe. Closes with a "Combining Recipes" section
showing all four composed. Cross-linked from customize-bmad.md.

## Validation

- Resolver: workflow.brief_template returns the default cleanly.
- validate-file-refs.js: 254 files scanned, 146 refs checked
  (+7 from this commit), 0 broken.

* docs(skills): encourage CLAUDE.md/AGENTS.md reinforcement of critical rules

Added a "Reinforce Global Rules in Your IDE's Session File" section to
extend-bmad-for-your-org.md. BMad customizations only load when a
skill activates, but IDE session files (CLAUDE.md, AGENTS.md, cursor
rules, copilot-instructions) load every turn — worth restating the
most critical rules there too so they survive ad-hoc chat outside a
BMad skill.

Includes a one-line example reinforcing the Recipe 1 Context7 rule,
plus a scope table that clarifies what each layer is for:
  - IDE session file: universal, every session, keep succinct
  - Agent customization: persona-specific, every dispatched workflow
  - Workflow customization: one workflow run

Emphasizes brevity — noise in the session file crowds out signal.

* docs(skills): add Named Agents explanation doc

New docs/explanation/named-agents.md walking through the three-legged
stool (skills + named agents + customization) with the "Hey Mary,
let's brainstorm" activation flow as the narrative thread.

Covers:
- Why named agents vs menu-driven or prompt-driven alternatives
- The 8-step activation flow and what each step contributes
- How customization scales the model beyond a single developer
- Cross-links to the how-to docs for implementation details

Sits alongside brainstorming.md, quick-dev.md, party-mode.md in the
explanation folder — feature narratives for users who want to
understand why BMad is designed the way it is, not just how to use it.

* docs(skills): clarify that keyed-merge requires a single identifier key per array

Review feedback (PR #2284) flagged that the merge-rules wording was
ambiguous: "every item has a `code` or `id` field" could reasonably
be read as "each item individually has at least one of the two",
allowing arrays to mix `code` and `id` across items.

The resolver has always required all items share the *same* identifier
key (all `code`, or all `id`). Mixed arrays fall through to append —
intentional, because mixing identifier keys within one array is a
schema smell and any guess about which key should merge creates a
worse trap than the append-fallback.

Clarified in three places:
- Merge-rules table in customize-bmad.md: "every item shares the
  **same** identifier field"
- `code`/`id` convention paragraph: "pick **one** convention ... and
  stick with it across the whole array"
- Resolver docstring and `_detect_keyed_merge_field` docstring:
  explicit note that mixed arrays fall through with rationale

No behavior change.

* docs(skills): address CodeRabbit review — fallback rules, OS claim, headless greeting

Three fixes from PR #2284 review feedback:

## 1. Fallback merge wording (7 SKILL.md files)

Every SKILL.md told the LLM to merge the three customization files
"in priority order (later wins)" when the resolver fails. That reads
as shallow last-write-wins — but the resolver does structural merge
(scalars override, tables deep-merge, code/id-keyed arrays merge by
key, other arrays append). Following the old wording manually would
have silently stripped base `principles`, `persistent_facts`, and
`menu` items whenever a team override was present.

Expanded the fallback sentence to restate the four structural rules
explicitly, matching the resolver's behavior.

Applied to all 6 agents + bmad-product-brief workflow.

## 2. Python 3.11 / OS shipping claim (customize-bmad.md)

The docs claimed "macOS 13+, Ubuntu 22.04+, Debian 12+, Fedora 37+
all ship 3.11 or newer." Inaccurate — Ubuntu 22.04 defaults `python3`
to 3.10.6 (3.11 is a separate package), and macOS doesn't really
ship Python by default anymore.

Replaced with honest guidance: check `python3 --version` and note
that macOS without Homebrew and Ubuntu 22.04 default to 3.10 or
earlier.

## 3. Autonomous mode greeting gate (bmad-product-brief)

Product-brief's activation-mode detection documents autonomous mode
as "produce complete brief without interaction" — but Step 5 greeted
unconditionally, adding conversational output before the headless
artifact. Gated the greeting on `{mode}` != `autonomous`.

## Dismissed (replied on thread)

- `.gitignore` migration from *.user.yaml to *.user.toml: YAML
  installer code was in reverted #2282, never released. No users
  affected. Same rationale as Augment's earlier thread.

Validated: 254 files, 146 refs, 0 broken. test:refs 7/7,
test:install 242/242.

* docs: rename Extend to Expand throughout customization docs
2026-04-19 19:30:29 -05:00
Brian e550df2474
Revert "feat(skills): YAML-based agent customization with Python resolver (#2282)" (#2283)
This reverts commit bd1c0053d5.
2026-04-19 11:09:21 -05:00
Brian bd1c0053d5
feat(skills): YAML-based agent customization with Python resolver (#2282)
Three-layer customization (skill defaults → team → user) for BMad agents    
  and any skill that opts in. Users edit `_bmad/custom/{skill-name}.yaml`
  (team, committed) or `{skill-name}.user.yaml` (personal, gitignored);       
  customizations survive updates.                                             
                                                                              
  Resolver is a Python script using PEP 723 inline metadata, invoked via      
  `uv run` so deps auto-install into a cached isolated env on first call.     
  This aligns with Anthropic's Agent Skills spec and BMB conventions, and     
  keeps the dependency declared (scannable by pip-audit/Dependabot) rather    
  than vendored.                                                              
                                                                              
  ## Design choices                                                           
                                                                              
  - **Agent identity is hardcoded** in SKILL.md (name, title, Overview prose) 
    so skills can be invoked reliably by role *or* default name. Brand
    recognition is preserved; customization shapes behavior, not identity.    
  - **Luminary-anchored personas** (e.g. "Channels Martin Fowler's            
    pragmatism and Werner Vogels's cloud-scale realism") deliver ~55%
    token savings per agent while preserving distinctive voice beats.         
  - **Universal per-field merge rules** with v6.1-compatible agent            
    semantics: metadata shallow-merge, persona replace, critical_actions      
    and memories append, menu merge-by-code, all else deep-merge.             
  - **Workflow customization** shares the same surface — `bmad-product-brief`
    pilots `activation_steps_prepend`, `activation_steps_append`, and         
    `skill_end` hooks that any workflow-style skill can adopt.                
                                                                              
  ## Infrastructure                                                           
                                                                              
  - `_bmad/scripts/` houses shared Python scripts (resolver + future).        
  - `_bmad/custom/` is provisioned empty with a seeded `.gitignore` for
    `*.user.yaml` on fresh installs.                                          
  - Installer filters ensure `scripts/`, `custom/`, and sidecar-generated   
    `memory/` directories are never treated as modules.                       
  - Dead v6.1 code cleaned up: `_config/agents/` no longer created,         
    `metadata.capabilities` removed from schema and CSV manifest.
2026-04-18 23:13:31 -05:00
Alex Verkhovsky 6cecab2626
chore(install): stop copying skill prompts to _bmad by default (#2182)
* chore(install): stop copying skill prompts to _bmad by default

Flip install_to_bmad default from true to false so skill directories
are cleaned from _bmad/ after IDE install. Skills are self-contained
in their IDE directories (.claude/skills/, etc.) and no longer need
duplicate copies in _bmad/.

Two skills (bmad-create-prd, bmad-validate-prd) opt back in via
explicit manifests because bmad-edit-prd cross-references their data
files. Also fixes broken bmm-skills/ path references and corrects
the file-ref validator module-to-source mapping.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(install): make edit-prd self-contained and remove install_to_bmad

Give bmad-edit-prd its own copy of prd-purpose.md and replace the
cross-skill validation workflow reference with a skill invocation, so
all three PRD skills are fully self-contained. With no remaining
consumers, remove the install_to_bmad flag from manifests, CSV output,
the post-install cleanup loop, and the dedicated test file.

* feat(install): clean up skill directories from _bmad after IDE install

Skills are self-contained in IDE directories, so _bmad/ only needs
module-level files (config.yaml, _config/). After all IDE setups
complete, remove skill directories from _bmad/ via skill-manifest.csv.
Also cleans up skill dirs left by older installer versions.

* test(install): drop stale install_to_bmad column from suite 27 CSV row

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 10:02:59 -07:00
Brian abfc56bd2c
feat: add bmad-prfaq skill as alternative analysis path (#2157)
* feat: add bmad-prfaq skill as alternative to product brief

Add Working Backwards PRFAQ challenge skill for stress-testing product
concepts through Amazon's PRFAQ methodology. Includes press release
drafting, customer FAQ, internal FAQ, and verdict stages with subagent
support for artifact scanning and web research.

- New bmad-prfaq skill with 5-stage interactive gauntlet and headless mode
- Subagents for artifact analysis and web research (graceful degradation)
- Research-grounded output directive for current market/competitive data
- Always produces distillate for downstream PRD consumption
- Fix manifest array syntax in both prfaq and product-brief manifests
- Drop number prefixes from reference files
- Update docs: getting-started, workflow-map, agents, skills reference
- Add analysis-phase explainer doc with comparison table and decision guide
- Update workflow-map-diagram.html with prfaq card
- Add -H and -A args to CSV for both skills
- Add unist-util-visit as devDependency (was imported but undeclared)

* fix: harden bmad-prfaq for compaction resilience and context efficiency

Add coaching persona re-anchors to all stage prompts so the behavioral
directive survives context compaction. Add do-not-read guards at resume
detection, headless mode, and input gathering to prevent parent agent
context bloat. Add Stage 1 coaching notes capture. Adapt template and
press release stage for non-commercial concept types. Cap subagent
response token budgets.

* fix: add config.user.yaml to file-ref validator allowlist

Also update PRFAQ config path to use correct _config/bmm/ prefix.
2026-03-28 17:16:41 -05:00
Alex Verkhovsky 7f1a55ca8c
feat(skills): add type:skill manifest for verbatim directory copying (#1851)
* feat(skills): add type:skill manifest for verbatim skill directory copying

Introduce `type: skill` in bmad-skill-manifest.yaml to signal the
installer to copy entire skill directories verbatim into IDE skill
directories, replacing the launcher-based approach.

Changes:
- skill-manifest.js: fix single-entry detection for type-only manifests,
  add getArtifactType export
- manifest-generator.js: collect type:skill entries separately, write
  skill-manifest.csv, derive canonicalId from directory name
- _config-driven.js: add installVerbatimSkills with YAML-safe SKILL.md
  generation, stale file cleanup, and warning on parse failures
- Rename quick-dev-new-preview to bmad-quick-dev-new-preview so
  directory name is the canonical ID
- Update workflow.md installed_path to reference IDE skill base directory

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: replace {installed_path} with relative paths in quick-dev skill

Skills resolve paths relative to the skill root directory per the
open agent standard, so the installed_path variable is unnecessary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(skills): add install_to_bmad flag and skill: help catalog reference

Add install_to_bmad flag to skill manifests (default true) enabling
skills to opt out of _bmad/ copy while retaining .claude/skills/
installation. Support skill:<canonicalId> references in module-help.csv
workflow-file column. Fix stale quick-dev-new-preview directory
references in agent YAML and help catalog.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add install_to_bmad design contract tests

Unit tests against getInstallToBmad and loadSkillManifest that nail
down the 4 core design decisions for the install_to_bmad flag.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: reset skills array between runs and allow skill-only targets

- Reset this.skills and this.files in ManifestGenerator to prevent stale
  data when instance is reused across multiple manifest runs
- Allow targets with empty artifact_types to still install verbatim
  skills by checking skill_format before short-circuiting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: resolve broken file references in quick-dev-new-preview workflow

- Fix step-02-plan.md templateFile path (./tech-spec-template.md → ../tech-spec-template.md)
- Teach validate-file-refs.js to skip skill: prefixed references in CSV

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 01:23:26 -07:00
Brian Madison c563cef0c2 refactor: replace module installer scripts with declarative directories config
Removes the security-risky _module-installer pattern (code execution at
install time) in favor of a declarative `directories` key in module.yaml.
The main installer now handles directory creation centrally based on this
config, eliminating per-module installer.js scripts and their CJS/ESM issues.

Changes:
- Delete src/bmm/_module-installer/installer.js
- Delete src/core/_module-installer/installer.js
- Add `directories` key to src/bmm/module.yaml
- Rename runModuleInstaller() -> createModuleDirectories()
- Remove _module-installer from ESLint overrides
- Remove _module-installer from file-ref validator skip dirs
2026-02-08 19:21:48 -06:00
Michael Pursifull 24cf444366
feat: extend Layer 1 file-ref validator to scan CSV workflow-file references (#1573)
* feat: extend validate-file-refs.js to scan CSV workflow-file references

Add CSV file reference extraction to the Layer 1 validation pipeline,
preventing broken _bmad/ workflow-file paths in module-help.csv files.
Closes the gap identified after PR #1529 where CSV references were
unvalidated despite being a source of repeat community issues.

Refs: #1519

* fix: include test:refs in aggregate test script

Add CSV file-ref extraction tests to the aggregate `npm test` pipeline,
matching the existing pattern for test:schemas and test:install.

Thanks to CodeRabbit for catching the omission.

* fix: address review feedback on CSV validator extension

- Surface CSV parse errors visibly instead of silently swallowing
  (no Layer 2c schema validator exists yet to catch these)
- Add explanatory comments for the !VERBOSE logging pattern
  (non-verbose prints file headers only when issues found)
- Add verbose-mode diagnostics for extensionless path handling
  ([SKIP] when nothing exists, [OK-DIR] for valid directories)

* refactor: collect-then-print to eliminate confusing !VERBOSE pattern

Replace the split header-printing logic (print early in verbose mode,
print late in non-verbose mode with a !VERBOSE guard) with a simpler
collect-then-print approach. Refs are now classified into ok[] and
broken[] arrays first, then printed in a single location with one
straightforward if/else if decision.

Addresses alexeyv's review feedback about the counterintuitive
"if not verbose, log" pattern.

* feat: promote extensionless unresolved paths from silent skip to [UNRESOLVED]

Paths without file extensions that don't exist as files or directories
are now flagged as [UNRESOLVED] — a distinct tag from [BROKEN] (which
means a file with a known extension wasn't found). Both count toward
the broken reference total and appear in CI annotations.

This catches real bugs like wrong directory names in installed_path
metadata and dead invoke-workflow references to removed workflows.
Extensionless paths that DO exist as directories are still [OK-DIR].

---------

Co-authored-by: Alex Verkhovsky <alexey.verkhovsky@gmail.com>
Co-authored-by: Brian <bmadcode@gmail.com>
2026-02-08 09:19:53 -06:00
Michael Pursifull ba890779a2
feat: cross-file reference validator for BMAD source files (#1494)
* feat: add cross-file reference validator for CI

Add tools/validate-file-refs.js that validates cross-file references
in BMAD source files (agents, workflows, tasks, steps). Catches broken
file paths, missing referenced files, wrong extensions, and absolute
path leaks before they reach users.

Addresses broken-file-ref and path-handling bug classes which account
for 25% of all historical bugs (59 closed issues, 129+ comments).

- Scans src/ for YAML, markdown, and XML files
- Validates {project-root}/_bmad/ references against source tree
- Checks relative path references, exec attributes, invoke-task tags
- Detects absolute path leaks (/Users/, /home/, C:\)
- Adds validate:refs npm script and CI step in quality.yaml

* feat: strip JSON example blocks to reduce false-positive broken refs

Add stripJsonExampleBlocks() to the markdown reference extractor so
bare JSON example/template blocks (braces on their own lines) are
removed before pattern matching. This prevents paths inside example
data from being flagged as broken references.

* feat: add line numbers, fix utility/ path mapping, improve verbose output

- Add utility/ to direct path mapping (was incorrectly falling through
  to src/modules/utility/)
- Show line numbers for broken references in markdown files
- Show YAML key path for broken references in YAML files
- Print file headers in verbose mode for all files with refs

* fix: correct verbose [OK]/[BROKEN] overlap and line number drift

Broken refs no longer print [OK] before [BROKEN] in --verbose mode.
Code block stripping now preserves newlines so offsetToLine() reports
accurate line numbers when code blocks precede broken references.

* fix: address review feedback, add CI annotations and step summary

Address alexeyv's review findings on PR #1494:
- Fix exec-attr prefix handling for {_bmad}/ and bare _bmad/ paths
- Fix mapInstalledToSource fallback (remove phantom src/modules/ mapping)
- Switch extractYamlRefs to parseDocument() for YAML line numbers

Add CI integration (stories 2-1, 2-2):
- Emit ::warning annotations for broken refs and abs-path leaks
- Write markdown table to $GITHUB_STEP_SUMMARY
- Guard both behind environment variable checks

Harden CI output:
- escapeAnnotation() encodes %, \r, \n per GitHub Actions spec
- escapeTableCell() escapes pipe chars in step summary table

---------

Co-authored-by: Alex Verkhovsky <alexey.verkhovsky@gmail.com>
Co-authored-by: Brian <bmadcode@gmail.com>
2026-02-03 13:13:38 -06:00