Switch in-repo plugins to per-subdirectory layout with sync script#118
Merged
Switch in-repo plugins to per-subdirectory layout with sync script#118
Conversation
Introduce package.json (Node >=22, pnpm), a sync script that mirrors the canonical agents/skills directories into per-plugin subdirectories, and a lefthook pre-commit job that runs sync + claude plugin validate. A sync-check GitHub Actions workflow guards against drift in PRs. This is preparation for the per-subdirectory plugin layout switch in the following commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Each in-repo plugin now lives in its own subdirectory (./dev-workflows, ./dev-workflows-frontend, ./dev-skills) populated by scripts/sync-plugins.mjs from the canonical top-level agents/ and skills/ directories. The marketplace.json source field points at each subdirectory and strict mode is restored. This works around two upstream Claude Code regressions in the loader: * The plugin installer stopped copying symlinked content in v2.1.117 (anthropics/claude-code#53948, still open) — which made the previous flatten that uses source: "./" the only viable single-source layout. * The marketplace agents/skills filter arrays under source: "./" are silently ignored by the loader (anthropics/claude-code#13344, still open) — so dev-skills was loading every agent and recipe-* skill that existed at the repo root. Switching to per-subdirectory sources sidesteps both issues by giving the loader a directory that physically contains only the intended subset. The marketplace.json arrays are kept and used as the spec for the sync script, so when the upstream filter is fixed we can collapse back to a single-source layout without re-deriving the per-plugin curation. Verified with a clean install in an isolated HOME on macOS: * dev-workflows: 20 agents / 20 skills * dev-workflows-frontend: 20 agents / 18 skills * dev-skills: 0 agents / 9 skills (no leakage) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Note that the bundled plugin subdirectories are generated, edits go to the canonical agents/ and skills/ directories, and pnpm install wires up the lefthook pre-commit hook that keeps the two in sync. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
dev-workflows,dev-workflows-frontend,dev-skills) now lives in its own subdirectory at the repo root, populated from the canonical top-levelagents/andskills/directories byscripts/sync-plugins.mjsclaude plugin validatelocally; a GitHub Actions workflow guards drift in PRsWhy
The previous flatten layout (#117,
source: "./") sidestepped a v2.1.117 installer regression that drops symlinked content (anthropics/claude-code#53948), but exposed a separate latent bug: theagents/skillsfilter arrays in marketplace.json are silently ignored by the loader (anthropics/claude-code#13344). As a resultdev-skillswas loading every agent and recipe-* skill at the repo root, instead of only the 9 knowledge skills it declares.Per-subdirectory sources sidestep both bugs by giving the loader a directory that physically contains only the intended subset. The
agents/skillsarrays in marketplace.json are kept and used as the spec forsync-plugins.mjs, so when upstream filtering is fixed we can collapse back to a single-source layout without re-deriving the per-plugin curation.What changed
scripts/sync-plugins.mjs— readsmarketplace.json, copies the listed agents/skills into each<plugin-name>/subdirectory, and generates<plugin-name>/.claude-plugin/plugin.json.--checkmode does the same in a temp directory and exits non-zero on drift. Cross-platform (no shell utilities); rejects path traversal, source typos that would overwrite canonical directories, and any symlink in the source treepackage.json+pnpm-lock.yaml+.nvmrc— Node >=22, pnpm, single dev dependency on lefthooklefthook.yml— pre-commit runspnpm sync(re-stages the generated subdirectories) and thenclaude plugin validatefor marketplace + each plugin.github/workflows/sync-check.yml— runspnpm sync:checkon PRs; SHA-pinned third-party actions, least-privilegecontents: read.claude-plugin/marketplace.json—sourceswitched to./<plugin-name>,strictrestored totrue, version bumped to0.16.16dev-workflows/,dev-workflows-frontend/,dev-skills/— generated bundlesCONTRIBUTING.md— short note on the editing workflowVerification
Verified with a clean install in an isolated
HOMEon macOS (Claude Code 2.1.123):claude plugin validatepasses formarketplace.jsonand all three subdirectories.pnpm sync:checkreports clean. Drift detection, malicious-path rejection, and internal-symlink rejection were all confirmed against synthetic inputs.Test plan
sync-checkworkflow passesHOMEreports the expected agent/skill counts aboveagents/orskills/and committing causes the lefthook hook to runpnpm syncand re-stage the generated subdirectory