[BUG] Local-scope plugin records keyed by subdirectory/worktree path are never updated: `plugin update --scope local` only resolves the main checkout root
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
- Create a git repo
repo/with a subdirectoryrepo/app/and a linked worktree underrepo/.claude/worktrees/wt/. - Start Claude Code in
repo/app/and in the worktree, and install any marketplace plugin at local scope from there. - Wait for the plugin's marketplace version to change. Or install an older version first.
- From
repo/app/, runclaude plugin update <plugin> --scope local. The output is✔ <plugin> is already at the latest version (<new>). - Inspect
installed_plugins.json. The records withprojectPath=repo/appand the worktree still carry the oldversionandinstallPath.
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 localact on the record for the exact current path, and haveplugin listwarn 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