[BUG] marketplace.json plugins[].skills filter ignored when entries share source root and ship no plugin.json (anthropic-agent-skills repro)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported (closest matches: #43297 — different bug, cross-marketplace conflation; #41890 / #50486 / #50488 — namespacing/aliasing ergonomics; none describe the shared-source pattern below)
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code (2.1.119)
What's Wrong?
When a marketplace.json declares multiple plugin entries that share the same source: "./" (i.e. point at the marketplace root) and use the per-entry skills: array to express disjoint skill subsets, **all installed plugins load all skills from the shared skills/ directory**, not the declared subset.
This is observable today on the official anthropic-agent-skills marketplace (anthropics/skills). Its marketplace.json declares three plugins from a shared source:
// .claude-plugin/marketplace.json (excerpt)
"plugins": [
{ "name": "document-skills", "source": "./", "skills": ["./skills/xlsx", "./skills/docx", "./skills/pptx", "./skills/pdf"] }, // intended: 4
{ "name": "example-skills", "source": "./", "skills": ["./skills/algorithmic-art", "./skills/brand-guidelines", /* ... 12 total */] }, // intended: 12
{ "name": "claude-api", "source": "./", "skills": ["./skills/claude-api"] } // intended: 1
]
Observed: each installed plugin registers all 17 skills under its own namespace, not its declared subset.
| Plugin | marketplace.json skills: (intended) | Skills actually registered |
|---|---|---|
| document-skills@anthropic-agent-skills | 4 (xlsx, docx, pptx, pdf) | 17 |
| claude-api@anthropic-agent-skills | 1 (claude-api) | 17 |
Both /document-skills:claude-api and /claude-api:claude-api exist, with byte-identical SKILL.md content (verified via sha256).
What Should Happen?
The marketplace.json plugins[].skills array should act as a load-time filter, mirroring the per-plugin plugin.json skills field which is documented in plugins-reference.md as:
skills| string\|array | Custom skill directories containing<name>/SKILL.md(replaces defaultskills/)
For document-skills, only xlsx, docx, pptx, pdf should register as /document-skills:* skills. /document-skills:claude-api should not exist.
If the current behavior is by design, then the docs at plugin-marketplaces.md should explicitly state that marketplace.json plugins[].skills is metadata-only (catalog hints, not a runtime filter). Today the field's description ("Custom paths to skill directories containing <name>/SKILL.md") parallels the plugin.json field but omits the "replaces default" parenthetical, leaving the semantics ambiguous.
Steps to Reproduce
- Add the marketplace and install both plugins:
````
/plugin marketplace add anthropics/skills
/plugin install document-skills@anthropic-agent-skills
/plugin install claude-api@anthropic-agent-skills
- List skills under each namespace:
```
/skills | grep -E '^/(document-skills|claude-api):'
document-skills:
Expected: 4 entries under , 1 under claude-api:`. Observed: 17 under each.
- Sha256-verify the duplication is at the file level, not just the namespace:
``bash``
for s in algorithmic-art brand-guidelines canvas-design claude-api doc-coauthoring \
docx frontend-design internal-comms mcp-builder pdf pptx skill-creator \
slack-gif-creator theme-factory web-artifacts-builder webapp-testing xlsx; do
a=$(shasum -a 256 ~/.claude/plugins/cache/anthropic-agent-skills/document-skills/*/skills/$s/SKILL.md | awk '{print $1}')
b=$(shasum -a 256 ~/.claude/plugins/cache/anthropic-agent-skills/claude-api/*/skills/$s/SKILL.md | awk '{print $1}')
[ "$a" = "$b" ] && echo "IDENTICAL $s" || echo "DIVERGENT $s"
done
Result: all 17 byte-identical.
- Inspect
marketplace.jsonto confirm the declared subset is not what loaded:
````
cat ~/.claude/plugins/cache/anthropic-agent-skills/document-skills/*/.claude-plugin/marketplace.json
Root Cause Hypothesis
Per plugins-reference.md "Plugin manifest schema":
The manifest is optional. If omitted, Claude Code auto-discovers components in default locations and derives the plugin name from the directory name.
None of the three plugins in anthropic-agent-skills ship a per-plugin .claude-plugin/plugin.json — only the marketplace's catalog marketplace.json exists. So at install/load time, each plugin appears manifest-less and falls through to auto-discovery, which scans the entire shared skills/ directory.
Two possible fixes:
- (a) Runtime fix — when constructing a plugin's component set, give precedence to
marketplace.jsonplugins[].skills(andcommands,agents,hooks, etc.) when present, the same way per-pluginplugin.jsonoverrides default auto-discovery. This is the more defensible interpretation given the parallel field names. - (b) Docs fix + upstream restructure — declare
marketplace.jsonplugins[].skillsis metadata-only; reorganizeanthropics/skillsso each plugin has its own source subdirectory (./document-skills/,./example-skills/,./claude-api/) with per-pluginplugin.jsonfiles.
Either way addresses the user-visible symptom. (a) is preferable because it preserves the existing marketplace structure and matches the authoring intent expressed in the catalog.
Impact
- Users who install both
document-skillsandclaude-apifrom the official Anthropic marketplace get 17 skills loaded twice, doubling their contribution to the in-context skills budget (perskills.md, default 8000 chars or 1% of context window — easy to truncate with ~120 plugin-shipped skills typical of a power-user setup). - Surprising namespacing:
/document-skills:claude-apiexists but is not whatdocument-skillswas supposed to ship. - Cross-marketplace impact: any third-party marketplace using the shared-source pattern (legitimately, e.g. for monorepo authoring convenience) inherits the same surprise.
claude doctordoes not surface this kind of in-namespace duplication today; the bug is silent until the user runs sha256 diffs.
Environment
- Claude Code version: 2.1.119
- OS: macOS Tahoe (Darwin 25.4.0, arm64)
- Node: managed via asdf
- Auth:
--dangerously-skip-permissionsmode underop runenv wrapper - Affected marketplace:
anthropic-agent-skills(https://github.com/anthropics/skills) at commit5128e1865d67 - Affected plugins:
document-skills@anthropic-agent-skills,claude-api@anthropic-agent-skills
Related issues
- #43297 — Marketplace plugin skill silently mapped to official plugin skill (cross-marketplace conflation; same family, different surface)
- #41890 / #50486 / #50488 — plugin skill namespacing and autocomplete-alias ergonomics
- #48750 — plugin skill shadows built-in
/reviewvia unqualified resolution
Related upstream
If the resolution path is (b), file a paired issue against anthropics/skills to restructure the marketplace into per-plugin source subdirs.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗