Stop hook command type not dispatched from settings.json (plugin Stop hooks fire, settings.json ones don't)

Resolved 💬 5 comments Opened Feb 19, 2026 by coop-liberty Closed May 23, 2026

Description

Command-type Stop hooks registered in ~/.claude/settings.json are never invoked by Claude Code, while plugin-registered Stop hooks (e.g., from claude-mem) fire reliably on every stop event.

Environment

  • Claude Code version: v2.1.47 (claude-opus-4-6[1m])
  • OS: Pop!_OS 24.04 LTS (Ubuntu-based)
  • Terminal: Warp

Steps to Reproduce

  1. Register a command-type Stop hook in ~/.claude/settings.json:
{
  "hooks": {
    "Stop": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/stop-hook.sh"
          }
        ]
      }
    ]
  }
}
  1. Create the hook script:
#!/usr/bin/env bash
echo "$(date -Iseconds) STOP FIRED" >> /tmp/stop-hook-test.log
exit 0
  1. chmod +x /path/to/stop-hook.sh
  2. Restart Claude Code (hooks are snapshot at startup)
  3. Have a normal conversation with tool usage
  4. Check /tmp/stop-hook-test.log — file is never created

Expected Behavior

The Stop hook script should execute at the end of each assistant turn, similar to how plugin-registered Stop hooks fire.

Actual Behavior

The script is never invoked. Evidence:

  • An unconditional debug log write at the top of the script never creates its log file
  • A state file that should be consumed (deleted) by the hook persists indefinitely across turns and sessions
  • Manual execution of the script (echo '{}' | /path/to/stop-hook.sh) works correctly

Comparison with Plugin Hooks

Plugin Stop hooks (registered via hooks.json in plugin directories) do fire correctly. For example, claude-mem's Stop hooks (summarize and session-complete) execute on every stop event, confirmed via worker logs showing 40+ Stop events per day.

This suggests the Stop event is generated by Claude Code, but the dispatcher only routes it to plugin-registered hooks, not to settings.json command hooks.

Additional Context

  • PreToolUse and PostToolUse command hooks registered in the same settings.json file work correctly
  • The Stop hook registration schema matches the documented format and other working hook registrations
  • Execute permissions are correct (rwxrwxr-x)
  • The hook was registered before the session started (loaded in the startup snapshot)

Workaround

Moving suggestion delivery to PostToolUse hooks (which dispatch correctly from settings.json) as a workaround.

View original on GitHub ↗

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