Plugin cache never prunes superseded version dirs — 4.77 GB stale across 4 marketplaces (incl. first-party), 11 copies of one plugin, no cleanup command (2.1.220)
Corroborates #71074 (bug,area:plugins), still reproducing on 2.1.220. That issue frames the impact as correctness — an agent resolving a skill by directory listing loads a stale version. This report adds the other half: disk cost at scale, across vendors, with no native way to clean it up — plus a second-order failure where stale directories turn a third-party plugin's version-selection bug into an unbounded process leak. Merge into #71074 if that's more useful; the evidence below is the part I couldn't find recorded anywhere.
Environment
- Claude Code 2.1.220
- macOS 15.7.7, Apple Silicon (arm64)
- 17 plugins installed across 6 marketplaces
Summary
claude plugin update writes the new version to cache/<marketplace>/<plugin>/<version>/ and never removes the predecessor. Old version directories accumulate indefinitely. On this machine that is 4.77 GB of stale plugin versions, one plugin holding 10 dead copies.
This is not vendor-specific — it reproduces across four unrelated marketplaces, including the first-party claude-plugins-official:
| Marketplace / plugin | Versions on disk | Stale | Wasted |
|---|---|---|---|
| claude-plugins-official/superpowers | 2 | 6.1.1 | 2 MB |
| context-mode/context-mode | 3 | 1.0.126, 1.0.168 | ~1 MB |
| nyldn-plugins/octo | 4 | 9.45.0, 9.52.0, 9.54.0 | 47 MB |
| thedotmack/claude-mem | 11 | everything below 13.12.4 | 4.3 GB |
| | | total | 4.77 GB |
$ ls ~/.claude/plugins/cache/thedotmack/claude-mem/
13.8.0 13.8.1 13.10.2 13.10.3 13.10.4 13.11.0
13.12.0 13.12.1 13.12.2 13.12.3 13.12.4 <- only this one is referenced
installed_plugins.json points at exactly one of these:
"claude-mem@thedotmack": [{
"installPath": ".../cache/thedotmack/claude-mem/13.12.4",
"version": "13.12.4",
"installedAt": "2026-04-08T16:57:50.535Z",
"lastUpdated": "2026-07-23T22:49:23.338Z"
}]
The other ten directories are unreferenced by any config and unused by any running process — pure dead weight at ~480 MB each.
Why the size varies so much
Plugins that vendor a runtime pay this per update. claude-mem ships a bundled dependency tree at ~480 MB, so eleven updates cost 5.2 GB; octo costs 16 MB a time and nobody notices. The bug is uniform — only the blast radius differs. Any plugin that vendors node_modules or a binary toolchain turns routine updates into multi-GB growth.
Second-order failure: stale dirs become a process leak
Worth flagging because it's how I found this. claude-mem selects its worker version by directory mtime rather than semver (thedotmack/claude-mem#3298). Left-behind directories are therefore not inert — they're live candidates in that selection. On this machine 13.12.3 and 13.12.4 carry an identical mtime (Jul 23 15:49:23), which is exactly the tie that bug trips on.
The downstream effect: a recycle loop that respawned chroma-mcp subprocesses across five distinct build generations and orphaned them to PID 1 — 22 leaked process pairs, oldest 8 days, which had accumulated ~8 GB of swap (confirmed: swap dropped from 24 GB → 16 GB after reaping them). Details in thedotmack/claude-mem#3413.
That specific selection bug is the plugin's to fix and it is filed there. The point here is that leftover version directories are not harmless — the harness is leaving loaded guns around for plugins to pick up. Pruning on update defuses an entire class of "wrong version got selected" bugs (including #71074's own reported failure) regardless of how carelessly a plugin resolves its own path.
No native cleanup path
claude plugin has no cache subcommand:
$ claude plugin --help
Commands: details, disable, enable, eval, help, init|new, install|i, ...
So the only remedy is hand-rolled rm -rf against a path users must first reverse-engineer, while correctly avoiding the active version, any version a running process is executing from, and (for git-sourced plugins) the temp_* staging clones that leak alongside them — see #80367 and #76240.
Steps to reproduce
- Install any plugin from a marketplace.
- Update it several times (
claude plugin update <name>, or let auto-update run). ls ~/.claude/plugins/cache/<marketplace>/<plugin>/— every version ever installed is still present.- Compare against
installed_plugins.json::installPath— exactly one is referenced.
Quick audit across all installed plugins:
for p in ~/.claude/plugins/cache/*/*/; do
n=$(ls -1 "$p" | grep -cE '^[0-9]+\.[0-9]+\.[0-9]+$')
[ "$n" -gt 1 ] && echo "$n versions: $p"
done
Expected
After a successful update, remove the superseded version directory. If keeping one previous version for rollback is desirable, cap it at N=1 and prune the rest.
Failing that, a claude plugin cache prune subcommand that keeps only what installed_plugins.json references and skips versions with running processes would at least make this self-serviceable — right now there is nothing to point users at.
🤖 Filed with the help of Claude Code