[BUG] Plugin cache creates duplicate directories on every session when ~/.claude is a git repo

Resolved 💬 9 comments Opened Mar 30, 2026 by BizlogicAI Closed May 22, 2026

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?

If ~/.claude is a git repository (common for dotfiles management), the plugin cache system creates a new duplicate cache directory for each enabled marketplace plugin on every session start. Each directory is named after the first 12 characters of ~/.claude's current HEAD commit SHA, even though the plugin content hasn't changed.

Over 30 hours with a single enabled plugin (skill-creator), this produced 22 duplicate directories containing identical files, growing the cache from ~290KB to 6.4MB. A /reload-plugins notification also fires on each session start, which appears to be triggered by the version mismatch.

Root cause: The plugin version computation falls through to reading git HEAD from the marketplace path. When the marketplace directory has no .git of its own (normal state after GCS download), git walks up the directory tree and finds ~/.claude/.git. Every commit to that repo changes HEAD, so the resolved "version" changes on every session, even though the actual plugin is identical.

The plugins/ directory is in ~/.claude/.gitignore, so the marketplace directory isn't even tracked by the parent repo. Git still walks up through it.

What Should Happen?

  1. Plugin cache keys shouldn't depend on an unrelated parent git repository's HEAD
  2. Git HEAD resolution from the marketplace directory shouldn't walk up to ~/.claude/.git
  3. The gitCommitSha field already stored in installed_plugins.json (the actual upstream repo commit) could be used for cache keying instead of re-resolving from the filesystem

Error Messages/Logs

# No error output. The symptom is a /reload-plugins notification and accumulating cache dirs:

~/.claude/plugins/cache/claude-plugins-official/skill-creator/
├── 5f7393c09595/   # Mar 27 - keyed to ~/.claude commit 5f7393c
├── 9e8061ca97b9/   # Mar 29 - keyed to ~/.claude commit 9e8061c
├── a04828cbbe5f/   # Mar 29 - keyed to ~/.claude commit a04828c
├── 555d7d7cbc85/   # Mar 29 - keyed to ~/.claude commit 555d7d7
├── ... (22 directories total in 30 hours)
└── a8369251a9b7/   # Mar 30 - keyed to ~/.claude commit a836925

# All directories contain byte-identical content (~290KB each, 24 files).

# installed_plugins.json shows the mismatch:
{
  "version": "9dcae5dfec9f",
  "gitCommitSha": "79caa0d824acb760fd9c023acb39c6c7da5ee7fc"
}

# "version" (9dcae5dfec9f) matches ~/.claude commit 9dcae5d ("session 19a review logs")
# "gitCommitSha" (79caa0d...) matches upstream commit in anthropics/claude-plugins-official
# The cache key uses the wrong one.

Steps to Reproduce

  1. Initialize ~/.claude as a git repository: cd ~/.claude && git init && git add -A && git commit -m "init"
  2. Install a marketplace plugin: /plugin install skill-creator
  3. Start a session, use it normally, close it
  4. Make a commit to ~/.claude: cd ~/.claude && git add -A && git commit -m "save"
  5. Start a new session
  6. Observe: /reload-plugins notification appears, new cache directory at ~/.claude/plugins/cache/claude-plugins-official/skill-creator/<new-sha>/
  7. Repeat steps 4-6. Each cycle creates another duplicate directory.

Verification that git walk-up is the cause:

# From marketplace dir (no .git of its own), git resolves to ~/.claude HEAD:
$ cd ~/.claude/plugins/marketplaces/claude-plugins-official
$ git rev-parse HEAD
9dcae5dfec9f50d9224069a90bb48957ba8bd1bb   # This is ~/.claude's HEAD, not the plugin's

# Workaround: give the marketplace its own .git
$ git init && git add -A && git commit -m "pin"
$ git rev-parse HEAD
dfe3acfdd1abf1dcc13011cc6b5e9f25c0237072   # Now stable, independent of ~/.claude

# Result: cache dirs stop accumulating (tested over 37 ~/.claude commits, 0 new cache dirs)

Why the workaround doesn't stick: GCS marketplace updates atomically replace the entire directory (extract ZIP to .staging, rename over old dir), wiping the local .git. This happened after 2 days when an upstream marketplace update shipped.

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.86

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

Windows Terminal

Additional Information

Workaround (temporary, re-apply after marketplace updates):

cd ~/.claude/plugins/marketplaces/claude-plugins-official
git init
git config user.name "local"
git config user.email "local@localhost"
git add -A
git commit -m "pin marketplace version"

This gives the marketplace directory its own .git, stopping the upward walk to ~/.claude/.git. The cache key stabilizes and duplicate directories stop accumulating.

To clean up existing duplicates, check which directory installed_plugins.json references (installPath field), then delete the rest from ~/.claude/plugins/cache/claude-plugins-official/<plugin-name>/.

Caveat: This fix gets wiped when the harness downloads a marketplace update from GCS (observed ~2 days after first applying). You'll need to re-run the commands above when the /reload-plugins message reappears.

---

Quantified impact (observed over 30 hours, single plugin):

  • 22 duplicate cache directories created
  • 6.4MB of identical files (290KB x 22)
  • /reload-plugins notification on every session start
  • .orphaned_at markers written on old dirs but cleanup didn't fire during the ~1 hour observation window (may fire on a longer threshold)
  • Impact scales linearly with commit frequency and number of enabled plugins

Evidence the workaround works:

| Period | Marketplace has own .git? | ~/.claude commits | New cache dirs |
|--------|---------------------------|---------------------|----------------|
| Mar 27-29 (fix active) | Yes | 37 | 0 |
| Mar 29-30 (fix wiped by GCS update) | No | ~24 | 22 |

Version 2.1.86 was active for the entire window. v2.1.87 was downloaded on Mar 28 but never launched. The version change can be ruled out as a variable.

SHA mapping: 21 of 23 cache directory names matched specific ~/.claude commit SHAs (first 12 characters). The remaining 2 matched the marketplace's own .git HEAD (created by the workaround), confirming the same mechanism from the other direction.

Who's affected: Anyone whose ~/.claude directory is inside a git repository. This includes dotfiles management via direct git init, stow, yadm, chezmoi, or nix home-manager. Also affects users whose home directory itself is a git repo.

Related issues:

  • #36569 — Stale cached version loaded after update (same .orphaned_at doesn't prevent loading)
  • #29074 — Cache not cleared on uninstall/reinstall
  • #37172, #36938 — plugin update uses stale local cache
  • #39927 — /reload-plugins should re-fetch from remote
  • #612 (claude-plugins-official) — Cache behavior undocumented

Possible fixes:

  1. Use the gitCommitSha from installed_plugins.json for cache keying (it's already stored, just not used for this)
  2. Use .gcs-sha as the version identifier for GCS-sourced marketplaces
  3. Prevent the git directory resolution from walking above the marketplace directory
  4. Write a .git file (even a zero-byte file blocks the walk-up — we tested this) into the marketplace directory after GCS extraction

View original on GitHub ↗

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