[BUG] Local-scope plugin records keyed by subdirectory/worktree path are never updated: `plugin update --scope local` only resolves the main checkout root

Status Open
Reported on v2.1.288
Maintainer reply None cached
Activity 0 comments · opened Oct 5, 2026

What's wrong

~/.claude/plugins/installed_plugins.json keeps scope: "local" records whose projectPath is a subdirectory of a git repository or a linked worktree, alongside the record for the main checkout root.

claude plugin update <plugin> --scope local only looks at the main-checkout record. Run from the subdirectory or the worktree, it replies already at the latest version, and the subdirectory/worktree records stay on the old version. There is no warning, and no CLI command can reach them: uninstall --scope local resolves to the same main-checkout record, so it would remove the good one.

claude plugin list --json still lists every stale record as enabled: true.

This is the same family as #52831 (closed by the stale bot, not fixed) and #14202 (still open). #52831 suggests opening a new issue that references it if the problem is still there, which is what this is. #45997 (also closed for inactivity) describes why stale records matter: the loader may read the first array entry without filtering by project.

Why it looks like an inconsistency, not a usage error

The settings docs (https://code.claude.com/docs/en/settings) say:

If you start Claude Code in a subdirectory of a git repository, it reads and writes that file at the repository root […] In a worktree, it uses the file at the main checkout's root.

So local scope is defined by the main checkout root. Yet new local records keyed by a subdirectory or worktree path were still being written as recently as 2026-10-03, which is after the fixes listed in the CHANGELOG.

Steps to reproduce

  1. Create a git repo repo/ with a subdirectory repo/app/ and a linked worktree under repo/.claude/worktrees/wt/.
  2. Start Claude Code in repo/app/ and in the worktree, and install any marketplace plugin at local scope from there.
  3. Wait for the plugin's marketplace version to change. Or install an older version first.
  4. From repo/app/, run claude plugin update <plugin> --scope local. The output is ✔ <plugin> is already at the latest version (<new>).
  5. Inspect installed_plugins.json. The records with projectPath = repo/app and the worktree still carry the old version and installPath.

Expected

Pick one, consistently with the docs:

  • Never write local records keyed by a subdirectory or worktree path. Resolve to the main checkout root, as the settings file already does. Or:
  • Have plugin update/uninstall --scope local act on the record for the exact current path, and have plugin list warn about records that point to the same repository at different versions.

Environment

  • Claude Code 2.1.288 and 2.1.289 (npm global)
  • macOS 27.0.1

View original on GitHub ↗