Skip to content

refactor(skills): add SKILL.md entrypoint to skill directories#1868

Merged
alexeyv merged 5 commits intobmad-code-org:mainfrom
alexeyv:refactor/skill-format
Mar 9, 2026
Merged

refactor(skills): add SKILL.md entrypoint to skill directories#1868
alexeyv merged 5 commits intobmad-code-org:mainfrom
alexeyv:refactor/skill-format

Conversation

@alexeyv
Copy link
Copy Markdown
Collaborator

@alexeyv alexeyv commented Mar 9, 2026

Summary

  • Add SKILL.md with name/description frontmatter to both tracer bullet skill directories, aligning with the Open Skills standard
  • Installer now reads metadata from SKILL.md instead of workflow.md, validates name matches directory name exactly
  • Installer copies skill directories verbatim instead of auto-generating SKILL.md
  • Install path in manifest CSV points to SKILL.md (the permanent entrypoint)
  • Copy filter excludes OS/editor artifacts (.DS_Store, backups, dotfiles)
  • No longer strips bmad-skill-manifest.yaml from copied skills
  • Debug-guards validation messages; name-mismatch remains a hard error
  • Adds typeof guard for malformed YAML frontmatter
  • Adds negative test cases for parseSkillMd validation (Suite 30)

Test plan

  • All 215 existing tests pass
  • New Suite 30 covers: missing SKILL.md, no frontmatter, missing name, missing description, name mismatch, malformed YAML, valid case
  • Lint, markdown lint, and prettier all clean
  • Pre-commit hooks pass

Align skill source format with Open Skills standard: each skill
directory now contains a SKILL.md with name/description frontmatter
where name must match the directory name exactly. The installer
copies skill directories verbatim instead of generating SKILL.md.

- Add SKILL.md to both tracer bullet skill directories
- Strip name/description from workflow.md frontmatter (SKILL.md owns it)
- Installer reads metadata from SKILL.md, validates name matches dirname
- Install path in manifest CSV now points to SKILL.md
- Copy filter excludes OS/editor artifacts (.DS_Store, backups, dotfiles)
- Debug-guard validation messages, keep name-mismatch as hard error
- Add typeof guard for malformed YAML frontmatter
- Add negative test cases for parseSkillMd validation (Suite 30)
@augmentcode
Copy link
Copy Markdown

augmentcode bot commented Mar 9, 2026

🤖 Augment PR Summary

Summary: This PR standardizes skills around a dedicated SKILL.md entrypoint with YAML frontmatter, aligning skill directories with the Open Skills pattern and simplifying how skills are discovered and installed.

Changes:

  • Adds SKILL.md entrypoints to the two “tracer bullet” skill directories and removes name/description frontmatter from their workflow.md files.
  • Updates manifest generation to identify skills via bmad-skill-manifest.yaml + SKILL.md, validate frontmatter, and emit manifest paths that point to SKILL.md (as the permanent entrypoint).
  • Introduces parseSkillMd() to parse and validate skill frontmatter (missing file/frontmatter/name/description, malformed YAML, and directory-name mismatch).
  • Refactors the IDE installer to copy skill directories verbatim (no auto-generation or transformation of SKILL.md) and filters common OS/editor artifacts during copy.
  • Updates Suite 29 installation tests for the new entrypoint and adds Suite 30 negative/positive validation coverage for parseSkillMd().

Technical Notes: Skills continue to derive canonicalId from the directory name, and skills are skipped when SKILL.md is missing/invalid or its name doesn’t exactly match the directory name.

🤖 Was this summary useful? React with 👍 or 👎

Copy link
Copy Markdown

@augmentcode augmentcode bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 3 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 9, 2026

📝 Walkthrough

Walkthrough

This PR migrates the skill detection and installation system from using workflow.md files with frontmatter and bmad-skill-manifest.yaml to a new SKILL.md file format as the canonical skill entry point. The manifest-generator.js is updated with a new parseSkillMd() method, and the installer logic is refactored to use SKILL.md directly without frontmatter transformation.

Changes

Cohort / File(s) Summary
New SKILL.md Files
src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/SKILL.md, src/core/tasks/bmad-review-adversarial-general/SKILL.md
Added new SKILL.md files with YAML frontmatter (name, description) as the canonical skill entry point, replacing the previous pattern of storing metadata in workflow.md frontmatter.
Workflow.md Metadata Removal
src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/workflow.md, src/core/tasks/bmad-review-adversarial-general/workflow.md
Removed name and description frontmatter fields from workflow.md files, moving this metadata to the new SKILL.md format.
Manifest Generator Core
tools/cli/installers/lib/core/manifest-generator.js
Added parseSkillMd() method to parse and validate SKILL.md frontmatter with directory-name consistency checks. Updated collectSkills() to detect skills via SKILL.md instead of workflow.md, and adjusted installation paths to reference SKILL.md as the canonical entrypoint.
Verbatim Skill Installation
tools/cli/installers/lib/ide/_config-driven.js
Removed frontmatter extraction and SKILL.md generation logic; now copies source SKILL.md directly without transformation. Updated path derivation and added explicit ignore rules for OS artifacts, temporary files, and hidden files during copy.
Installation Tests
test/test-installation-components.js
Updated test expectations from workflow.md-based skill detection to SKILL.md. Added Suite 30 with negative/positive validation cases for parseSkillMd() (missing SKILL.md, invalid frontmatter, name mismatches, malformed YAML).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • PR #1857: Converts adversarial review task into a SKILL-based skill (adding SKILL.md/workflow.md) and updates manifest-generator to detect and use SKILL.md in coordination with this change.
  • PR #1834: Implements SKILL.md-based skill detection and parsing, directly overlapping with the core refactor of skill detection logic in this PR.
  • PR #1851: Modifies the same skill-installation surface (SKILL.md, manifest-generator, installer logic) to align with the new skill discovery pattern.

Suggested reviewers

  • bmadcode
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding SKILL.md as the entrypoint to skill directories, which is the primary refactoring objective.
Description check ✅ Passed The description comprehensively details the changes, including adding SKILL.md files, metadata handling, installer updates, and test coverage.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test/test-installation-components.js (1)

1609-1697: ⚠️ Potential issue | 🟠 Major

These fixtures still stop short of the code path that changed.

Suite 29 only inspects generator29.skills in memory. The risky part of this PR is the serialized skill-manifest.csv row plus _config-driven.installVerbatimSkills() copying/filtering the directory tree, so a bad SKILL.md path or broken nested-artifact filter would still pass here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/test-installation-components.js` around lines 1609 - 1697, The test only
checks in-memory generator29.skills and doesn't exercise the serialization and
installation code paths that were changed (skill-manifest.csv and
_config-driven.installVerbatimSkills), so extend the fixture and assertions to
write/read the serialized manifest and call the install routine: after
generator29.generateManifests(tempFixture29,...), read the generated
skill-manifest.csv (or equivalent manifest CSV produced by
ManifestGenerator.generateManifests) and assert it contains the correct SKILL.md
relative path for 'my-skill', then call _config-driven.installVerbatimSkills (or
the public wrapper that triggers it) against the generated manifest and the temp
install dir and assert the copied tree includes the SKILL.md at the expected
nested path and that nested artifacts (like workflow.md inside skill-only
modules) are filtered according to the new nested-artifact rules; use the
existing generator29 and scannedModules29 variables (and functions
generateManifests, scanInstalledModules, and installVerbatimSkills) to locate
code paths to exercise.
🧹 Nitpick comments (1)
tools/cli/installers/lib/ide/_config-driven.js (1)

665-680: Don't delete the working skill before the replacement copy succeeds.

Lines 667-680 make any mid-copy failure destructive: the old skill is already gone, and the new one is only partially written. Stage into a temp directory and rename on success.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/cli/installers/lib/ide/_config-driven.js` around lines 665 - 680,
Current logic removes skillDir before copying, which can leave you with a
partially written skill on failure; instead create a temporary target (e.g.,
skillTmpDir = path.join(targetPath, `${canonicalId}.tmp-${Date.now()}`) or use
fs.mkdtemp), ensure and copy all files from sourceDir into skillTmpDir using the
same filtering logic (entries loop and fs.copy), then on successful completion
move/rename skillTmpDir to skillDir (or fs.move) replacing the old directory
atomically; only remove the original skillDir after a successful copy or use
fs.move to overwrite atomically so failures don’t delete the working skill.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/test-installation-components.js`:
- Around line 1713-1714: Replace the timestamped directory creation for
tempFixture30 with fs.mkdtemp to avoid collisions: instead of building a path
with path.join(os.tmpdir(), `bmad-test-30-${Date.now()}`) and calling
fs.ensureDir, call fs.mkdtemp with a prefix like path.join(os.tmpdir(),
'bmad-test-30-') and assign its returned path to tempFixture30 (no separate
ensureDir call needed); update any usages of tempFixture30 accordingly.
- Around line 1686-1697: The test creates the "skill-only-mod" fixture but calls
generateManifests() before it, so it only verifies scanInstalledModules() in
isolation; move the creation of skill-only-mod (the fs.ensureDir and
fs.writeFile calls creating deep/nested/my-skill with bmad-skill-manifest.yaml,
SKILL.md, and workflow.md) to occur before invoking
generator29.generateManifests(), or re-run generateManifests() after creating
the skill-only-mod so that generateManifests() (and downstream collectSkills())
can discover and include that module in the emitted manifests; verify the
generated manifests include "skill-only-mod" (or the expected skill identifier)
rather than only asserting scanInstalledModules().
- Around line 1716-1765: Add tests that create SKILL.md frontmatter where
description is a non-string structured value (e.g., description: [ "a", "b" ]
and description: { text: "x" }) and ensure these fixtures are passed through the
full manifest generation path by invoking
ManifestGenerator.generateManifests(...) (in addition to parseSkillMd),
asserting the generator either skips/returns null for those skills or safely
normalizes them; reference the existing ManifestGenerator, parseSkillMd, and
generateManifests symbols when adding the new cases so the test exercises the
CSV/text normalization codepath that currently fails on structured descriptions.

In `@tools/cli/installers/lib/ide/_config-driven.js`:
- Around line 670-680: The current artifact filtering only checks top-level
entries and then blindly copies directory subtrees, so nested dotfiles/temp
files slip through; replace the flat copy with a recursive copy that applies the
same checks for every Dirent: implement a helper (e.g., copyFiltered or
recursiveCopy) that reads each directory with fs.readdir(..., { withFileTypes:
true }), skips entries matching skipPatterns, skipSuffixes, or leading-dot rules
(but preserves '.gitkeep'), and for directories recurses into them creating the
destination dir, while for files performs fs.copy; update the call sites that
used fs.copy(sourceDir, skillDir) to use copyFiltered(sourceDir, skillDir) so
the artifact filter is applied recursively.
- Around line 656-660: The code uses new RegExp(`^${bmadFolderName}/`) to strip
a prefix from record.path which fails if bmadFolderName contains regex
metacharacters; update the logic where relativePath is computed (and the same
other occurrence later) to build a literal prefix string (prefix =
bmadFolderName + '/') and use record.path.startsWith(prefix) ?
record.path.slice(prefix.length) : record.path to derive relativePath, then
continue to join with bmadDir to produce sourceFile; apply the identical change
to the second occurrence mentioned so both prefix-strip sites use
startsWith/slice.

---

Outside diff comments:
In `@test/test-installation-components.js`:
- Around line 1609-1697: The test only checks in-memory generator29.skills and
doesn't exercise the serialization and installation code paths that were changed
(skill-manifest.csv and _config-driven.installVerbatimSkills), so extend the
fixture and assertions to write/read the serialized manifest and call the
install routine: after generator29.generateManifests(tempFixture29,...), read
the generated skill-manifest.csv (or equivalent manifest CSV produced by
ManifestGenerator.generateManifests) and assert it contains the correct SKILL.md
relative path for 'my-skill', then call _config-driven.installVerbatimSkills (or
the public wrapper that triggers it) against the generated manifest and the temp
install dir and assert the copied tree includes the SKILL.md at the expected
nested path and that nested artifacts (like workflow.md inside skill-only
modules) are filtered according to the new nested-artifact rules; use the
existing generator29 and scannedModules29 variables (and functions
generateManifests, scanInstalledModules, and installVerbatimSkills) to locate
code paths to exercise.

---

Nitpick comments:
In `@tools/cli/installers/lib/ide/_config-driven.js`:
- Around line 665-680: Current logic removes skillDir before copying, which can
leave you with a partially written skill on failure; instead create a temporary
target (e.g., skillTmpDir = path.join(targetPath,
`${canonicalId}.tmp-${Date.now()}`) or use fs.mkdtemp), ensure and copy all
files from sourceDir into skillTmpDir using the same filtering logic (entries
loop and fs.copy), then on successful completion move/rename skillTmpDir to
skillDir (or fs.move) replacing the old directory atomically; only remove the
original skillDir after a successful copy or use fs.move to overwrite atomically
so failures don’t delete the working skill.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0e8fda07-9c00-4858-a5ea-20a156032dd5

📥 Commits

Reviewing files that changed from the base of the PR and between ee25fcc and 34abaf2.

📒 Files selected for processing (7)
  • src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/SKILL.md
  • src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/workflow.md
  • src/core/tasks/bmad-review-adversarial-general/SKILL.md
  • src/core/tasks/bmad-review-adversarial-general/workflow.md
  • test/test-installation-components.js
  • tools/cli/installers/lib/core/manifest-generator.js
  • tools/cli/installers/lib/ide/_config-driven.js
💤 Files with no reviewable changes (2)
  • src/bmm/workflows/bmad-quick-flow/bmad-quick-dev-new-preview/workflow.md
  • src/core/tasks/bmad-review-adversarial-general/workflow.md

alexeyv and others added 4 commits March 9, 2026 00:59
Add trigger context so LLMs know when to invoke the skill,
matching the "Use when..." pattern used by other skills.
…killMd

Prevents cleanForCSV() crash when YAML parses name or description as
a non-string type (number, object, boolean).
…e filter)

- Replace Date.now() temp dir with fs.mkdtemp() in Suite 30 tests (F5)
- Replace unescaped RegExp with startsWith/slice for path prefix stripping (F7)
- Apply artifact filter recursively via fs.copy filter option (F8)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@alexeyv alexeyv merged commit 1b3c3c5 into bmad-code-org:main Mar 9, 2026
5 checks passed
@alexeyv alexeyv deleted the refactor/skill-format branch March 9, 2026 08:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant