claude-code - 💡(How to fix) Fix Plugin hooks.json registrations multiply additively (1×→122×) in multi-agent sessions (v2.1.156)

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

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…

In multi-agent sessions, a plugin's hooks/hooks.json registrations multiply additively — each command registration object is duplicated N times, so every hook fires N times per tool call. Observed growth: 1× → 122× for a directory-source plugin. At high multiples the duplicated hook execution pollutes tool output with garbled content.

Root Cause

In multi-agent sessions, a plugin's hooks/hooks.json registrations multiply additively — each command registration object is duplicated N times, so every hook fires N times per tool call. Observed growth: 1× → 122× for a directory-source plugin. At high multiples the duplicated hook execution pollutes tool output with garbled content.

Fix Action

Fix / Workaround

  1. hooks/hooks.json starts at its canonical count (one registration object per hook).
  2. During a session that dispatches sub-agents (the Agent tool / Subagent lifecycle), the working-tree hooks.json grows — registration objects are duplicated additively (observed up to 122× per hook).
  3. git checkout -- hooks/hooks.json restores it, but it can re-grow.
  4. At high multiples, hooks fire N times each and tool output is corrupted.

Intermittent. It did not reproduce in a focused session (held at the canonical count across a no-op sub-agent dispatch + two parallel real-work agents + ~14 tool calls). No deterministic minimal repro yet — filing with the negative-reproduction record rather than a guaranteed repro, in case others can correlate.

  1. Is the plugin-hook load/merge expected to be idempotent across sub-agent dispatch / plugin reload? A duplicated-registration guard (or replace-not-append semantics) on the merge path would prevent this.
  2. Any known trigger for plugin reload mid-session that would re-run the merge?

Code Example

jq '[.. | objects | select(.type=="command")] | length' hooks/hooks.json
RAW_BUFFERClick to expand / collapse

Summary

In multi-agent sessions, a plugin's hooks/hooks.json registrations multiply additively — each command registration object is duplicated N times, so every hook fires N times per tool call. Observed growth: 1× → 122× for a directory-source plugin. At high multiples the duplicated hook execution pollutes tool output with garbled content.

Environment

  • Claude Code 2.1.156
  • macOS (darwin 25.4.0)
  • Plugin installed from a local/directory-source marketplace ("type": "local", "source": "./"). The plugin is registered both as a directory source and as a cached install; both start at the canonical registration count.

What happens

  1. hooks/hooks.json starts at its canonical count (one registration object per hook).
  2. During a session that dispatches sub-agents (the Agent tool / Subagent lifecycle), the working-tree hooks.json grows — registration objects are duplicated additively (observed up to 122× per hook).
  3. git checkout -- hooks/hooks.json restores it, but it can re-grow.
  4. At high multiples, hooks fire N times each and tool output is corrupted.

The growth is purely additive (duplicated registration objects), consistent with the plugin-hook load/merge path re-running and appending the plugin's hook set rather than replacing it.

Why this looks like the harness, not the plugin

A full audit of the plugin's own scripts found no additive writer to hooks.json — the only writer overwrites the file with the canonical copy (atomic tmp+mv). The only mechanism that fits a 1×→N× additive growth is the harness re-running its plugin-hook load/merge and appending.

Reproduction status

Intermittent. It did not reproduce in a focused session (held at the canonical count across a no-op sub-agent dispatch + two parallel real-work agents + ~14 tool calls). No deterministic minimal repro yet — filing with the negative-reproduction record rather than a guaranteed repro, in case others can correlate.

Correct metric

Count structurally, not by line-grep:

jq '[.. | objects | select(.type=="command")] | length' hooks/hooks.json

(grep -c command double-counts — the "type" line plus the "command" line.)

Ask

  1. Is the plugin-hook load/merge expected to be idempotent across sub-agent dispatch / plugin reload? A duplicated-registration guard (or replace-not-append semantics) on the merge path would prevent this.
  2. Any known trigger for plugin reload mid-session that would re-run the merge?

Happy to add more detail or test a patch.

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

claude-code - 💡(How to fix) Fix Plugin hooks.json registrations multiply additively (1×→122×) in multi-agent sessions (v2.1.156)