Summary
packages/agent-bundle/src/adapters/claude.ts (buildPluginManifest, around line 3164) writes
...(hookDocument === undefined ? {} : { hooks: `./${hookContract.manifestPath}` }),
into .claude-plugin/plugin.json, i.e. "hooks": "./hooks/hooks.json". Claude Code auto-loads the conventional hooks/hooks.json, and since 2.1.255 it treats the manifest entry as a duplicate and refuses to load the plugin at all:
Hook load failed: Duplicate hooks file detected: ./hooks/hooks.json resolves to already-loaded file
<root>/hooks/hooks.json. The standard hooks/hooks.json is loaded automatically, so manifest.hooks
should only reference additional hook files.
Observed with Claude Code 2.1.259 on cargo-hauler@0.4.1 built from agent-bundle preview 886b192: claude plugin list shows ✘ failed to load; the session has no mcp__cargo-hauler__* tools and none of the plugin's hooks, even though agent-bundle doctor --host claude reports installed copy: current. Downstream report: ScriptedAlchemy/cargo-hauler#48.
Fix
- Omit
hooks from plugin.json when the hook manifest is at the conventional hooks/hooks.json (which is always the case for the adapter's own output). Only emit hooks for additional hook files.
native-claude-contract / doctor --host claude should run claude plugin list --json and surface errors[] for the installed plugin, reporting it broken rather than current.
- Add the 2.1.255+ behaviour to the Claude capability table / audit notes so the contract test catches a regression.
Version
agent-bundle 886b192 (main); main at 284141958 still has the same line.
Summary
packages/agent-bundle/src/adapters/claude.ts(buildPluginManifest, around line 3164) writesinto
.claude-plugin/plugin.json, i.e."hooks": "./hooks/hooks.json". Claude Code auto-loads the conventionalhooks/hooks.json, and since 2.1.255 it treats the manifest entry as a duplicate and refuses to load the plugin at all:Observed with Claude Code 2.1.259 on
cargo-hauler@0.4.1built from agent-bundle preview886b192:claude plugin listshows✘ failed to load; the session has nomcp__cargo-hauler__*tools and none of the plugin's hooks, even thoughagent-bundle doctor --host claudereportsinstalled copy: current. Downstream report: ScriptedAlchemy/cargo-hauler#48.Fix
hooksfromplugin.jsonwhen the hook manifest is at the conventionalhooks/hooks.json(which is always the case for the adapter's own output). Only emithooksfor additional hook files.native-claude-contract/doctor --host claudeshould runclaude plugin list --jsonand surfaceerrors[]for the installed plugin, reporting itbrokenrather thancurrent.Version
agent-bundle
886b192(main);mainat284141958still has the same line.