Summary
~/.claude/plugins/installed_plugins.json on the laptop carries project-scope entries for 15 project paths, each pinning roughly 57 to 65 plugins at the version current when that project first enabled them. Three of those paths no longer exist on disk. The pins never update, so the plugin cache holds 412 version directories (963 MB) and the file keeps growing with every worktree that has a .claude/settings.json enabling the fleet.
Evidence (2026-09-02, Claude Code 2.1.259)
jq over installed_plugins.json: project-scope pins per path: claude-code-plugins 65, six D:\worktrees\ccp-* paths 63-64 each, chezmoi source 63, provisioning 57, and three paths that no longer exist (chezmoi-worktrees\...-feat-cross-platform-wsl, chezmoi\.claude\worktrees\linux-lane-parity, D:\worktrees\dotfiles-statusline).
- guardrails alone: user scope 0.31.2, project pins at 0.29.9, 0.29.12 (x9), 0.30.0 (x6).
- Transcripts from sessions in the claude-code-plugins checkout reference
plugins/cache/melodic-software/guardrails/0.31.1, the user-scope version at the time, so the user scope wins and the pins are not running stale hook code. They are disk and clutter only.
- The plugins reference says orphaned versions are swept about 14 days after an update or uninstall; a project-scope pin is never updated, so nothing ever orphans it.
Why it matters
Every new worktree of a repo whose project settings enable the fleet adds another ~60 pinned installs. The cache never shrinks, installed_plugins.json grows, and claude plugin list prints every pin of every path, which is what makes "which version is running here" hard to answer at a glance.
Suggested handling
- Decide whether project settings should enable plugins at all when the user scope already does; a project
enabledPlugins block that mirrors the user scope buys nothing on a single-operator fleet and is the source of every pin.
- If they stay, add a sweep to the disk-hygiene or claude-ops audit:
claude plugin uninstall <plugin> --scope project for pins whose projectPath no longer exists, and a report of pins that are more than N versions behind the user scope.
- Consider
claude plugin prune --scope project coverage in the same sweep.
Verification
jq -r '.plugins | to_entries[] | .value[] | select(.scope=="project") | .projectPath' ~/.claude/plugins/installed_plugins.json | sort -u lists the paths; test each with Test-Path.
No related issue.
Summary
~/.claude/plugins/installed_plugins.jsonon the laptop carries project-scope entries for 15 project paths, each pinning roughly 57 to 65 plugins at the version current when that project first enabled them. Three of those paths no longer exist on disk. The pins never update, so the plugin cache holds 412 version directories (963 MB) and the file keeps growing with every worktree that has a.claude/settings.jsonenabling the fleet.Evidence (2026-09-02, Claude Code 2.1.259)
jqoverinstalled_plugins.json: project-scope pins per path: claude-code-plugins 65, sixD:\worktrees\ccp-*paths 63-64 each, chezmoi source 63, provisioning 57, and three paths that no longer exist (chezmoi-worktrees\...-feat-cross-platform-wsl,chezmoi\.claude\worktrees\linux-lane-parity,D:\worktrees\dotfiles-statusline).plugins/cache/melodic-software/guardrails/0.31.1, the user-scope version at the time, so the user scope wins and the pins are not running stale hook code. They are disk and clutter only.Why it matters
Every new worktree of a repo whose project settings enable the fleet adds another ~60 pinned installs. The cache never shrinks,
installed_plugins.jsongrows, andclaude plugin listprints every pin of every path, which is what makes "which version is running here" hard to answer at a glance.Suggested handling
enabledPluginsblock that mirrors the user scope buys nothing on a single-operator fleet and is the source of every pin.claude plugin uninstall <plugin> --scope projectfor pins whoseprojectPathno longer exists, and a report of pins that are more than N versions behind the user scope.claude plugin prune --scope projectcoverage in the same sweep.Verification
jq -r '.plugins | to_entries[] | .value[] | select(.scope=="project") | .projectPath' ~/.claude/plugins/installed_plugins.json | sort -ulists the paths; test each withTest-Path.No related issue.