Plugin skill discovery: multi-scope installs silently load intersection, project-scope leaks across unrelated cwds

Resolved 💬 3 comments Opened Apr 27, 2026 by mcfoton Closed May 29, 2026

Summary

When the same plugin is installed at both project and user scope at different versions, the active skill set in any session equals the intersection of skills present in all scopes, not the union or the higher-precedence scope. Project-scope entries also appear to apply to sessions launched in unrelated working directories, not only inside their pinned projectPath.

Net effect: a freshly added skill in a newer plugin version never appears in /skills, even after /reload-plugins, full restart, version bumps, and re-installs — until the older project-scope entry is removed.

Environment

Repro

  1. Install plugin X@1.0 at project scope inside ~/projA. Plugin has skills a, b.
  2. Add a new skill c to plugin upstream and bump to 1.1.
  3. From any cwd, run /plugin install X@marketplace to install at user scope. ~/.claude/plugins/installed_plugins.json now lists two entries:
  • scope: project, projectPath: ~/projA, version: 1.0
  • scope: user, version: 1.1
  1. cd ~/projB (entirely unrelated to ~/projA).
  2. /skills — only a and b shown. c missing.
  3. /reload-plugins reports 0 skills reloaded; restart Claude Code fully — c still missing.
  4. Bump plugin to 1.2, 1.3 — same. Three round-trip update cycles do not surface c.
  5. Manually remove the project-scope entry from installed_plugins.json and restart — c appears.

Expected

  • Project-scope plugin should only affect sessions whose cwd is inside projectPath.
  • When multiple scopes are present for the same plugin, the higher-precedence scope (typically the more specific one for the cwd) should win — not the intersection.
  • /reload-plugins should rescan skill files on disk and report a non-zero count when new SKILL.md files are present in the active version.

Actual

  • Project-scope shadows user-scope across all sessions regardless of cwd.
  • Loaded skill set = skills(scope_A) ∩ skills(scope_B), silently filtered, no warning.
  • /reload-plugins always reports 0 skills for this plugin even after legitimately new skill files are added; only full restart picks them up, and only after the shadowing scope is removed.

Diagnostic snippet

jq '.plugins["<plugin>@<marketplace>"]' ~/.claude/plugins/installed_plugins.json

If multiple scope entries at different versions exist and the missing skills are exactly those added after the older version, you've hit this bug.

Workaround

Back up installed_plugins.json, drop the stale project-scope entry, restart Claude Code:

cp ~/.claude/plugins/installed_plugins.json{,.bak}
jq '.plugins["X@marketplace"] |= map(select(.scope != "project" or .version != "<old>"))' \
  ~/.claude/plugins/installed_plugins.json > /tmp/p.json && \
  mv /tmp/p.json ~/.claude/plugins/installed_plugins.json

Notes

  • Three PRs against the plugin repo (frontmatter length, embedded quotes, argument-hint removal) were red herrings — the SKILL.md files were valid the whole time. They are recoverable; the underlying issue was the scope merge.
  • /reload-plugins returning 0 skills even when new SKILL.md files exist on disk is the most user-hostile part: it suggests "nothing to refresh" when in fact the loader is silently filtering them out.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗