installed_plugins.json gitCommitSha is stale — never updates after initial install

Resolved 💬 1 comment Opened May 15, 2026 by asawicki Closed Jun 14, 2026

Summary

~/.claude/plugins/installed_plugins.json records gitCommitSha for each installed plugin entry, but this field is only set on first install and is never updated when the plugin version is bumped or the marketplace is refreshed. Other fields in the same entry (installPath, version, lastUpdated) update correctly. This makes the gitCommitSha audit field misleading — it can even reference a commit that no longer exists in the marketplace repo (after force-push, rebase, or rewrite).

Environment

  • Claude Code: 2.1.142
  • macOS: 26.5 (Build 25F71, Darwin 25.5.0)
  • Affected file: ~/.claude/plugins/installed_plugins.json

Reproduction

  1. Install a plugin from a marketplace when the marketplace HEAD is commit A.
  2. Push new commits + bump the plugin's plugin.json version (e.g., 2.16.0 → 2.16.2) so the marketplace HEAD is now commit B.
  3. Refresh the marketplace and run /reload-plugins (or the equivalent update flow that re-syncs the plugin cache).
  4. Observe installed_plugins.json for the plugin entry.

Expected

The entry's gitCommitSha reflects the commit from which the currently-cached plugin files were copied (i.e., commit B).

Actual

  • installPath: updates to the new version directory (e.g., cache/<marketplace>/<plugin>/2.16.2/) ✓
  • version: updates to the new version (e.g., 2.16.2) ✓
  • lastUpdated: updates to the refresh timestamp ✓
  • gitCommitSha: stays at the original install-time commit A, even though the cached files clearly come from commit B

Concrete evidence

\\\json
"forge@forge-marketplace": [
{
"scope": "user",
"installPath": "/Users/<me>/.claude/plugins/cache/forge-marketplace/forge/2.16.2",
"version": "2.16.2",
"installedAt": "2026-04-04T09:41:56.838Z",
"lastUpdated": "2026-05-15T12:50:27.788Z",
"gitCommitSha": "3423cd5e8e4865debe755acfd375ce62fda7264e"
}
]
\
\\

But:

\\\`bash
$ cd ~/.claude/plugins/marketplaces/forge-marketplace
$ git rev-parse HEAD
24a9d5cbd5d0e26ffb8e63cafaeb6169c31973e5 # <-- actual marketplace HEAD

$ git cat-file -t 3423cd5e
fatal: Not a valid object name 3423cd5e # <-- recorded hash doesn't exist in repo!

$ cat ~/.claude/plugins/cache/forge-marketplace/forge/2.16.2/.claude-plugin/plugin.json | jq -r .version
2.16.2 # <-- cache directory contains the new version
\\\`

The cached files contain code from commit \24a9d5c\, but \installed_plugins.json\ records \gitCommitSha: 3423cd5e\ — a hash that no longer exists in the marketplace repo (because the marketplace repo was later force-pushed / rewritten / had history changed between the initial install in April and now).

Impact

  • Audit trail is misleading. When verifying "which commit of the plugin is currently active," \gitCommitSha\ is the natural field to consult and it lies.
  • No reliable post-hoc provenance. If a user wants to map cached plugin code back to a marketplace commit (for security audit, compliance, or root-cause analysis), the only reliable path is \git log\ on the cached file content, not the recorded field.
  • Especially confusing when the recorded hash is unreachable (force-push, rebased branch, deleted commit) — looks like data corruption.

Suggested fix

Update \gitCommitSha\ on the same trigger that updates \installPath\, \version\, and \lastUpdated\. The current behavior treats \gitCommitSha\ as an install-time-only field, but the surrounding fields are update-aware — the inconsistency is the bug.

Alternatively (lower-impact): rename the field to \installedAtGitCommitSha\ to make the install-time-only semantics explicit, and add a separate \updatedAtGitCommitSha\ that does update.

Workaround

To verify which commit of plugin code is actually active:

\\\bash
ls ~/.claude/plugins/cache/<marketplace>/<plugin>/ # see cached version directories
cat ~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/.claude-plugin/plugin.json
\
\\

…or \git log -1\ on a specific cached file via the marketplace clone.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗