plugin/.claude-plugin/plugin.json pins "version", and Claude Code updates an installed copy only when that version changes. The docs say: "a manifest that pins "version": "1.0.0" keeps every user on the cached copy until its author changes the string, however many commits they push" (https://code.claude.com/docs/en/plugins/loading#how-claude-code-computes-the-version). The bump is done by hand, and no check enforces it.
The history shows plugin changes shipping without a bump. On origin/main, 04f6b1a ("bound what a report carries from a tool's output"), afc3032 and 397cfee ("scrub browser output in one pass") all landed under 0.2.1. 068e63b had already published 0.2.1, so an install from that point kept the copy without those three fixes until 0.3.0 (64446a6, 2026-10-12). Today's head (bdfcd8c, 0.3.4) is bumped, so nothing is stale right now.
One fix is to remove version from the manifest, which is what vibescrobble did in its PR #261 (https://tangled.org/permadeath.com/vibescrobble.com/pulls/261). For a relative-path plugin in a git-hosted marketplace, Claude Code then versions the plugin by the marketplace's commit SHA, shortened to 12 characters. I tested this with Claude Code 2.1.301 in a scratch config: claude plugin marketplace update followed by claude plugin update moved an install from 0.1.0 to 7c106d7ba7a3. Any commit counts as an update, including one outside plugin/. The other fix is to keep the version and add a prek check that fails when plugin/ changes without a bump. Either way, claude plugin update alone reads the marketplace as last fetched, so users need claude plugin marketplace update didbot first, or auto-update turned on.