Skip to content

feat(installer): lean shard-doc skill prototype intermediary-state PoC#1844

Closed
dickymoore wants to merge 11 commits intobmad-code-org:mainfrom
dickymoore:feature/native-skills-lean-shard-doc-prototype
Closed

feat(installer): lean shard-doc skill prototype intermediary-state PoC#1844
dickymoore wants to merge 11 commits intobmad-code-org:mainfrom
dickymoore:feature/native-skills-lean-shard-doc-prototype

Conversation

@dickymoore
Copy link
Copy Markdown
Contributor

@dickymoore dickymoore commented Mar 7, 2026

What

This PR delivers the first lean native-skills installer PoC requested in the Native Skills Transition thread.

It keeps the scope literal and narrow:

  • keep legacy shard-doc.xml in place
  • add one real source-authored prototype skill at src/core/tasks/bmad-shard-doc-skill-prototype/SKILL.md
  • for skill_format targets, install that prototype skill alongside the canonical installed bmad-shard-doc skill
  • keep non-skill install behavior unchanged

Why

The requested first step was a small, reviewable intermediary-state proof of concept:

  1. prove one simple end-to-end path from source skill to installed skill
  2. preserve legacy shard-doc.xml during the transition
  3. verify that skill-capable targets can receive a real source-authored skill without changing non-skill behavior

This PR is intentionally low-abstraction. It is not proposing final architecture for native skills.

Scope

Included

  • src/core/tasks/bmad-shard-doc-skill-prototype/SKILL.md
    • source-authored prototype skill artifact
  • src/core/tasks/bmad-shard-doc-skill-prototype/bmad-skill-manifest.yaml
    • BMAD sidecar manifest for the prototype skill
  • tools/cli/installers/lib/ide/_config-driven.js
    • threads bmadDir through the skill-writing path
    • for skill_format targets, copies bmad-shard-doc-skill-prototype/SKILL.md from source into the platform skills directory
    • keeps the behavior literal and shard-doc-specific for this PoC
  • test/test-installation-components.js
    • verifies a skill_format install writes both:
      • canonical bmad-shard-doc
      • bmad-shard-doc-skill-prototype
    • verifies the prototype skill content is copied from source SKILL.md
    • verifies non-skill installs do not emit the prototype duplicate artifact

Excluded

  • no repo-wide conversion to source skills
  • no generalized prototype linkage/domain model
  • no broader manifest resolution cleanup
  • no stricter manifest matching policy changes
  • no generalized path-hardening/source-resolution work beyond this single PoC path
  • no upstream-facing command/help behavior changes

Notes

  • The prototype skill currently acts as a thin wrapper pointing to legacy shard-doc.xml.
  • The installer logic is deliberately a bit hardcoded/inelegant in _config-driven.js as a tradeoff to keep the first PoC narrow and reviewable.

Validation

  • node test/test-installation-components.js

Supersedes

@augmentcode
Copy link
Copy Markdown

augmentcode bot commented Mar 7, 2026

🤖 Augment PR Summary

Summary: Adds a transitional “prototype skill” wrapper for shard-doc and updates the config-driven IDE installer to emit an additional prototype skill only for skill_format targets.

Changes:

  • Adds a source-authored prototype skill at src/core/tasks/bmad-shard-doc-skill-prototype/SKILL.md with a small sidecar manifest.
  • Threads bmadDir through task/tool writing so the installer can locate source artifacts during skill emission.
  • Extends writeSkillFile() to (when writing the canonical bmad-shard-doc skill) copy the prototype SKILL verbatim into the target skills directory.
  • Adds a dedicated fixture + Test Suite 11 to verify canonical + prototype output for skill-format installs, and verifies non-skill installs do not produce the prototype artifact.

Technical Notes: Prototype copying is intentionally narrow-scoped (hard-coded to bmad-shard-doc) and preserves the source-authored prototype content verbatim, while canonical skills still go through the normal transformToSkillFormat path.

🤖 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. 2 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 7, 2026

📝 Walkthrough

Walkthrough

The change extends the config-driven installer to support shard-doc prototype SKILL duplication via a new helper method, updates method signatures to pass bmadDir parameters, creates a prototype skill directory, and adds tests verifying installation behavior across skill-format and non-skill paths.

Changes

Cohort / File(s) Summary
Installer Configuration and Helper Methods
tools/cli/installers/lib/ide/_config-driven.js
Extended writeTaskToolArtifacts and writeSkillFile signatures to accept bmadDir parameter; added new writeShardDocPrototypeSkill helper method that conditionally copies prototype SKILL.md from BMAD source tree when installing bmad-shard-doc skill in skill-format mode.
Prototype Skill Artifact Definitions
src/core/tasks/bmad-shard-doc-skill-prototype/SKILL.md, src/core/tasks/bmad-shard-doc-skill-prototype/bmad-skill-manifest.yaml
New prototype skill directory with YAML manifest (canonicalId: bmad-shard-doc-skill-prototype, type: task) and documentation file containing frontmatter, prototype marker, and reference to shard-doc task instructions.
Integration Tests
test/test-installation-components.js
Introduced createShardDocPrototypeFixture helper that extends base test fixture with shard-doc task files and manifests; added Test 11 verifying shard-doc prototype installation behavior via both skill-format platform and synthetic non-skill paths, validating artifact provisioning and cleanup logic.

Sequence Diagram(s)

sequenceDiagram
    actor Test
    participant IdeManager
    participant ConfigDrivenIdeSetup
    participant writeTaskToolArtifacts
    participant writeSkillFile
    participant writeShardDocPrototypeSkill
    participant FileSystem

    Test->>IdeManager: initiate installation with bmadDir
    IdeManager->>ConfigDrivenIdeSetup: execute installation flow
    ConfigDrivenIdeSetup->>writeTaskToolArtifacts: write task tool artifacts (bmadDir passed)
    writeTaskToolArtifacts->>writeSkillFile: delegate skill writing (bmadDir passed)
    writeSkillFile->>FileSystem: write base SKILL.md
    writeSkillFile->>writeShardDocPrototypeSkill: copy prototype (bmadDir, skillName)
    alt bmadDir present AND skillName is 'bmad-shard-doc'
        writeShardDocPrototypeSkill->>FileSystem: copy prototype SKILL.md from BMAD source
    else
        writeShardDocPrototypeSkill->>writeShardDocPrototypeSkill: skip duplication
    end
    writeSkillFile-->>ConfigDrivenIdeSetup: skill installation complete
    ConfigDrivenIdeSetup-->>Test: installation artifacts provisioned
    Test->>FileSystem: validate canonical and prototype artifacts
    Test->>Test: verify frontmatter/content as expected
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title directly reflects the main change: adding a lean shard-doc skill prototype PoC for the installer, with a focus on the intermediary-state implementation.
Description check ✅ Passed The pull request description directly relates to the changeset, explaining a lean PoC for native skills with specific scope and implementation details.

✏️ 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

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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: 6

🧹 Nitpick comments (2)
test/test-installation-components.js (1)

576-617: Move the temp-directory cleanup to finally.

Any exception after these directories are created leaks them, because the three fs.remove() calls only run on the happy path.

One way to make the cleanup reliable
-  try {
+  let tempCodexProjectDir;
+  let tempGeminiProjectDir;
+  let installedBmadDir;
+  try {
     clearCache();
     const platformCodes = await loadPlatformCodes();
     const codexInstaller = platformCodes.platforms.codex?.installer;
     const geminiInstaller = platformCodes.platforms.gemini?.installer;
@@
-    const tempCodexProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-codex-prototype-test-'));
-    const tempGeminiProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-gemini-prototype-test-'));
-    const installedBmadDir = await createShardDocPrototypeFixture();
+    tempCodexProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-codex-prototype-test-'));
+    tempGeminiProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-gemini-prototype-test-'));
+    installedBmadDir = await createShardDocPrototypeFixture();
@@
-    await fs.remove(tempCodexProjectDir);
-    await fs.remove(tempGeminiProjectDir);
-    await fs.remove(installedBmadDir);
   } catch (error) {
     assert(false, 'Shard-doc prototype duplication test succeeds', error.message);
+  } finally {
+    await Promise.allSettled(
+      [tempCodexProjectDir, tempGeminiProjectDir, installedBmadDir]
+        .filter(Boolean)
+        .map((dir) => fs.remove(dir)),
+    );
   }
🤖 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 576 - 617, The temp
directories (tempCodexProjectDir, tempGeminiProjectDir, installedBmadDir) are
only removed on the happy path; move the three await fs.remove(...) calls into a
finally block so they always run; declare those variables in the outer scope
before the try so the finally can reference them, and in the finally guard each
removal (e.g., if (variable) await fs.remove(variable)) to avoid errors when
creation failed; update the test block containing IdeManager.setup and
assertions accordingly so cleanup is performed regardless of success or failure.
tools/cli/installers/lib/ide/_config-driven.js (1)

520-525: Do not reread the same manifest for every artifact.

Skill-format installs now add one readFile + yaml.parse per artifact even when many artifacts share a directory. Cache by dirPath for the duration of a setup run.

🤖 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 520 - 525,
getPrototypeSkillIdsForArtifact currently calls loadSkillManifest for every
artifact even when multiple artifacts share the same source dir; add a
short-lived in-memory cache keyed by sourceRef.dirPath (e.g.,
this._manifestCache or similar) and change getPrototypeSkillIdsForArtifact to
first resolveArtifactSourceRef, then check the cache for sourceRef.dirPath, call
loadSkillManifest only if missing, store the parsed manifest in the cache, and
finally call getPrototypeIds(manifest, sourceRef.filename); ensure the cache is
scoped to the installer/run (instance property) so manifests are reused for the
duration of the setup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/native-skills-lean-shard-doc-prototype/phase-2-prd.md`:
- Around line 1-4: Add the required YAML frontmatter block (--- title,
description, sidebar.order, ---) before the H1 heading in each phase doc (e.g.,
phase-1-analysis.md, phase-2-prd.md, phase-3-design.md,
phase-4-implementation.md) so the files conform to the Astro/Starlight
collection schema; specifically, insert a frontmatter block like `---\ntitle:
"Phase X: ..."\ndescription: "Brief desc"\nsidebar:\n  order: N\n---`
immediately above the existing `# Phase ...` H1 heading in each file.

In `@docs/native-skills-lean-shard-doc-prototype/phase-3-architecture.md`:
- Around line 1-4: This doc (starting with the heading "Phase 3 Architecture:
Native Skills Lean PoC") and the other phase files (phase-1, phase-2, phase-4)
are missing required YAML frontmatter; add a top-of-file YAML block containing
at least title and description fields (e.g. title: "Phase 3 Architecture: Native
Skills Lean PoC" and a short description summarizing the doc) so the file
follows the docs/ frontmatter convention, ensuring the frontmatter sits before
any markdown content and is present in each of the four phase files.

In `@docs/native-skills-lean-shard-doc-prototype/phase-4-implementation.md`:
- Around line 20-31: Update the Verification Plan to include the docs
content-validation step that CI enforces: in addition to running node
test/test-installation-components.js, add running the repository’s
docs/content-validation job (the CI "content-validation" step) and verify that
it passes; keep the existing checks that no edits were made to legacy
shard-doc.xml and src/core/module-help.csv and state that the PR must pass the
docs validation before marking Done Criteria complete.
- Around line 1-4: The Markdown files for "Phase 4 Implementation: Native Skills
Lean PoC" and the corresponding Phase 1 file are missing the required YAML
frontmatter that Astro Starlight's docsSchema() expects; add a YAML frontmatter
block at the very top of each file containing at minimum a title field (e.g.,
title matching the document heading) so the schema validates.

In `@test/test-installation-components.js`:
- Around line 93-101: The fixture manifest written to bmad-skill-manifest.yaml
is missing the shard-doc.xml fields present in production; update the
shard-doc.xml entry in the test fixture to include the same type and description
keys as the real manifest (restore the missing "type" and "description"
properties for the shard-doc.xml entry so the test shape matches production),
editing the write in test-installation-components.js that creates
bmad-skill-manifest.yaml to include those fields and values used in the real
src/core/tasks/bmad-skill-manifest.yaml.

In `@tools/cli/installers/lib/ide/_config-driven.js`:
- Around line 561-562: Remove the now-dead eslint suppression that precedes the
regex replace on the normalized variable; specifically delete the comment "//
eslint-disable-next-line unicorn/prefer-string-replace-all -- regex replacement
is intentional" above the line "normalized = normalized.replace(/^\/+/, '');" so
the linter can report appropriately and the code remains unchanged.

---

Nitpick comments:
In `@test/test-installation-components.js`:
- Around line 576-617: The temp directories (tempCodexProjectDir,
tempGeminiProjectDir, installedBmadDir) are only removed on the happy path; move
the three await fs.remove(...) calls into a finally block so they always run;
declare those variables in the outer scope before the try so the finally can
reference them, and in the finally guard each removal (e.g., if (variable) await
fs.remove(variable)) to avoid errors when creation failed; update the test block
containing IdeManager.setup and assertions accordingly so cleanup is performed
regardless of success or failure.

In `@tools/cli/installers/lib/ide/_config-driven.js`:
- Around line 520-525: getPrototypeSkillIdsForArtifact currently calls
loadSkillManifest for every artifact even when multiple artifacts share the same
source dir; add a short-lived in-memory cache keyed by sourceRef.dirPath (e.g.,
this._manifestCache or similar) and change getPrototypeSkillIdsForArtifact to
first resolveArtifactSourceRef, then check the cache for sourceRef.dirPath, call
loadSkillManifest only if missing, store the parsed manifest in the cache, and
finally call getPrototypeIds(manifest, sourceRef.filename); ensure the cache is
scoped to the installer/run (instance property) so manifests are reused for the
duration of the setup.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5ede490f-b11f-4753-9ebd-3dbe93d7f1eb

📥 Commits

Reviewing files that changed from the base of the PR and between 434e7ef and a036381.

📒 Files selected for processing (8)
  • docs/native-skills-lean-shard-doc-prototype/phase-1-analysis.md
  • docs/native-skills-lean-shard-doc-prototype/phase-2-prd.md
  • docs/native-skills-lean-shard-doc-prototype/phase-3-architecture.md
  • docs/native-skills-lean-shard-doc-prototype/phase-4-implementation.md
  • src/core/tasks/bmad-skill-manifest.yaml
  • test/test-installation-components.js
  • tools/cli/installers/lib/ide/_config-driven.js
  • tools/cli/installers/lib/ide/shared/skill-manifest.js

@dickymoore dickymoore marked this pull request as draft March 7, 2026 18:02
@dickymoore
Copy link
Copy Markdown
Contributor Author

Applied a scope-tightening update and resolved all open review threads.

  • Removed the phase docs from this PR (not part of delivered repo scope for this change).
  • Addressed installer and test feedback:
    • Added containment check in artifact source resolution to prevent path escape.
    • Added per-run manifest cache to avoid repeated manifest reads.
    • Updated fixture manifest shape to match production (type + description).
    • Moved temp-dir cleanup to finally so cleanup always runs.
    • Removed the unused eslint suppression.
  • Re-ran node test/test-installation-components.js (pass).

PR remains in draft for manual review.

@dickymoore
Copy link
Copy Markdown
Contributor Author

Thread-alignment update pushed:

  • Added source prototype skill folder: src/core/tasks/bmad-shard-doc-skill-prototype/SKILL.md
  • Installer now copies prototype source SKILL as-is for skill_format targets when present
  • Added per-skill sidecar: src/core/tasks/bmad-shard-doc-skill-prototype/skill-manifest.yaml
  • Renamed core tasks sidecar to skill-manifest.yaml and added canonical+legacy manifest filename support in loader
  • Preserved non-skill behavior (Gemini remains canonical-only for shard-doc prototype test)

Validation: node test/test-installation-components.js passed.

@dickymoore dickymoore requested a review from alexeyv March 7, 2026 22:28
@dickymoore dickymoore marked this pull request as ready for review March 7, 2026 23:13
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 7, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 7, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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. 2 suggestions posted.

Fix All in Augment

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

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: 9

Caution

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

⚠️ Outside diff range comments (1)
tools/cli/installers/lib/ide/shared/skill-manifest.js (1)

12-24: ⚠️ Potential issue | 🟠 Major

Broken manifests still degrade to “no manifest”.

Returning null on parse failure makes a malformed skill manifest indistinguishable from an absent one. In this PR that means prototype installs can silently disappear while setup still reports success. That should fail loudly, or at least propagate a structured warning the caller can treat as an installation problem.

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

In `@tools/cli/installers/lib/ide/shared/skill-manifest.js` around lines 12 - 24,
loadSkillManifest currently swallows parse errors and returns null, making
malformed manifests indistinguishable from missing ones; change it so parsing
failures (and cases where parsed is falsy/not an object) return a structured
error object instead of null (for example { __invalidManifest: { message:
error.message, path: manifestPath } }) and likewise replace the catch that logs
and returns null with a return of that structured object; keep the existing
success shapes (returning { __single: parsed } or parsed) so callers can detect
and handle the { __invalidManifest } sentinel and treat it as an install failure
rather than a missing manifest.
🧹 Nitpick comments (1)
tools/cli/installers/lib/ide/_config-driven.js (1)

523-528: This hot path re-parses the same manifest over and over.

Every artifact write does a fresh loadSkillManifest(sourceRef.dirPath). On a real install that is repeated YAML I/O for the same directory, exactly where the new prototype logic sits in the inner write loop. Memoize by dirPath for the lifetime of setup() instead of rereading it on every artifact.

🤖 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 523 - 528, The
getPrototypeSkillIdsForArtifact function is repeatedly calling
loadSkillManifest(sourceRef.dirPath) for the same dirPath, causing duplicate
YAML I/O; add a short-lived cache keyed by dirPath that lives for the duration
of setup() and use it inside getPrototypeSkillIdsForArtifact (and any sibling
callers) to return a cached manifest if present instead of reloading; reference
the functions getPrototypeSkillIdsForArtifact, resolveArtifactSourceRef, and
loadSkillManifest and ensure the cache is populated on first load and read
thereafter, scoped to the installer/setup lifecycle so it resets after setup
completes.
🤖 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 887-949: The test never verifies the non-skill_format (flat-file)
path, so add an assertion that the flat-file installer is not skill_format and
run the same fixture through IdeManager.setup for the flat-file platform (use
the same createShardDocPrototypeFixture and ideManager.setup calls), then assert
the canonical SKILL.md exists but the prototype duplicate does NOT (i.e., verify
only the canonical file is written for the flat-file install); reference
platformCodes.platforms.flatfile?.installer, ideManager.setup('flatfile', ...),
createShardDocPrototypeFixture, and the canonical/prototype SKILL.md path checks
to implement this additional negative test.
- Around line 106-136: Add a prototype sidecar manifest next to the SKILL.md
file so the fixture mirrors production sidecar discovery: create a manifest file
inside the 'core/tasks/bmad-shard-doc-skill-prototype' directory (using the same
path construction as the SKILL.md write: path.join(fixtureDir, 'core', 'tasks',
'bmad-shard-doc-skill-prototype', ...)) and populate it with the minimal fields
the sidecar parser expects (e.g., name/canonicalId/displayName or the same keys
used in '_config/task-manifest.csv') so tests exercise sidecar discovery for the
prototype directory the same way production does.
- Around line 917-944: The current tests only assert file existence; enhance
assertions to verify content contracts: read codexCanonicalSkill and
codexPrototypeSkill (codexCanonicalContent, codexPrototypeContent) and assert
codexCanonicalContent contains the canonical shard-doc reference (e.g.,
"shard-doc.xml") and does NOT contain the prototype marker or prototype
frontmatter, while codexPrototypeContent includes the exact "Prototype marker:
source-authored-skill" and the prototype frontmatter name "name:
bmad-shard-doc-skill-prototype"; after ideManager.setup('gemini', ...) also read
geminiCanonicalSkill and geminiPrototypeSkill and assert geminiCanonicalContent
references "shard-doc.xml" and geminiPrototypeContent exactly matches the
source-authored prototype content (or equals codexPrototypeContent) to ensure
Gemini preserved the prototype without rewriting it.

In `@tools/cli/installers/lib/ide/_config-driven.js`:
- Around line 511-513: The prototype-copy path currently writes the source
SKILL.md without enforcing the name/frontmatter invariant; update the code that
calls readPrototypeSourceSkillContent(...) and writeFile(...) to parse the
returned SKILL.md frontmatter, verify that the frontmatter.name equals the
destination prototypeId (after normalizing with transformToSkillFormat if
appropriate), and throw or return a descriptive error instead of writing if they
disagree; apply the same validation for the other prototype-copy site (the
second read/write block mentioned) so no prototype install can produce a
SKILL.md whose name mismatches the destination id.
- Around line 504-513: The install currently skips prototypes when
readPrototypeSourceSkillContent(sourceRef, prototypeId) returns falsy, leading
to silent partial installs; change the logic in the loop inside the function
that calls resolveArtifactSourceRef and getPrototypeSkillIdsForArtifact so that
if readPrototypeSourceSkillContent(...) returns null/undefined or the SKILL.md
is unreadable, you surface an installation error (throw or return an
install-failure) referencing the specific prototypeId and sourceRef instead of
silently continuing; update the same guard used around the second occurrence
(the block around lines 538-542) so both places fail fast with a clear error
tied to prototypeId/SKILL.md rather than skipping.
- Around line 504-513: The code uses manifest-derived prototypeId directly as a
filesystem name and path (in
resolveArtifactSourceRef/getPrototypeSkillIdsForArtifact loop) which can allow
traversal or invalid names; validate and normalize prototypeId to a single safe
basename before using it for targetPath, ensureDir,
readPrototypeSourceSkillContent and writeFile (same validation/normalization
used for canonical artifacts), reject or skip any prototypeId that is empty,
contains path separators, dot-segments, or platform-invalid characters, and only
proceed with the sanitized basename when creating prototypeDir and
reading/writing SKILL.md.
- Around line 551-575: The containment check in resolveArtifactSourceRef is
insufficient for embedded traversal; after computing relativeDir/dirPath,
resolve the final directory to an absolute path (e.g. via path.resolve with
bmadDir and relativeDir) and normalize it, then verify the resolvedDir is
contained in the resolved bmadDir (compare with path.resolve(bmadDir) and ensure
the resolvedDir starts with that + path.sep or is equal); if it is outside,
return null. Keep existing filename checks but perform this secure containment
check before returning { dirPath, filename } and use the resolved absolute
dirPath for any subsequent file operations.

In `@tools/cli/installers/lib/ide/shared/skill-manifest.js`:
- Around line 60-72: resolveManifestEntry is too permissive and task-specific:
it falls back from .md to .xml and to .agent.yaml causing unrelated artifacts
(e.g., help.md matching help.xml); update resolveManifestEntry so it only
returns exact filename matches (and the __single override), and remove the
hardcoded alternate-extension fallbacks; if shared fallback behavior is required
for tasks only, add a boolean flag or a separate function (e.g.,
resolveManifestEntryForTasks) and call that from getTasksFromDir so other
callers keep strict matching; ensure references in getTasksFromDir use the
task-specific resolver and other modules continue to call the strict
resolveManifestEntry.
- Around line 80-91: normalizeIdList currently drops malformed prototypeIds
silently; change it to validate and warn instead of silently filtering: update
normalizeIdList to accept an optional logger (or import the module logger) and,
before returning, detect the malformed shapes—if ids is neither string nor
array, call logger.warn with the field name "prototypeIds" and the provided
value; if ids is an array and contains non-string entries or items that trim to
empty, call logger.warn listing the offending items and their indexes; keep the
existing dedupe/trim behavior for valid entries but ensure the warnings include
enough context so downstream installers know prototypeIds was malformed.

---

Outside diff comments:
In `@tools/cli/installers/lib/ide/shared/skill-manifest.js`:
- Around line 12-24: loadSkillManifest currently swallows parse errors and
returns null, making malformed manifests indistinguishable from missing ones;
change it so parsing failures (and cases where parsed is falsy/not an object)
return a structured error object instead of null (for example {
__invalidManifest: { message: error.message, path: manifestPath } }) and
likewise replace the catch that logs and returns null with a return of that
structured object; keep the existing success shapes (returning { __single:
parsed } or parsed) so callers can detect and handle the { __invalidManifest }
sentinel and treat it as an install failure rather than a missing manifest.

---

Nitpick comments:
In `@tools/cli/installers/lib/ide/_config-driven.js`:
- Around line 523-528: The getPrototypeSkillIdsForArtifact function is
repeatedly calling loadSkillManifest(sourceRef.dirPath) for the same dirPath,
causing duplicate YAML I/O; add a short-lived cache keyed by dirPath that lives
for the duration of setup() and use it inside getPrototypeSkillIdsForArtifact
(and any sibling callers) to return a cached manifest if present instead of
reloading; reference the functions getPrototypeSkillIdsForArtifact,
resolveArtifactSourceRef, and loadSkillManifest and ensure the cache is
populated on first load and read thereafter, scoped to the installer/setup
lifecycle so it resets after setup completes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 24f667a2-5df0-41d1-a489-41e442589887

📥 Commits

Reviewing files that changed from the base of the PR and between a036381 and ea299f3.

📒 Files selected for processing (5)
  • src/core/tasks/bmad-shard-doc-skill-prototype/SKILL.md
  • src/core/tasks/bmad-shard-doc-skill-prototype/bmad-skill-manifest.yaml
  • test/test-installation-components.js
  • tools/cli/installers/lib/ide/_config-driven.js
  • tools/cli/installers/lib/ide/shared/skill-manifest.js
✅ Files skipped from review due to trivial changes (2)
  • src/core/tasks/bmad-shard-doc-skill-prototype/SKILL.md
  • src/core/tasks/bmad-shard-doc-skill-prototype/bmad-skill-manifest.yaml

@dickymoore dickymoore force-pushed the feature/native-skills-lean-shard-doc-prototype branch from 07d7322 to 3755e72 Compare March 8, 2026 16:44
@dickymoore dickymoore marked this pull request as draft March 8, 2026 17:01
@dickymoore dickymoore marked this pull request as ready for review March 8, 2026 18:18
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 8, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 8, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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. 1 suggestion posted.

Fix All in Augment

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

try {
clearCache();
const platformCodes = await loadPlatformCodes();
const skillFormatEntry = Object.entries(platformCodes.platforms || {}).find(([_, platform]) => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The test picks the first skill_format platform it finds, but task templates differ across platforms (e.g. default-task.md vs kiro-task.md/opencode-task.md), so the hard-coded string assertions below can become order-dependent/flaky. Consider selecting a specific known platform code for this test (or relaxing assertions to match the chosen platform’s template contract).

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

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: 3

♻️ Duplicate comments (5)
test/test-installation-components.js (3)

958-972: ⚠️ Potential issue | 🟠 Major

This negative-path test is not representative of production.

You mutate a real skill-format installer into skill_format: false and instantiate ConfigDrivenIdeSetup directly, bypassing the same handler construction path production uses (IdeManager.loadConfigDrivenHandlers() plus setBmadFolderName()). A pass here does not prove existing flat-file behavior stayed intact. Use a real flat-file platform through IdeManager, or initialize the synthetic handler exactly the same way the manager does.

🤖 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 958 - 972, The test
mutates a real skill-format installer into non-skill mode and constructs
ConfigDrivenIdeSetup directly, which bypasses the production construction path;
instead obtain a real flat-file platform handler via
IdeManager.loadConfigDrivenHandlers() and configure it with setBmadFolderName()
(or replicate the exact initialization sequence IdeManager uses) so the test
uses the same handler creation as production; replace the direct new
ConfigDrivenIdeSetup(...) and mutated nonSkillInstaller usage with loading the
handler from IdeManager and selecting the matching flat-file/platform entry
before calling setup (keep references to nonSkillInstaller, nonSkillHandler,
ConfigDrivenIdeSetup, IdeManager.loadConfigDrivenHandlers, and setBmadFolderName
to guide the change).

976-981: ⚠️ Potential issue | 🟠 Major

The flat-file assertions are still too shallow to catch the real regression.

Checking directory entries only proves that something named bmad-shard-doc was written. It would still pass if the canonical flat file accidentally contained the prototype wrapper content. Read the canonical output and assert it still targets shard-doc.xml and does not include Prototype marker: source-authored-skill.

🤖 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 976 - 981, The current
test only checks filenames; extend it to open the canonical artifact file found
in nonSkillTargetDir (the entry matched by hasCanonical /
/^bmad-shard-doc(\.|$)/), read its contents and assert that the canonical output
targets "shard-doc.xml" (e.g., contains the expected target string) and that it
does NOT include the prototype marker "Prototype marker: source-authored-skill";
keep the existing hasPrototype assertion but add these content assertions after
locating the canonical file using nonSkillEntries/nonSkillTargetDir.

905-930: ⚠️ Potential issue | 🟠 Major

One skill-format platform is not enough coverage for this feature.

The change is supposed to hold across skill-format installers, but this only exercises one randomly selected platform. That leaves whole template families uncovered, especially Gemini’s non-default path. Run the scenario against at least one Markdown-based platform and Gemini so a regression in either family is caught.

🤖 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 905 - 930, The test only
exercises one randomly selected skill-format platform
(skillFormatEntry/skillFormatPlatformCode) — extend it to run the same
setup/assertion against two additional platforms: one Markdown-based platform
and the Gemini platform. Concretely, collect all matching skill-format platforms
(replace skillFormatEntry with skillFormatPlatforms array), locate a Markdown
template platform by checking installer fields that indicate Markdown templating
(e.g., installer.template_engine/template_type containing "md" or "markdown" or
platform code including "markdown"/"md"), and locate the Gemini platform by
platform code "gemini" or installer name containing "Gemini"; for each found
platform call ideManager.setup (same options as used for
skillFormatPlatformCode) and assert success (similar to skillResult assertion).
Ensure the new variables (e.g., markdownPlatformCode, geminiPlatformCode and
their results) reuse the same temp dirs and installedBmadDir setup, and
skip/test-guard if either Markdown or Gemini platform is not present.
tools/cli/installers/lib/ide/_config-driven.js (2)

529-534: ⚠️ Potential issue | 🟠 Major

Validate the copied prototype frontmatter before writing it.

This path copies the source SKILL.md verbatim without checking that its name: still matches bmad-shard-doc-skill-prototype. If that source file drifts, you install a directory whose metadata points at a different skill id, which strict skill platforms tend to reject.

🤖 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 529 - 534,
Before writing SKILL.md, parse and validate the frontmatter in
sourceSkillContent to ensure the "name" field matches prototypeId (the expected
prototype skill id); if the parsed frontmatter name is missing or not equal to
prototypeId, abort (throw or log and return) instead of writing the file. Use
the existing variables sourceSkillContent, prototypeId, prototypeDir and the
SKILL.md write path to locate the check, and perform the validation between
reading the file and calling this.writeFile to avoid installing mismatched
prototype metadata.

527-530: ⚠️ Potential issue | 🟠 Major

Missing or empty prototype source still reports a successful install.

Returning on pathExists === false or empty content turns a broken source tree into a partial install with no signal beyond a missing duplicate skill. This should fail fast, or at minimum emit a warning tied to bmad-shard-doc-skill-prototype.

🤖 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 527 - 530, The
installer currently silently returns when a prototype skill file is missing or
empty (checks on sourceSkillPath and sourceSkillContent), which leads to a
partial/hidden success; update the logic in the code handling
sourceSkillPath/sourceSkillContent so that if fs.pathExists(sourceSkillPath) is
false or the file read yields empty content you either (a) throw an Error to
fail fast or (b) emit a clear error/warning tied to the
bmad-shard-doc-skill-prototype identifier (use the existing logging mechanism
used elsewhere in this module) and abort the install flow rather than returning
silently; locate the checks around sourceSkillPath and sourceSkillContent to
implement this change.
🧹 Nitpick comments (1)
tools/cli/installers/lib/ide/_config-driven.js (1)

269-297: Keep the shard-doc transition out of the generic skill writer.

Plumbing bmadDir through writeTaskToolArtifacts() into writeSkillFile() makes the shared “write one skill” primitive carry a task-specific filesystem side effect. That coupling will get worse the moment a second prototype is added. Trigger the duplicate install from the task branch, or drive it from artifact metadata before calling writeSkillFile().

Also applies to: 492-513

🤖 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 269 - 297, The
writeTaskToolArtifacts function is passing bmadDir into the generic
writeSkillFile, coupling a task-specific duplicate-install side effect into the
shared skill writer; remove plumbing of bmadDir into writeSkillFile and instead
handle the shard/duplicate install from the task branch (inside
writeTaskToolArtifacts) before calling writeSkillFile when artifact.type ===
'task' (or when artifact metadata indicates a duplicate-install is required), or
drive that duplicate write from artifact.metadata; update calls to
writeSkillFile to omit bmadDir and perform any extra filesystem writes (the
bmadDir copy) explicitly in writeTaskToolArtifacts (and the analogous spot at
lines ~492-513) so the generic writeSkillFile remains task-agnostic.
🤖 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 94-103: Update the test fixture that writes
bmad-skill-manifest.yaml in test/test-installation-components.js to include the
production prototype linkage: inside the array passed to fs.writeFile for the
manifest (the entry with 'shard-doc.xml:' and 'canonicalId: bmad-shard-doc') add
a 'prototypeIds:' YAML block with the same prototype id(s) used in production
(e.g. a nested list line like '  prototypeIds:' followed by '    -
<production-prototype-id>'). This ensures the installer test exercises the
prototype relationship rather than relying on a hardcoded path.
- Around line 905-944: The test is fragile because it picks the first
skill_format platform via skillFormatEntry and asserts an exact template
sentence; change it to either (A) pin explicit platform codes (use a small
allowed list and find the first matching code, e.g. check
skillFormatPlatformCode against that list before running the rest) or (B) relax
the content assertions: keep selecting a valid skill installer via
skillFormatEntry/skillInstaller but replace the exact sentence checks on
canonicalSkillContent/prototypeSkillContent with stable checks such as the
presence of "shard-doc.xml" reference and a distinct prototype marker (e.g.
presence/absence of a known prototype filename or frontmatter flag) rather than
the full written sentence; update the assertions that reference
canonicalSkillContent and prototypeSkillContent accordingly.

In `@tools/cli/installers/lib/ide/_config-driven.js`:
- Around line 512-526: The writeShardDocPrototypeSkill function currently
hardcodes prototypeId and sourceSkillPath, ignoring manifest-declared
prototypeIds and sidecar loading; change it to read the artifact/manifest for
the given skill (use the same manifest/sidecar loading code used elsewhere),
fetch prototypeIds from that manifest, and iterate over those prototypeIds to
copy each prototype SKILL.md from bmadDir (or skip if not present) instead of
always using the literal 'bmad-shard-doc-skill-prototype'; ensure you update
references to prototypeId and sourceSkillPath in this function to use the
manifest-driven values.

---

Duplicate comments:
In `@test/test-installation-components.js`:
- Around line 958-972: The test mutates a real skill-format installer into
non-skill mode and constructs ConfigDrivenIdeSetup directly, which bypasses the
production construction path; instead obtain a real flat-file platform handler
via IdeManager.loadConfigDrivenHandlers() and configure it with
setBmadFolderName() (or replicate the exact initialization sequence IdeManager
uses) so the test uses the same handler creation as production; replace the
direct new ConfigDrivenIdeSetup(...) and mutated nonSkillInstaller usage with
loading the handler from IdeManager and selecting the matching
flat-file/platform entry before calling setup (keep references to
nonSkillInstaller, nonSkillHandler, ConfigDrivenIdeSetup,
IdeManager.loadConfigDrivenHandlers, and setBmadFolderName to guide the change).
- Around line 976-981: The current test only checks filenames; extend it to open
the canonical artifact file found in nonSkillTargetDir (the entry matched by
hasCanonical / /^bmad-shard-doc(\.|$)/), read its contents and assert that the
canonical output targets "shard-doc.xml" (e.g., contains the expected target
string) and that it does NOT include the prototype marker "Prototype marker:
source-authored-skill"; keep the existing hasPrototype assertion but add these
content assertions after locating the canonical file using
nonSkillEntries/nonSkillTargetDir.
- Around line 905-930: The test only exercises one randomly selected
skill-format platform (skillFormatEntry/skillFormatPlatformCode) — extend it to
run the same setup/assertion against two additional platforms: one
Markdown-based platform and the Gemini platform. Concretely, collect all
matching skill-format platforms (replace skillFormatEntry with
skillFormatPlatforms array), locate a Markdown template platform by checking
installer fields that indicate Markdown templating (e.g.,
installer.template_engine/template_type containing "md" or "markdown" or
platform code including "markdown"/"md"), and locate the Gemini platform by
platform code "gemini" or installer name containing "Gemini"; for each found
platform call ideManager.setup (same options as used for
skillFormatPlatformCode) and assert success (similar to skillResult assertion).
Ensure the new variables (e.g., markdownPlatformCode, geminiPlatformCode and
their results) reuse the same temp dirs and installedBmadDir setup, and
skip/test-guard if either Markdown or Gemini platform is not present.

In `@tools/cli/installers/lib/ide/_config-driven.js`:
- Around line 529-534: Before writing SKILL.md, parse and validate the
frontmatter in sourceSkillContent to ensure the "name" field matches prototypeId
(the expected prototype skill id); if the parsed frontmatter name is missing or
not equal to prototypeId, abort (throw or log and return) instead of writing the
file. Use the existing variables sourceSkillContent, prototypeId, prototypeDir
and the SKILL.md write path to locate the check, and perform the validation
between reading the file and calling this.writeFile to avoid installing
mismatched prototype metadata.
- Around line 527-530: The installer currently silently returns when a prototype
skill file is missing or empty (checks on sourceSkillPath and
sourceSkillContent), which leads to a partial/hidden success; update the logic
in the code handling sourceSkillPath/sourceSkillContent so that if
fs.pathExists(sourceSkillPath) is false or the file read yields empty content
you either (a) throw an Error to fail fast or (b) emit a clear error/warning
tied to the bmad-shard-doc-skill-prototype identifier (use the existing logging
mechanism used elsewhere in this module) and abort the install flow rather than
returning silently; locate the checks around sourceSkillPath and
sourceSkillContent to implement this change.

---

Nitpick comments:
In `@tools/cli/installers/lib/ide/_config-driven.js`:
- Around line 269-297: The writeTaskToolArtifacts function is passing bmadDir
into the generic writeSkillFile, coupling a task-specific duplicate-install side
effect into the shared skill writer; remove plumbing of bmadDir into
writeSkillFile and instead handle the shard/duplicate install from the task
branch (inside writeTaskToolArtifacts) before calling writeSkillFile when
artifact.type === 'task' (or when artifact metadata indicates a
duplicate-install is required), or drive that duplicate write from
artifact.metadata; update calls to writeSkillFile to omit bmadDir and perform
any extra filesystem writes (the bmadDir copy) explicitly in
writeTaskToolArtifacts (and the analogous spot at lines ~492-513) so the generic
writeSkillFile remains task-agnostic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f5af717a-3eb4-4c59-9d6c-542084b25623

📥 Commits

Reviewing files that changed from the base of the PR and between ea299f3 and f053d30.

📒 Files selected for processing (4)
  • src/core/tasks/bmad-shard-doc-skill-prototype/SKILL.md
  • src/core/tasks/bmad-shard-doc-skill-prototype/bmad-skill-manifest.yaml
  • test/test-installation-components.js
  • tools/cli/installers/lib/ide/_config-driven.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/core/tasks/bmad-shard-doc-skill-prototype/SKILL.md
  • src/core/tasks/bmad-shard-doc-skill-prototype/bmad-skill-manifest.yaml

Comment on lines +94 to +103
await fs.writeFile(
path.join(fixtureDir, 'core', 'tasks', 'bmad-skill-manifest.yaml'),
[
'shard-doc.xml:',
' canonicalId: bmad-shard-doc',
' type: task',
' description: "Splits large markdown documents into smaller, organized files based on sections"',
'',
].join('\n'),
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

The fixture still omits the new prototypeIds linkage.

Right now this test passes even if the installer ignores manifest-declared prototype relationships entirely, because the shard-doc fixture only declares canonicalId, type, and description. Add the prototypeIds entry that production uses, otherwise this scenario is proving the hardcoded path, not the new contract.

🤖 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 94 - 103, Update the test
fixture that writes bmad-skill-manifest.yaml in
test/test-installation-components.js to include the production prototype
linkage: inside the array passed to fs.writeFile for the manifest (the entry
with 'shard-doc.xml:' and 'canonicalId: bmad-shard-doc') add a 'prototypeIds:'
YAML block with the same prototype id(s) used in production (e.g. a nested list
line like '  prototypeIds:' followed by '    - <production-prototype-id>'). This
ensures the installer test exercises the prototype relationship rather than
relying on a hardcoded path.

Comment on lines +905 to +944
const skillFormatEntry = Object.entries(platformCodes.platforms || {}).find(([_, platform]) => {
const installer = platform?.installer;
if (!installer || installer.skill_format !== true || typeof installer.target_dir !== 'string') return false;
if (Array.isArray(installer.artifact_types) && !installer.artifact_types.includes('tasks')) return false;
return true;
});

assert(Boolean(skillFormatEntry), 'Found a skill_format platform that installs task artifacts');
if (!skillFormatEntry) throw new Error('No suitable skill_format platform found for shard-doc prototype test');

const [skillFormatPlatformCode, skillFormatPlatform] = skillFormatEntry;
const skillInstaller = skillFormatPlatform.installer;

tempSkillProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-skill-prototype-test-'));
tempNonSkillProjectDir = await fs.mkdtemp(path.join(os.tmpdir(), 'bmad-nonskill-prototype-test-'));
installedBmadDir = await createShardDocPrototypeFixture();

const ideManager = new IdeManager();
await ideManager.ensureInitialized();

const skillResult = await ideManager.setup(skillFormatPlatformCode, tempSkillProjectDir, installedBmadDir, {
silent: true,
selectedModules: ['bmm'],
});

assert(skillResult.success === true, `${skillFormatPlatformCode} setup succeeds for shard-doc prototype fixture`);

const canonicalSkillPath = path.join(tempSkillProjectDir, skillInstaller.target_dir, 'bmad-shard-doc', 'SKILL.md');
const prototypeSkillPath = path.join(tempSkillProjectDir, skillInstaller.target_dir, 'bmad-shard-doc-skill-prototype', 'SKILL.md');
assert(await fs.pathExists(canonicalSkillPath), `${skillFormatPlatformCode} install writes canonical shard-doc skill`);
assert(await fs.pathExists(prototypeSkillPath), `${skillFormatPlatformCode} install writes duplicated shard-doc prototype skill`);

const canonicalSkillContent = await fs.readFile(canonicalSkillPath, 'utf8');
const prototypeSkillContent = await fs.readFile(prototypeSkillPath, 'utf8');

assert(canonicalSkillContent.includes('name: bmad-shard-doc'), 'Canonical shard-doc skill keeps canonical frontmatter name');
assert(
canonicalSkillContent.includes('Read the entire task file at: {project-root}/_bmad/core/tasks/shard-doc.xml'),
'Canonical shard-doc skill points to shard-doc.xml',
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

This test is order-dependent and template-dependent.

It picks the first skill_format platform returned by Object.entries() and then asserts a very specific task-template sentence. Both are fragile: platform order can change, and not every valid skill-format template is going to use that exact wording. Pin explicit platforms or assert only the stable contract, e.g. a shard-doc.xml reference plus the absence/presence of the prototype marker.

🤖 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 905 - 944, The test is
fragile because it picks the first skill_format platform via skillFormatEntry
and asserts an exact template sentence; change it to either (A) pin explicit
platform codes (use a small allowed list and find the first matching code, e.g.
check skillFormatPlatformCode against that list before running the rest) or (B)
relax the content assertions: keep selecting a valid skill installer via
skillFormatEntry/skillInstaller but replace the exact sentence checks on
canonicalSkillContent/prototypeSkillContent with stable checks such as the
presence of "shard-doc.xml" reference and a distinct prototype marker (e.g.
presence/absence of a known prototype filename or frontmatter flag) rather than
the full written sentence; update the assertions that reference
canonicalSkillContent and prototypeSkillContent accordingly.

Comment on lines +512 to +526
await this.writeShardDocPrototypeSkill(targetPath, bmadDir, skillName);
}

/**
* Copy shard-doc prototype skill during transition when installing skill-format targets.
* Keeps scope literal for the first PoC without introducing generalized prototype linkage.
* @param {string} targetPath - Base skills directory
* @param {string|null} bmadDir - Installed bmad directory
* @param {string} skillName - Canonical skill name being written
*/
async writeShardDocPrototypeSkill(targetPath, bmadDir, skillName) {
if (!bmadDir || skillName !== 'bmad-shard-doc') return;

const prototypeId = 'bmad-shard-doc-skill-prototype';
const sourceSkillPath = path.join(bmadDir, 'core', 'tasks', prototypeId, 'SKILL.md');
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

The new manifest linkage is ignored here.

writeShardDocPrototypeSkill() hardcodes both the canonical source skill and the prototype id, so the newly added prototypeIds manifest data and sidecar loading logic never participate in the install decision on this path. If the manifest changes, this code keeps copying whatever the literals say. Plumb the declared prototype ids onto the artifact and iterate those instead.

🤖 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 512 - 526, The
writeShardDocPrototypeSkill function currently hardcodes prototypeId and
sourceSkillPath, ignoring manifest-declared prototypeIds and sidecar loading;
change it to read the artifact/manifest for the given skill (use the same
manifest/sidecar loading code used elsewhere), fetch prototypeIds from that
manifest, and iterate over those prototypeIds to copy each prototype SKILL.md
from bmadDir (or skip if not present) instead of always using the literal
'bmad-shard-doc-skill-prototype'; ensure you update references to prototypeId
and sourceSkillPath in this function to use the manifest-driven values.

@bmadcode bmadcode closed this Mar 27, 2026
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.

3 participants