[BUG] Plugin hooks.json entries with shell-spawning command silently skipped on Windows; node-spawning entries trigger normally

Resolved 💬 4 comments Opened Apr 29, 2026 by VISDE Closed May 31, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] 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.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗