PreToolUse/PostToolUse hooks don't fire in non-interactive -p mode

Status Fixed / completed
Maintainer reply ✓ Yes — dicksontsai
Activity 4 comments · opened Mar 2, 2026 · closed Mar 3, 2026
💡 Likely answer: A maintainer (dicksontsai, collaborator) responded on this thread — see the highlighted reply below.

Description

When running Claude Code in non-interactive prompt mode (-p), project-level hooks defined in .claude/settings.json (PreToolUse, PostToolUse) do not fire. This appears to affect all hook types, not just PermissionRequest (which is documented as not firing in -p mode).

Steps to Reproduce

  1. Create a project with .claude/settings.json:
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash(*)",
        "hooks": [
          {
            "type": "command",
            "command": "echo HOOK_FIRED >> .hook-breadcrumb.log",
            "timeout": 5
          }
        ]
      }
    ]
  }
}
  1. Run Claude in prompt mode:
CLAUDECODE= claude -p "Run 'echo hello' using Bash." \
  --model haiku \
  --dangerously-skip-permissions \
  --output-format stream-json
  1. Check for .hook-breadcrumb.log — it does not exist. The hook never fired.

Expected Behavior

PreToolUse and PostToolUse hooks should fire in -p mode, just as they fire in interactive mode. The documentation states PermissionRequest hooks don't fire in non-interactive mode, but does not mention this limitation for PreToolUse/PostToolUse.

Actual Behavior

No hooks fire at all in -p mode. Tested with:

  • --dangerously-skip-permissions and without
  • Relative and absolute paths in hook commands
  • Both PreToolUse and PostToolUse matchers

Environment

  • Claude Code: v2.1.41
  • OS: Windows 11 (Git Bash / MSYS2)
  • Node.js: v25.6.1

Impact

We use -p mode for automated behavioral testing (SBTF — Sovereign Behavioral Testing Framework). Hooks are the primary enforcement mechanism for governance gates (e.g., requiring verify.sh to pass before commits). Without hooks in -p mode, we had to fall back to git pre-commit hooks as a workaround.

Workaround

Git pre-commit hooks (.git/hooks/pre-commit) fire at the git level regardless of Claude Code mode. We use these for enforcement in automated test runs.

View original on GitHub ↗

4 Comments

github-actions[bot] · 7 months ago

Found 1 possible duplicate issue:

  1. https://github.com/anthropics/claude-code/issues/20063

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

dicksontsai collaborator · 7 months ago

Your matcher syntax is invalid: Bash(*) isn't a valid pattern. The (*) makes it an invalid regex (quantifier with nothing to repeat), so it silently matches nothing. Instead use:

"matcher": "Bash"

See https://code.claude.com/docs/en/hooks#matcher-patterns

bungles411 · 7 months ago

Thanks @dicksontsai — good catch on the matcher syntax, that was definitely wrong in my repro.

That said, the underlying question still stands: do PreToolUse/PostToolUse hooks fire in non-interactive -p mode? Issue #20063 reports the same behavior (hooks not running in headless mode) and is still open.

Our workaround (git pre-commit hooks) works fine for enforcement, but it'd be great to get confirmation on whether -p mode hook support is intended or a known limitation.

github-actions[bot] · 7 months ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.