claude-code - 💡(How to fix) Fix [BUG] Plugin hooks.json entries with shell-spawning command silently skipped on Windows; node-spawning entries trigger normally [3 comments, 3 participants]

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…
GitHub stats
anthropics/claude-code#54772Fetched 2026-04-30 06:36:26
View on GitHub
Comments
3
Participants
3
Timeline
9
Reactions
0
Author
Timeline (top)
labeled ×4commented ×3cross-referenced ×2

Error Message

On Windows 11 + Git Bash, certain entries inside a plugin's hooks/hooks.json are silently skipped by Claude Code's hook dispatcher — no error in stderr, no entry in any plugin-side instrumentation. Other entries in the same hooks.json, with the same matcher and the same async/timeout flags, fire correctly. The only differentiator I have evidence for is the shape of the command string: entries that ultimately invoke a .sh wrapper are skipped, while entries that ultimately invoke a .js script run. All entries in hooks/hooks.json should be invoked according to their matcher. If a hook command cannot be spawned, Claude Code should surface an error rather than silently skip the entry.

Fix Action

Fix / Workaround

On Windows 11 + Git Bash, certain entries inside a plugin's hooks/hooks.json are silently skipped by Claude Code's hook dispatcher — no error in stderr, no entry in any plugin-side instrumentation. Other entries in the same hooks.json, with the same matcher and the same async/timeout flags, fire correctly. The only differentiator I have evidence for is the shape of the command string: entries that ultimately invoke a .sh wrapper are skipped, while entries that ultimately invoke a .js script run.

  • Matcher: pre:mcp-health-check (same matcher: "*") fires correctly.
  • Async/timeout: post:quality-gate (async: true) and pre:bash:dispatcher (async: true) fire correctly.
  • Plugin-level failure: 17 of 19 hooks in the same plugin fire, ruling out plugin load failure.
  • Working directory / project context: identical between fired and skipped entries.
  • disabled markers / env flags: none set; ~/.claude/homunculus/disabled does not exist; ECC_HOOK_PROFILE unset; ECC_SKIP_OBSERVE unset.

~/.claude/homunculus/projects/<hash>/ is created at session start but stays completely empty — no observations.jsonl, no .last-purge, no project.json, no subdirectories. Manually piping a synthetic event into the .sh wrapper from a real Git Bash terminal works correctly end-to-end and produces the expected file tree, so the script itself is functional. The failure is purely on the Claude Code dispatcher side selecting not to start those two hook commands.

Code Example

node -e "<bootstrap js>" shell scripts/hooks/run-with-flags-shell.sh pre:observe skills/continuous-learning-v2/hooks/observe.sh standard,strict

---

node -e "<bootstrap js>" node scripts/hooks/run-with-flags.js <hook-id> <script.js> standard,strict
RAW_BUFFERClick to expand / collapse

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report
  • I am using the latest version of Claude Code

What's Wrong?

On Windows 11 + Git Bash, certain entries inside a plugin's hooks/hooks.json are silently skipped by Claude Code's hook dispatcher — no error in stderr, no entry in any plugin-side instrumentation. Other entries in the same hooks.json, with the same matcher and the same async/timeout flags, fire correctly. The only differentiator I have evidence for is the shape of the command string: entries that ultimately invoke a .sh wrapper are skipped, while entries that ultimately invoke a .js script run.

What Should Happen?

All entries in hooks/hooks.json should be invoked according to their matcher. If a hook command cannot be spawned, Claude Code should surface an error rather than silently skip the entry.

Steps to Reproduce

  1. Install the everything-claude-code plugin v2.0.0-rc.1 on Windows 11 (commit c7c7d37f).
  2. Use Claude Code normally for ~10 minutes (dozens of tool calls).
  3. Add an appendFileSync debug call at the top of ~/.claude/plugins/cache/everything-claude-code/everything-claude-code/2.0.0-rc.1/scripts/hooks/plugin-hook-bootstrap.js to log every invocation to ~/.claude/homunculus/_debug.log.
  4. Inspect log: every mode=node hook entry in the plugin's hooks.json produces a log line per invocation. Two mode=shell entries (pre:observe:continuous-learning, post:observe:continuous-learning) produce zero log lines, indicating Claude Code never started their node -e "..." command at all.

The two skipped entries use this command shape:

node -e "<bootstrap js>" shell scripts/hooks/run-with-flags-shell.sh pre:observe skills/continuous-learning-v2/hooks/observe.sh standard,strict

The 17 working entries use this shape:

node -e "<bootstrap js>" node scripts/hooks/run-with-flags.js <hook-id> <script.js> standard,strict

The <bootstrap js> payload is character-for-character identical between the working and the skipped entries.

Eliminated alternatives (with evidence)

  • Matcher: pre:mcp-health-check (same matcher: "*") fires correctly.
  • Async/timeout: post:quality-gate (async: true) and pre:bash:dispatcher (async: true) fire correctly.
  • Plugin-level failure: 17 of 19 hooks in the same plugin fire, ruling out plugin load failure.
  • Working directory / project context: identical between fired and skipped entries.
  • disabled markers / env flags: none set; ~/.claude/homunculus/disabled does not exist; ECC_HOOK_PROFILE unset; ECC_SKIP_OBSERVE unset.

Symptom on the user side

~/.claude/homunculus/projects/<hash>/ is created at session start but stays completely empty — no observations.jsonl, no .last-purge, no project.json, no subdirectories. Manually piping a synthetic event into the .sh wrapper from a real Git Bash terminal works correctly end-to-end and produces the expected file tree, so the script itself is functional. The failure is purely on the Claude Code dispatcher side selecting not to start those two hook commands.

Claude Model

Opus 4.7

Is this a regression?

Don't know — first time installing this plugin version on this machine.

Claude Code Version

2.1.x (current)

Operating System

Windows 11 Pro 26200, Git Bash (mingw64)

Additional context

The plugin's docs (SKILL.md line 141-145, continuous-learning-v2) state plainly: "If installed as a plugin (recommended): No extra settings.json hook block is required. Claude Code v2.1+ auto-loads the plugin hooks/hooks.json". The behaviour observed contradicts that promise for the 2 affected entries.

The plugin author has been informed of the symptom on their tracker as well.

extent analysis

TL;DR

The issue can be fixed by modifying the command string in the hooks.json file to invoke the .sh wrapper scripts correctly, possibly by adjusting the shell execution or command formatting.

Guidance

  • Investigate the difference in command string shape between the working and skipped entries, focusing on the invocation of .sh wrapper scripts.
  • Verify that the node -e command is correctly formatted and executed for the skipped entries, potentially by logging or debugging the command execution.
  • Check the documentation for Claude Code's hook dispatcher to ensure that it supports invoking .sh scripts directly or if additional configuration is required.
  • Consider testing the invocation of the .sh wrapper scripts manually using Git Bash to isolate the issue.

Example

No code snippet is provided due to the lack of specific code details in the issue.

Notes

The issue seems to be related to the specific command string shape and the invocation of .sh wrapper scripts. Further investigation is needed to determine the root cause and the most effective solution.

Recommendation

Apply a workaround by modifying the command string in the hooks.json file to correctly invoke the .sh wrapper scripts, as the issue appears to be related to the command execution rather than a version-specific bug.

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 [BUG] Plugin hooks.json entries with shell-spawning command silently skipped on Windows; node-spawning entries trigger normally [3 comments, 3 participants]