Local plugin hooks match but never execute (isLocal: true)
Summary
Local plugins (isLocal: true) have their hooks matched by Claude Code but the hooks are never actually executed. This appears to be the same root cause as #11509, #11939, and #12151.
Environment
- Claude Code version: 2.0.64
- Platform: macOS Darwin 24.6.0
- Plugin installation: Local (
isLocal: trueininstalled_plugins.json)
Steps to Reproduce
- Create a local plugin with hooks in
hooks/hooks.json:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "my-plugin hook queue-synthesis",
"async": true
}
]
}
]
}
}
- Install the plugin locally (results in
isLocal: true)
- Run Claude Code and observe debug logs
Expected Behavior
The Stop hook should execute when Claude finishes responding.
Actual Behavior
Debug logs show:
Loaded hooks from standard location for plugin totalrecall: /Users/.../.claude/plugins/cache/totalrecall-local/totalrecall/3.0.5/hooks/hooks.json
Loading hooks from plugin: totalrecall
Getting matching hook commands for Stop with query: undefined
Found 1 hook matchers in settings
Matched 1 unique hooks for query "no match query" (1 before deduplication)
But no execution follows. The command is never run. No process spawned. Manual execution of the same command works perfectly:
echo '{"session_id":"test","transcript_path":"/path/to/transcript.jsonl"}' | my-plugin hook queue-synthesis
# Returns: {"queued":true,"queue_id":1,"message":"Session chunk queued for synthesis"}
Workaround
Moving hooks from the plugin's hooks/hooks.json to the user's ~/.claude/settings.json works:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "/absolute/path/to/my-plugin hook queue-synthesis",
"timeout": 30000
}
]
}
]
}
}
This confirms the hook configuration is correct - only the plugin hook execution path is broken.
Evidence from installed_plugins.json
"my-plugin@my-plugin-local": {
"isLocal": true
}
Related Issues
- #10875 - Plugin hooks JSON output not captured (CLOSED)
- #11509 - Local file-based plugin hooks never execute
- #11939 - Local plugin SessionStart hooks don't execute (CLOSED as dup)
- #12151 - Plugin hook output not passed to agent (OPEN)
Impact
This bug completely breaks the hook functionality for any locally-developed plugin, forcing developers to either:
- Ask users to manually copy hooks to their settings.json
- Publish to git and install from remote (changes
isLocaltofalse)
Neither is acceptable for local plugin development workflow.
This issue has 8 comments on GitHub. Read the full discussion on GitHub ↗