PreToolUse/PostToolUse hooks don't fire in non-interactive -p mode
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
- Create a project with
.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash(*)",
"hooks": [
{
"type": "command",
"command": "echo HOOK_FIRED >> .hook-breadcrumb.log",
"timeout": 5
}
]
}
]
}
}
- Run Claude in prompt mode:
CLAUDECODE= claude -p "Run 'echo hello' using Bash." \
--model haiku \
--dangerously-skip-permissions \
--output-format stream-json
- 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-permissionsand without- Relative and absolute paths in hook commands
- Both
PreToolUseandPostToolUsematchers
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.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗