[BUG] Stale plugin installs from abandoned git worktrees silently break TUI slash-command autocomplete
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?
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:
claude plugin listshould 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 suggestingclaude plugin uninstall --scope projectfrom the stale location.- 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. git worktree remove(or a Claude Code/pluginequivalent) should cascade-cleanup the worktree's plugin installs frominstalled_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
- Create a plugin-enabled project with a marketplace plugin registered; install the plugin at some version N. Confirm it works.
- Create a git worktree inside the project:
git worktree add .claude/worktrees/test-wt. - From inside the worktree, install the same plugin at project scope:
(cd .claude/worktrees/test-wt && claude plugin install <plugin>@<marketplace> --scope project). - 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. - Restart Claude Code (full quit + reopen).
- Observe:
claude plugin listshows 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.
- 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/itilpackage, relevant because it adds new skills across versions; same mechanism should apply to any plugin) - Marketplace: GitHub-hosted
windyroadmarketplace cloned to~/.claude/plugins/marketplaces/windyroad/
Related existing issues (family — different triggers, same registry-staleness surface):
- #43763 —
installed_plugins.jsonnot updated when project marketplace plugin version changes - #52218 — Plugin
autoUpdatedoesn't updateinstalled_plugins.json, leaving bundled hooks pinned to staleinstallPath - #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) - #49669 —
extraKnownMarketplacesdirectory 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
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗