claude-code - 💡(How to fix) Fix [BUG] Stale plugin installs from abandoned git worktrees silently break TUI slash-command autocomplete [2 comments, 2 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#52831Fetched 2026-04-25 06:19:44
View on GitHub
Comments
2
Participants
2
Timeline
10
Reactions
0
Timeline (top)
labeled ×5referenced ×3commented ×2

Error Message

  1. claude plugin list should deduplicate or warn when the same plugin namespace has multiple enabled install entries across scopes within a single project tree, naming the install paths (e.g. main project root vs .claude/worktrees/upbeat-keller) and suggesting claude plugin uninstall --scope project from the stale location.

Error Messages/Logs

No error messages — this is a silent failure. The diagnostic evidence is in claude plugin list output showing duplicate rows at different versions, and in ~/.claude/plugins/installed_plugins.json retaining the stale entry.

Root Cause

Environment

  • macOS 15.3 (Darwin 25.3.0, arm64)
  • Claude Code 2.1.119
  • Plugin: wr-itil@windyroad (reproduced on @windyroad/itil package, relevant because it adds new skills across versions; same mechanism should apply to any plugin)
  • Marketplace: GitHub-hosted windyroad marketplace cloned to ~/.claude/plugins/marketplaces/windyroad/

Code Example

❯ wr-itil@windyroad
  Version: 0.1.0
  Scope: project
  Status: ✔ enabled

❯ wr-itil@windyroad
  Version: 0.18.1
  Scope: project
  Status: ✔ enabled

... (six more rows at 0.18.1, one per sibling project)

---

"wr-itil@windyroad": [
  {
    "scope": "project",
    "projectPath": "/Users/tomhoward/Projects/windyroad-claude-plugin/.claude/worktrees/upbeat-keller",
    "installPath": "/Users/tomhoward/.claude/plugins/cache/windyroad/wr-itil/0.1.0",
    "version": "0.1.0",
    "installedAt": "2026-04-18T07:09:24.311Z",
    "lastUpdated": "2026-04-18T07:09:24.311Z"
  },
  {
    "scope": "project",
    "projectPath": "/Users/tomhoward/Projects/windyroad-claude-plugin",
    "installPath": "/Users/tomhoward/.claude/plugins/cache/windyroad/wr-itil/0.18.1",
    "version": "0.18.1",
    "installedAt": "2026-04-24T08:16:07.284Z",
    ...
  }
]
RAW_BUFFERClick to expand / collapse

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • I am using the latest version of Claude Code

What's Wrong?

When a git worktree is created inside a plugin-enabled project and a plugin is installed (project scope) inside the worktree at version N, the install is registered in ~/.claude/plugins/installed_plugins.json against the worktree path. The entry is never cleaned up when the worktree is abandoned — neither git worktree remove nor subsequent /plugin install on the outer project at version N+k causes the stale row to drop.

The stale row stays flagged enabled in the registry. At the next session start, claude plugin list shows two rows for the same plugin at different versions (the stale N and the current N+k), both "enabled", both "project scope". From there, TUI slash-command autocomplete and the agent-side skill enumerator disagree on which skill list to present:

  • TUI autocomplete reads the first matching install entry for the plugin namespace and uses that version's skill list. If the first match is the stale N (which ships fewer skills than N+k), skills added in N+1..N+k are silently absent from the / dropdown.
  • Agent-side skill enumerator takes the union across all installs of the same plugin namespace. The agent sees all 13 skills and Skill(skill: "wr-itil:report-upstream") works.

Net user-visible symptom: a plugin skill that was recently added, and that definitely ships in the installed plugin cache, silently fails to appear in slash-command autocomplete while being invocable by the agent. The user cannot discover it via /. It took two full debug rounds on my side (architect review + JTBD review + a release to npm + reinstall + restart + re-test) to rule out the red-herring hypothesis (the plugin's own SKILL.md frontmatter) before landing on the actual cause (stale installed_plugins.json row pinned to a dormant worktree).

What Should Happen?

Pick any of these; ideally all three:

  1. claude plugin list should deduplicate or warn when the same plugin namespace has multiple enabled install entries across scopes within a single project tree, naming the install paths (e.g. main project root vs .claude/worktrees/upbeat-keller) and suggesting claude plugin uninstall --scope project from the stale location.
  2. TUI and agent skill enumerators should agree on skill visibility. Whatever resolution strategy is chosen (prefer-newest, prefer-outermost-scope, union, etc.), both surfaces should use the same one. A silent invisibility on / combined with agent invocability is the worst-of-both failure mode and very hard to diagnose.
  3. git worktree remove (or a Claude Code /plugin equivalent) should cascade-cleanup the worktree's plugin installs from installed_plugins.json. Abandoned worktrees should not leave dangling registry rows indefinitely; mine was six days old and still flagged enabled.

Error Messages/Logs

No error messages — this is a silent failure. The diagnostic evidence is in claude plugin list output showing duplicate rows at different versions, and in ~/.claude/plugins/installed_plugins.json retaining the stale entry.

❯ wr-itil@windyroad
  Version: 0.1.0
  Scope: project
  Status: ✔ enabled

❯ wr-itil@windyroad
  Version: 0.18.1
  Scope: project
  Status: ✔ enabled

... (six more rows at 0.18.1, one per sibling project)

And in installed_plugins.json:

"wr-itil@windyroad": [
  {
    "scope": "project",
    "projectPath": "/Users/tomhoward/Projects/windyroad-claude-plugin/.claude/worktrees/upbeat-keller",
    "installPath": "/Users/tomhoward/.claude/plugins/cache/windyroad/wr-itil/0.1.0",
    "version": "0.1.0",
    "installedAt": "2026-04-18T07:09:24.311Z",
    "lastUpdated": "2026-04-18T07:09:24.311Z"
  },
  {
    "scope": "project",
    "projectPath": "/Users/tomhoward/Projects/windyroad-claude-plugin",
    "installPath": "/Users/tomhoward/.claude/plugins/cache/windyroad/wr-itil/0.18.1",
    "version": "0.18.1",
    "installedAt": "2026-04-24T08:16:07.284Z",
    ...
  }
]

Steps to Reproduce

  1. Create a plugin-enabled project with a marketplace plugin registered; install the plugin at some version N. Confirm it works.
  2. Create a git worktree inside the project: git worktree add .claude/worktrees/test-wt.
  3. From inside the worktree, install the same plugin at project scope: (cd .claude/worktrees/test-wt && claude plugin install <plugin>@<marketplace> --scope project).
  4. Publish a new version N+k of the plugin that adds at least one new skill. Reinstall in the outer project: claude plugin uninstall <plugin>@<marketplace> --scope project && claude plugin install <plugin>@<marketplace> --scope project.
  5. Restart Claude Code (full quit + reopen).
  6. Observe:
    • claude plugin list shows both version N and N+k as enabled project-scope entries.
    • In the TUI, type /<plugin-prefix>:<new-skill-prefix>. The new skill does not appear in autocomplete. Only the skills present in version N appear (as fuzzy matches against other prefixes).
    • From the agent side, Skill(skill: "<plugin>:<new-skill>") works — the skill is fully invokable.
  7. Remove the worktree install: (cd .claude/worktrees/test-wt && claude plugin uninstall <plugin>@<marketplace> --scope project). Restart Claude Code. The new skill now appears in / autocomplete.

Claude Model

Not sure / Multiple models

Is this a regression?

I don't know

Last Working Version

No response

Claude Code Version

2.1.119

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

VS Code integrated terminal

Additional Information

Environment

  • macOS 15.3 (Darwin 25.3.0, arm64)
  • Claude Code 2.1.119
  • Plugin: wr-itil@windyroad (reproduced on @windyroad/itil package, relevant because it adds new skills across versions; same mechanism should apply to any plugin)
  • Marketplace: GitHub-hosted windyroad marketplace cloned to ~/.claude/plugins/marketplaces/windyroad/

Related existing issues (family — different triggers, same registry-staleness surface):

  • #43763installed_plugins.json not updated when project marketplace plugin version changes
  • #52218 — Plugin autoUpdate doesn't update installed_plugins.json, leaving bundled hooks pinned to stale installPath
  • #47077 — Plugin marketplace removal leaves orphaned cache and data directories
  • #51008 — Skills appear duplicated/triplicated in the slash command list (inverse symptom of the same enumerator-over-multiple-installs behaviour)
  • #41828 — Slash command exact match should take priority over fuzzy match (amplifies the silent-failure mode: /<prefix>:<exact-skill> shows only fuzzy matches on other skills when the exact match has been filtered by the stale-install shadowing)
  • #49669extraKnownMarketplaces directory source resolves against main repo root instead of worktree root (adjacent worktree-plugin-path mishandling)

This ticket focuses specifically on the worktree-accumulation case: a plugin install registered against an abandoned worktree directory persists and silently shadows the outer project's newer install for TUI autocomplete while remaining invisible to the user's normal diagnostic instincts (searching for "missing skill" doesn't turn up the stale-install mechanism).

Cross-reference

Reported from https://github.com/windyroad/agent-plugins. This issue is tracked locally as P113 in the downstream project's docs/problems/ directory: https://github.com/windyroad/agent-plugins/blob/main/docs/problems/113-wr-itil-report-upstream-missing-from-slash-command-autocomplete.closed.md

extent analysis

TL;DR

The issue can be resolved by cleaning up stale plugin install entries from installed_plugins.json when a git worktree is removed.

Guidance

  • Identify and remove stale plugin install entries from installed_plugins.json that are associated with abandoned worktrees.
  • Modify the claude plugin uninstall command to cleanup plugin installs from installed_plugins.json when a worktree is removed.
  • Update the TUI and agent-side skill enumerators to agree on skill visibility, potentially by using a consistent resolution strategy such as preferring the newest version.
  • Consider adding a warning or deduplication mechanism to claude plugin list when multiple enabled install entries are found for the same plugin namespace.

Example

No code snippet is provided as the issue is more related to the logic and workflow of the plugin management system.

Notes

The issue is specific to the worktree-accumulation case, where a plugin install registered against an abandoned worktree directory persists and silently shadows the outer project's newer install. The provided steps to reproduce and environment information are helpful in understanding the issue.

Recommendation

Apply a workaround by manually cleaning up stale plugin install entries from installed_plugins.json when a git worktree is removed, until a permanent fix is implemented to automatically handle this scenario.

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

claude-code - 💡(How to fix) Fix [BUG] Stale plugin installs from abandoned git worktrees silently break TUI slash-command autocomplete [2 comments, 2 participants]