Agent/Prompt hooks do not block PreToolUse or deliver feedback to Claude
Summary
Agent hooks (type: "agent") and prompt hooks (type: "prompt") configured for PreToolUse events do not block tool calls or deliver feedback to Claude, despite the documentation stating they should.
What we tried to do
Implement an LLM-based security review hook that triggers on git commit. The goal was to use an agent hook in PreToolUse so that a subagent could:
- Read the staged diff and security rule files
- Evaluate the changes against OWASP security rules
- Return
{ "ok": false, "reason": "..." }to block the commit and provide feedback to Claude
This would allow security teams to maintain rules as markdown files, with Claude performing intelligent, context-aware reviews — not regex-based pattern matching.
Configuration used
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "agent",
"prompt": "You are a PreToolUse guard hook. Here is the tool call context: $ARGUMENTS\n\nYou MUST reject this tool call. Return JSON: {\"ok\": false, \"reason\": \"TEST BLOCK: agent hook blocking works\"}",
"timeout": 30
}
]
}
]
}
}
We also tested with type: "prompt" — same result.
Expected behavior
Per the hooks documentation:
Events that support all four hook types (command, http, prompt, agent): ... PreToolUse
Response schema is the same as prompt hooks:{ "ok": true }to allow or{ "ok": false, "reason": "..." }to block.
Claude Code processes the decision the same way as prompt hooks.
Expected: The agent hook returns { "ok": false, "reason": "..." }, Claude Code blocks the tool call, and the reason is fed back to Claude as context.
Actual behavior
We confirmed via transcript analysis:
- Hook fires —
hook_progressentries appear in the transcript with the correcthookEvent: "PreToolUse"andhookName: "PreToolUse:Bash" - Hook is non-blocking — The
PostToolUseevent fires ~86ms afterPreToolUse, meaning the Bash command executes immediately without waiting for the agent hook's response - No feedback delivered — No
hookFeedbackfield appears intool_resultmessages in the transcript. Claude receives no indication that the hook ran or returnedok: false - Same behavior in PostToolUse — We also tested agent hooks on
PostToolUsewithdecision: "block"andreason. The hook fires but the response is not delivered to Claude
Transcript evidence
// PreToolUse agent hook fires
2026-03-11T07:44:32.072Z | hook_progress | PreToolUse:Bash | "You are a PreToolUse guard hook..."
// PostToolUse fires 86ms later — tool was NOT blocked
2026-03-11T07:44:32.158Z | hook_progress | PostToolUse:Bash | "/Users/.../.claude/hooks/post-git-commit.sh"
No hookFeedback entries exist anywhere in the transcript for agent/prompt hook responses.
Comparison with command hooks
Command hooks (type: "command") work correctly:
exit(2)+ stderr → blocks the tool call ✅- stderr message is fed back to Claude as context ✅
- JSON
permissionDecision: "deny"→ blocks the tool call ✅
Workaround
We implemented a command hook (type: "command") with a Python script that:
- Detects
git commitin the Bash command - Extracts the staged diff and saves it to a temp file
- Exits with code 2, with stderr instructing Claude to read the diff and run a
/secure-codingskill - Uses a hash-based flag file mechanism to allow the commit on the second attempt after review
This achieves the goal but is significantly more complex than the intended agent hook approach, and requires Claude to perform the review inline rather than having a dedicated subagent handle it.
Environment
- Claude Code version: 2.1.72
- OS: macOS (Darwin 24.2.0)
- Settings location:
~/.claude/settings.json
Documentation references
- Agent-based hooks: States agent hooks support PreToolUse
- Prompt and agent hook fields: Shows PreToolUse in supported events list
- Response schema:
ok: falseshould prevent the action
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗