[BUG] `claude plugin update` doesn't refresh `gitCommitSha` for directory-source marketplaces
Summary
When a plugin installed from a directory-source marketplace is updated via claude plugin update <plugin>@<marketplace>, three of the four mutable fields in ~/.claude/plugins/installed_plugins.json refresh correctly (version, installPath, lastUpdated) but gitCommitSha stays pinned at the SHA captured at original install time. After many consecutive updates the field becomes increasingly misleading — it suggests the install came from a commit that pre-dates almost everything in the loaded code.
The actual loaded code is current (the cache snapshot at the new installPath contains the up-to-date plugin source), so this is a metadata-only issue. But the field is the natural answer to "which commit produced the installed code?" and the wrong answer there is bad for forensic debugging.
Reproduction
Tested on Claude Code 2.1.119, macOS, with a directory-source marketplace pointing at a local repo that has shipped multiple version bumps.
# Initial install when the source repo is at v0.5.0 / commit 8f42848
$ claude plugin install doc-authoring@doc-authoring-local
$ jq '.plugins["doc-authoring@doc-authoring-local"][0]' ~/.claude/plugins/installed_plugins.json
{
"version": "0.5.0",
"installPath": ".../cache/doc-authoring-local/doc-authoring/0.5.0",
"installedAt": "2026-04-27T09:44:13Z",
"lastUpdated": "2026-04-27T09:44:13Z",
"gitCommitSha": "8f42848fd71d3b87b6006d21d3727393101fd711"
}
# Source repo advances to v0.6.0 / commit 6cf0d57; refresh marketplace + update
$ claude plugin marketplace update doc-authoring-local
$ claude plugin update doc-authoring@doc-authoring-local
$ jq '.plugins["doc-authoring@doc-authoring-local"][0]' ~/.claude/plugins/installed_plugins.json
{
"version": "0.6.0", # ✅ refreshed
"installPath": ".../cache/doc-authoring-local/doc-authoring/0.6.0", # ✅ refreshed
"installedAt": "2026-04-27T09:44:13Z", # (correctly preserved)
"lastUpdated": "2026-04-30T05:51:27Z", # ✅ refreshed
"gitCommitSha": "8f42848fd71d3b87b6006d21d3727393101fd711" # ❌ still v0.5.0 commit
}
# Repeat for v0.6.1, v0.6.2, v0.6.3, v0.7.0, v0.7.1, v0.8.0, v0.8.1, v0.8.2, v0.9.0
# gitCommitSha never updates, despite each update creating a new cache snapshot
After 10 consecutive claude plugin update invocations across version bumps 0.5.0 → 0.9.0, the field still reports 8f42848 (the v0.5.0 commit). The current source HEAD is now a12adf0 (v0.9.0).
Expected behaviour
When claude plugin update creates a new cache snapshot from a directory-source marketplace, the gitCommitSha field should be refreshed to reflect the current HEAD of the source directory's git repo. This matches the natural reading of the field name and matches what lastUpdated and installPath are already doing.
Actual behaviour
gitCommitSha is written once at install time and never refreshed by subsequent claude plugin update invocations (at least for directory-typed marketplaces; I haven't tested github-typed marketplaces which may behave differently because they pin to refs explicitly).
Impact
- Severity: cosmetic. The actual loaded code is current —
installPathpoints at the up-to-date cache snapshot. - Nuisance value: medium. The field is the obvious place an operator would look to answer "what commit am I running?" — getting a stale SHA back is misleading.
- Affected workflows: forensic debugging where someone tries to map the installed version to a git commit; CI/CD systems that record
gitCommitShafor audit trails; release-engineering scripts that diff installed code against a reference commit.
Proposed fix
In the claude plugin update code path, when the marketplace source type is directory, refresh gitCommitSha to the current HEAD of the source directory's git repo (use git -C <source-path> rev-parse HEAD). Apply the refresh in the same write that already updates version, installPath, and lastUpdated.
For github and git source types, the existing behaviour may already be correct (the SHA is pinned to whatever ref was checked out at install time) — but worth verifying that update against a moving branch reference also refreshes the SHA.
Workaround
Operators can manually edit ~/.claude/plugins/installed_plugins.json after claude plugin update:
SHA=$(git -C /path/to/source rev-parse HEAD)
python3 -c "
import json
path = '$HOME/.claude/plugins/installed_plugins.json'
with open(path) as f: data = json.load(f)
data['plugins']['<plugin>@<marketplace>'][0]['gitCommitSha'] = '$SHA'
with open(path, 'w') as f: json.dump(data, f, indent=2)
"
This is per-update manual labour and not a tractable workaround for users with multiple directory-source plugins or frequent updates.
Schema clarification (alternative resolution)
If the design intent is that gitCommitSha records the original install commit (rather than the current cache-snapshot commit), consider renaming the field to originalInstallCommitSha and adding a separate currentSnapshotCommitSha field that does refresh. That would make the semantics explicit and solve the "wrong answer to a natural question" framing without changing the existing field's behaviour.
Environment
- Claude Code:
2.1.119 - OS: macOS (Darwin 25.4.0)
- Marketplace source type:
directory - Reproducible across all 10 plugin-update events tested in a single session
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗