claude-code - 💡(How to fix) Fix [BUG] `claude plugin update` doesn't refresh `gitCommitSha` for directory-source marketplaces [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#54969Fetched 2026-05-01 05:49:41
View on GitHub
Comments
0
Participants
1
Timeline
5
Reactions
0
Participants
Timeline (top)
labeled ×4closed ×1

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.

Root Cause

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).

Fix Action

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.

Code Example

# 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

---

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)
"
RAW_BUFFERClick to expand / collapse

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 — installPath points 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 gitCommitSha for 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

extent analysis

TL;DR

The gitCommitSha field in ~/.claude/plugins/installed_plugins.json is not updated after running claude plugin update for directory-source marketplaces, causing it to become outdated.

Guidance

  • Verify that the issue is specific to directory-source marketplaces by testing with github-typed marketplaces.
  • Consider implementing the proposed fix: refresh gitCommitSha to the current HEAD of the source directory's git repo in the claude plugin update code path.
  • As a temporary workaround, operators can manually edit ~/.claude/plugins/installed_plugins.json after each update using the provided Python script.
  • Review the schema clarification alternative resolution, which suggests renaming the field to originalInstallCommitSha and adding a separate currentSnapshotCommitSha field.

Example

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)
"

Notes

The issue is cosmetic, but it can cause nuisance in forensic debugging and CI/CD systems. The proposed fix and workaround are specific to directory-source marketplaces, and the behavior of github-typed marketplaces is unknown.

Recommendation

Apply the proposed fix: refresh gitCommitSha to the current HEAD of the source directory's git repo in the claude plugin update code path, as it aligns with the natural reading of the field name and matches the behavior of lastUpdated and installPath.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING