claude-code - 💡(How to fix) Fix Plugin manager: expose a `post-update` migration hook for breaking plugin redesigns [1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

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#58882Fetched 2026-05-14 03:37:06
View on GitHub
Comments
1
Participants
2
Timeline
6
Reactions
0
Timeline (top)
labeled ×3cross-referenced ×2commented ×1

When a plugin ships a major-version update that fundamentally changes the agent surface (e.g. 80 specialist agents → 1 orchestrator + 17 commands, or vice versa), the plugin manager has no way for the plugin author to declare cleanup actions that should run once on the upgrade boundary. The result is that the new version installs alongside the old, both directories survive on disk (one orphan-flagged but not garbage-collected — see companion issue #1), and external tooling that assumes the old layout can silently keep the old version "hot" by walking the cache directory.

Root Cause

When a plugin ships a major-version update that fundamentally changes the agent surface (e.g. 80 specialist agents → 1 orchestrator + 17 commands, or vice versa), the plugin manager has no way for the plugin author to declare cleanup actions that should run once on the upgrade boundary. The result is that the new version installs alongside the old, both directories survive on disk (one orphan-flagged but not garbage-collected — see companion issue #1), and external tooling that assumes the old layout can silently keep the old version "hot" by walking the cache directory.

Fix Action

Fix / Workaround

  • v4.0.0 was orphan-flagged by the plugin manager (incorrectly — the user had it enabled in enabledPlugins).
  • v3.2.0 was retained in cache with live .in_use/<pid> locks.
  • An installer-side shell script (~/.claude/.a11y-agent-team-update.sh) installed during v3.x ran nightly via launchd and re-populated agent files into the plugin cache, picking v3.2.0 alphabetically.
  • The combined effect was that a session loading the plugin would see the v3.2.0 agent registry — the 80-specialist surface — even though plugin.json declared v4.0.0 with 1 agent.
  • The user saw a "cumulative agent descriptions ~15.5k > 15.0k tokens" warning every session and was unable to resolve it without manually patching the updater script, manually orphan-flag-clearing v4.0.0, and manually deleting the legacy launchd plist.

Code Example

{
  "name": "accessibility-agents",
  "version": "4.0.0",
  "hooks": {
    "post-update": "scripts/post-update.sh",
    "post-uninstall": "scripts/post-uninstall.sh"
  }
}
RAW_BUFFERClick to expand / collapse

Plugin manager: expose a post-update migration hook for breaking plugin redesigns

Summary

When a plugin ships a major-version update that fundamentally changes the agent surface (e.g. 80 specialist agents → 1 orchestrator + 17 commands, or vice versa), the plugin manager has no way for the plugin author to declare cleanup actions that should run once on the upgrade boundary. The result is that the new version installs alongside the old, both directories survive on disk (one orphan-flagged but not garbage-collected — see companion issue #1), and external tooling that assumes the old layout can silently keep the old version "hot" by walking the cache directory.

Concrete case

accessibility-agents v3.2.0 → v4.0.0 (May 2026):

  • v3.2.0: 80 specialist agents registered, each consuming ~150–250 tokens of agent-list schema (≈12–18k tokens total).
  • v4.0.0: 1 orchestrator agent (accessibility-lead) with inline checklists, plus 17 three-line slash commands. ≈ <1k tokens of agent-list schema.

The upgrade went through the marketplace channel correctly. But:

  • v4.0.0 was orphan-flagged by the plugin manager (incorrectly — the user had it enabled in enabledPlugins).
  • v3.2.0 was retained in cache with live .in_use/<pid> locks.
  • An installer-side shell script (~/.claude/.a11y-agent-team-update.sh) installed during v3.x ran nightly via launchd and re-populated agent files into the plugin cache, picking v3.2.0 alphabetically.
  • The combined effect was that a session loading the plugin would see the v3.2.0 agent registry — the 80-specialist surface — even though plugin.json declared v4.0.0 with 1 agent.
  • The user saw a "cumulative agent descriptions ~15.5k > 15.0k tokens" warning every session and was unable to resolve it without manually patching the updater script, manually orphan-flag-clearing v4.0.0, and manually deleting the legacy launchd plist.

A plugin-author-supplied post-update hook running on the upgrade boundary could have:

  1. Removed the legacy launchd plist (~/Library/LaunchAgents/com.community-access.a11y-agent-team-update.plist).
  2. Removed the shadow updater script (~/.claude/.a11y-agent-team-update.sh) and its git clone (~/.claude/.a11y-agent-team-repo/).
  3. Triggered an immediate rm -rf of the old version directory rather than relying on orphan-GC TTL.
  4. Printed a one-time migration notice to the user.

Proposed design

Plugin manifest gains a hooks field:

{
  "name": "accessibility-agents",
  "version": "4.0.0",
  "hooks": {
    "post-update": "scripts/post-update.sh",
    "post-uninstall": "scripts/post-uninstall.sh"
  }
}
  • post-update runs after the new version is installed and the old version is orphan-flagged. Receives the prior version as $1.
  • post-uninstall runs after the user disables the plugin or removes it entirely.
  • Plugin manager waits up to N seconds for the hook to exit, logs output, and surfaces a final status message to the user.
  • Hooks run in the user's shell with the plugin's cache directory as CWD.

Sandboxing: hook scripts run with the same permissions as the Claude Code process. Plugins are already trusted code (they install agents and MCP servers); a post-update hook is no greater trust delegation than the existing model. Surface the hook intent in the install/update confirmation prompt.

Acceptance

  • A plugin with hooks.post-update declared in its manifest has the script invoked when the plugin manager upgrades it from one version to another.
  • The hook receives the prior version number as $1 and can act on it (rm, mv, launchctl bootout, etc.).
  • Hook stdout/stderr is captured and surfaced in the plugin manager's update output.
  • Hook failure (non-zero exit) is non-blocking by default but clearly reported. Optional manifest field hooks.failureMode: "block" can opt into hard-fail.

See also

  • Companion issue: .orphaned_at flag has no garbage collector — #58880 (would have caught the v3.2.0 directory after 14 days even without a hook).
  • Companion issue: .in_use/<pid> lock files leak stale PIDs — #58881 (contributed to v3.2.0 staying "live" past its real usage).

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