Desktop app embedded loader ignores plugin manifest 'skills' array — serves all repo skills under every plugin, SHA-namespaced (CLI 2.1.206 correct)
Summary
When a marketplace plugin's manifest restricts its skill set via a skills array (repo has a larger skills/ subdir; the array should replace the directory scan), the terminal CLI (2.1.206) honors the array correctly, but the Claude desktop app's embedded Agent SDK loader ignores it: it serves ALL skills found in the cached repo under EVERY plugin from that marketplace, and namespaces them by the install version/SHA directory name instead of the plugin name.
This looks like the same regression that was fixed for the CLI in ~2.1.206 (pre-2.1.206 the CLI also installed/served the full scan), still present in the app-embedded loader.
Environment
- Claude desktop app (macOS): 1.20186.0
claude --version(terminal): 2.1.206- macOS: Darwin 25.5.0
- Marketplace: single GitHub repo with
source: "./"for both plugins, top-levelskills/dir containing 10 skills; plugin A's manifest lists 7 of them in itsskillsarray, plugin B lists the other 3.
Expected (and observed on terminal CLI 2.1.206)
Session skill list contains exactly:
plugin-a:skill1 ... plugin-a:skill7
plugin-b:skill8 plugin-b:skill9 plugin-b:skill10
claude plugin details also reports 7 and 3 correctly.
Actual (desktop app session, same machine, same installed cache)
All 10 skills are served under BOTH plugins (20 entries), and the namespace prefix is the cache version directory name (first 12 chars of the git commit SHA), not the plugin name:
68dfbd7acf1d:skill1
...all 10...
68dfbd7acf1d:skill1 <- repeated block from the second plugin
...all 10 again...
Notes
- The installed cache under
~/.claude/plugins/cache/<marketplace>/<plugin>/<sha>/skills/contains all 10 skill folders for both plugins — expected withsource: "./"(whole repo materialized), since the CLI filters at load time. The app loader appears to scan thatskills/dir wholesale instead of applying the manifest array. - The SHA-based namespacing (
68dfbd7acf1d:instead ofplugin-name:) also breaks any workflow that references skills by their documentedplugin:skillname.
Impact
Audience-scoped plugin splits (e.g. ops skills vs dev skills from one team repo) silently collapse for desktop-app users: everyone gets every skill, and the namespaced names differ between app and CLI sessions on the same machine.
3 Comments
Seeing the same thing on claude.ai web, so this isn't limited to the desktop app's embedded loader. The server-side packaging that builds
/mnt/skillsfor claude.ai chats also ignores the manifestskillsarray.Setup: private company repo, 13 plugins, every plugin has
"source": "./"and an explicitskillsarray of subdirectory paths ("strict": false, noplugin.jsonfiles, no pinned versions). We verified all of this after re-adding the marketplace from scratch on 2026-07-30.skillsarray is parsed and used for the post-install UI, just not by the packager. Users have no way to notice the leak from the UI.mcpServers(Atlassian vs Figma) for their declared skills. With skills leaking into every namespace, a skill ends up under plugins that never declared the MCP server it needs. We haven't checked whethermcpServersget unioned the way skills do, but the declared mapping is broken either way.We haven't re-tested CLI load filtering on this marketplace; all we checked is that
claude plugin validateon 2.1.220 passes it. Related:#13344 (the original CLI report),
#15439 and #53948 (why marketplace authors have no workaround).
Happy to share the full manifest and repro details with maintainers.
Closing for now — inactive for too long. Please open a new issue if this is still relevant.
Re-filed as #96319 with the claude.ai web reproduction and current versions (CLI 2.1.280, desktop 2.7032.0), since this was closed as stale without a maintainer response.