[BUG] Installing any plugin pack exposes every skill from every marketplace pack under that plugin's namespace
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
When any plugin pack is installed, Claude Code populates that pack's skill cache with every skill from the entire marketplace — not just the skills the pack declares. Then, since every installed pack gets all skills, each skill appears once per installed pack in the session — so installing 2 packs gives you every skill twice.
Concrete example — I installed jtbd (which should only provide jtbd and jira-ticket-builder) and address-pr-feedback (which should only provide address-pr-feedback):
$ claude plugin install jtbd@gpe-agent-skills
✔ Successfully installed plugin: jtbd@gpe-agent-skills
$ ls ~/.claude/plugins/cache/gpe-agent-skills/jtbd/664e3e83f176/skills
address-pr-feedback arch-review gpe-incident-analysis gper-activity-report gper-idea-creator
jira-ticket-builder jtbd kentik midyear-checkin rhythms-ff-updates servicenow-api ...
$ claude plugin install address-pr-feedback@gpe-agent-skills
✔ Successfully installed plugin: address-pr-feedback@gpe-agent-skills
$ ls ~/.claude/plugins/cache/gpe-agent-skills/address-pr-feedback/664e3e83f176/skills
address-pr-feedback arch-review gpe-incident-analysis gper-activity-report gper-idea-creator
jira-ticket-builder jtbd kentik midyear-checkin rhythms-ff-updates servicenow-api ...
Both packs got the full marketplace dumped into their cache. The result in a Claude Code session — /kentik appears twice, under two different namespaces, even though I never installed kentik:
/kentik (jtbd) Query Kentik for network intelligence...
/kentik (address-pr-feedback) Query Kentik for network intelligence...
Every extra skill consumes context tokens per session. With 2 packs installed and 16 total marketplace skills, that's 32 skill entries loaded instead of 3.
What Should Happen?
Only the skills declared in the installed pack's skills array in marketplace.json should appear under that pack's namespace. Skills from other packs should not be listed at all.
Error Messages/Logs
🔒 on address-pr-feedback:address-pr-feedback · plugin · ~140 tok
🔒 on address-pr-feedback:gpe-incident-analysis · plugin · ~160 tok
🔒 on address-pr-feedback:gpe-sec-exc-report · plugin · ~130 tok
🔒 on address-pr-feedback:gper-activity-report · plugin · ~150 tok
🔒 on address-pr-feedback:gper-ff-updates · plugin · ~130 tok
🔒 on address-pr-feedback:rhythms-ff-updates · plugin · ~130 tok
🔒 on address-pr-feedback:servicenow-api · plugin · ~280 tok
Only address-pr-feedback was installed. The other 6 skills belong to different packs.
Steps to Reproduce
- Create a marketplace with multiple packs, each with a distinct
skillsarray in.claude-plugin/marketplace.json - Install a single pack:
claude plugins install address-pr-feedback@gpe-agent-skills - Open a new Claude Code session
- Observe the skill list — every skill from every other pack in the marketplace appears under the installed pack's namespace
Claude Model
Sonnet (default)
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.153 (Claude Code)
Platform
AWS Bedrock
Operating System
macOS
Terminal/Shell
iTerm2
Additional Information
Previously tracked in #23819 and #27721, both closed as not planned. Suggest reopening because the workaround imposes a real ongoing maintenance burden on marketplace authors.
The only fix is to ship a cache-pruning script that manually deletes leaked skill folders after every claude plugins update. This script duplicates the dependency graph already declared in marketplace.json and must stay in sync by hand:
#!/usr/bin/env bash
# Must re-run after every `claude plugins update`
CACHE_ROOT="${CACHE_ROOT:-$HOME/.claude/plugins/cache/<your-marketplace>}"
keep_regex_for() {
case "$1" in
pack-a) echo '^(pack-a)$' ;;
pack-b) echo '^(pack-b|shared-dep)$' ;;
*) return 1 ;;
esac
}
for pack_dir in "$CACHE_ROOT"/*/; do
pack="$(basename "$pack_dir")"
KEEP_REGEX="$(keep_regex_for "$pack")" || continue
for skills_dir in "$pack_dir"*/skills; do
pushd "$skills_dir" > /dev/null
for f in *; do
echo "$f" | grep -Eq "$KEEP_REGEX" || rm -rf -- "$f"
done
popd > /dev/null
done
done
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗