Preflight Checklist
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:
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 default skills/)
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):'
Expected: 4 entries under document-skills:, 1 under claude-api:. Observed: 17 under each.
-
Sha256-verify the duplication is at the file level, not just the namespace:
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.json to 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.json plugins[].skills (and commands, agents, hooks, etc.) when present, the same way per-plugin plugin.json overrides default auto-discovery. This is the more defensible interpretation given the parallel field names.
- (b) Docs fix + upstream restructure — declare
marketplace.json plugins[].skills is metadata-only; reorganize anthropics/skills so each plugin has its own source subdirectory (./document-skills/, ./example-skills/, ./claude-api/) with per-plugin plugin.json files.
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-skills and claude-api from the official Anthropic marketplace get 17 skills loaded twice, doubling their contribution to the in-context skills budget (per skills.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-api exists but is not what document-skills was 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 doctor does 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-permissions mode under op run env wrapper
- Affected marketplace:
anthropic-agent-skills (https://github.com/anthropics/skills) at commit 5128e1865d67
- Affected plugins:
document-skills@anthropic-agent-skills, claude-api@anthropic-agent-skills
Related issues
Related upstream
If the resolution path is (b), file a paired issue against anthropics/skills to restructure the marketplace into per-plugin source subdirs.
Preflight Checklist
What's Wrong?
When a
marketplace.jsondeclares multiple plugin entries that share the samesource: "./"(i.e. point at the marketplace root) and use the per-entryskills:array to express disjoint skill subsets, all installed plugins load all skills from the sharedskills/directory, not the declared subset.This is observable today on the official
anthropic-agent-skillsmarketplace (anthropics/skills). Itsmarketplace.jsondeclares three plugins from a shared source:Observed: each installed plugin registers all 17 skills under its own namespace, not its declared subset.
marketplace.jsonskills:(intended)document-skills@anthropic-agent-skillsclaude-api@anthropic-agent-skillsBoth
/document-skills:claude-apiand/claude-api:claude-apiexist, with byte-identicalSKILL.mdcontent (verified via sha256).What Should Happen?
The
marketplace.jsonplugins[].skillsarray should act as a load-time filter, mirroring the per-pluginplugin.jsonskillsfield which is documented inplugins-reference.mdas:For
document-skills, onlyxlsx,docx,pptx,pdfshould register as/document-skills:*skills./document-skills:claude-apishould not exist.If the current behavior is by design, then the docs at
plugin-marketplaces.mdshould explicitly state thatmarketplace.jsonplugins[].skillsis metadata-only (catalog hints, not a runtime filter). Today the field's description ("Custom paths to skill directories containing<name>/SKILL.md") parallels theplugin.jsonfield but omits the "replaces default" parenthetical, leaving the semantics ambiguous.Steps to Reproduce
Add the marketplace and install both plugins:
List skills under each namespace:
Expected: 4 entries under
document-skills:, 1 underclaude-api:. Observed: 17 under each.Sha256-verify the duplication is at the file level, not just the namespace:
Result: all 17 byte-identical.
Inspect
marketplace.jsonto confirm the declared subset is not what loaded:Root Cause Hypothesis
Per
plugins-reference.md"Plugin manifest schema":None of the three plugins in
anthropic-agent-skillsship a per-plugin.claude-plugin/plugin.json— only the marketplace's catalogmarketplace.jsonexists. So at install/load time, each plugin appears manifest-less and falls through to auto-discovery, which scans the entire sharedskills/directory.Two possible fixes:
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.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
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)./document-skills:claude-apiexists but is not whatdocument-skillswas supposed to ship.claude doctordoes not surface this kind of in-namespace duplication today; the bug is silent until the user runs sha256 diffs.Environment
--dangerously-skip-permissionsmode underop runenv wrapperanthropic-agent-skills(https://github.com/anthropics/skills) at commit5128e1865d67document-skills@anthropic-agent-skills,claude-api@anthropic-agent-skillsRelated issues
/reviewvia unqualified resolutionRelated upstream
If the resolution path is (b), file a paired issue against anthropics/skills to restructure the marketplace into per-plugin source subdirs.