Context
Today the repo is a single Claude Code marketplace with one plugin:
.claude-plugin/
├── marketplace.json # marketplace "axoniq-agent-skills" → 1 plugin "axon4to5" (source "./")
└── plugin.json # the axon4to5 plugin manifest
skills/
└── axon4to5-openrewrite/ # the only skill so far
We expect many plugins in this repo, each bundling a subset of the skills in skills/, while keeping skills/ at the root as the single canonical source so it stays directly consumable by:
- Claude Code (marketplace install)
npx skills / agentskills.io (reads skills/<name>/SKILL.md at repo root)
- a future Codex plugin/manifest (also reads the same pool)
Problem / core constraint
The obvious approach — multiple marketplace.json entries all with source: "./" plus a skills selector — does not subset. Per the Plugins reference:
- Component paths must be relative to the plugin root, start with
./, and cannot traverse outside it (../shared "will not work after installation because those external files are not copied to the cache"). → #path-traversal-limitations
- The
skills manifest field adds to the default skills/ scan — it does not replace it. → #component-path-fields
So any plugin whose root is the repo root auto-discovers the entire root skills/ dir. The current setup only appears to select because there is exactly one skill.
Goals
Options
Option A — Symlink monorepo (officially documented for this case)
Per-plugin subdirectories; each plugin's skills/ holds symlinks into the canonical root skills/. On marketplace install, Claude dereferences sibling-marketplace symlinks (copies the real content into its cache). → Share files within a marketplace with symlinks
.claude-plugin/marketplace.json # metadata.pluginRoot="./plugins"; one entry per plugin
skills/ # canonical pool (untouched)
axon4to5-openrewrite/SKILL.md
...
plugins/
axon4to5/
.claude-plugin/plugin.json
skills/
axon4to5-openrewrite -> ../../../skills/axon4to5-openrewrite # symlink
axon-devagent/
.claude-plugin/plugin.json
skills/
axon-devagent-assistant -> ../../../skills/axon-devagent-assistant
- Pro: True per-plugin subsetting; zero content duplication;
npx skills/Codex read root skills/ untouched; no strict:false, no duplicated component lists.
- Con: Windows — Git checks symlinks out as text stubs unless
core.symlinks=true + Developer Mode — affects Windows contributors and Windows end users whose Claude fetches the marketplace.
- Con:
claude --plugin-dir <subdir> does not dereference cross-dir symlinks; local testing must use /plugin marketplace add <local path> then install.
Option B — Committed generator / copy-sync (Windows-proof)
Same plugins/<name>/ layout, but instead of committing symlinks, commit a small scripts/link-skills.sh driven by a declared skill list per plugin. Use symlinks for local dev and copy real files at release (or always copy).
- Pro: Bulletproof across OSes and both consumers; no symlink fragility.
- Con: Adds a build/sync step; "copy" mode duplicates skill content in the published tree.
Option C — Separate sources via git-subdir / per-repo plugins
Keep one marketplace.json but fetch each plugin from its own path/repo using source: { "source": "git-subdir", ... }. → Plugin sources
- Pro: Best if plugins eventually live in separate repos; sparse-clones large monorepos.
- Con: Doesn't share one in-repo
skills/ pool as cleanly; more moving parts.
Option D — Single mega-plugin, no subsetting
One plugin bundles all skills; rely on Claude auto-activating the right skill by description.
- Pro: Simplest; no plumbing.
- Con: No separate install units / branding / discovery per domain; conflates unrelated skills.
Recommendation
Option A (with B as the fallback if Windows contributors/users are in scope). It's the documented mechanism, keeps skills/ canonical for all three runtimes, and needs no content duplication.
Follow-up work if A/B is chosen
References
Context
Today the repo is a single Claude Code marketplace with one plugin:
We expect many plugins in this repo, each bundling a subset of the skills in
skills/, while keepingskills/at the root as the single canonical source so it stays directly consumable by:npx skills/ agentskills.io (readsskills/<name>/SKILL.mdat repo root)Problem / core constraint
The obvious approach — multiple
marketplace.jsonentries all withsource: "./"plus askillsselector — does not subset. Per the Plugins reference:./, and cannot traverse outside it (../shared"will not work after installation because those external files are not copied to the cache"). → #path-traversal-limitationsskillsmanifest field adds to the defaultskills/scan — it does not replace it. → #component-path-fieldsSo any plugin whose root is the repo root auto-discovers the entire root
skills/dir. The current setup only appears to select because there is exactly one skill.Goals
skills/at the repo root as the single source of truth (no duplication of skill content)npx skills/ agentskills.io and a future Codex manifestOptions
Option A — Symlink monorepo (officially documented for this case)
Per-plugin subdirectories; each plugin's
skills/holds symlinks into the canonical rootskills/. On marketplace install, Claude dereferences sibling-marketplace symlinks (copies the real content into its cache). → Share files within a marketplace with symlinksnpx skills/Codex read rootskills/untouched; nostrict:false, no duplicated component lists.core.symlinks=true+ Developer Mode — affects Windows contributors and Windows end users whose Claude fetches the marketplace.claude --plugin-dir <subdir>does not dereference cross-dir symlinks; local testing must use/plugin marketplace add <local path>then install.Option B — Committed generator / copy-sync (Windows-proof)
Same
plugins/<name>/layout, but instead of committing symlinks, commit a smallscripts/link-skills.shdriven by a declared skill list per plugin. Use symlinks for local dev and copy real files at release (or always copy).Option C — Separate sources via
git-subdir/ per-repo pluginsKeep one
marketplace.jsonbut fetch each plugin from its own path/repo usingsource: { "source": "git-subdir", ... }. → Plugin sourcesskills/pool as cleanly; more moving parts.Option D — Single mega-plugin, no subsetting
One plugin bundles all skills; rely on Claude auto-activating the right skill by description.
Recommendation
Option A (with B as the fallback if Windows contributors/users are in scope). It's the documented mechanism, keeps
skills/canonical for all three runtimes, and needs no content duplication.Follow-up work if A/B is chosen
axon4to5intoplugins/axon4to5/marketplace.json(metadata.pluginRoot: "./plugins", one entry per plugin, dropstrict:false)README.mdlocal-test instructions (marketplace addinstead of--plugin-dir)References