[BUG] Hookify plugin not passing blocking messages to Claude (missing permissionDecisionReason)
Bug Description
The hookify plugin blocks tool calls correctly but the detailed blocking message is only shown to the user, not passed to Claude. This prevents Claude from understanding why a tool was blocked and how to fix it.
Root Cause
In plugins/hookify/core/rule_engine.py (lines 72-79), when blocking a PreToolUse, hookify returns:
return {
"hookSpecificOutput": {
"hookEventName": hook_event,
"permissionDecision": "deny"
},
"systemMessage": combined_message
}
Per the hooks documentation, systemMessage is shown to the user, but permissionDecisionReason is what gets passed to Claude when permissionDecision is "deny".
Expected Behavior
Claude should receive the detailed blocking message (e.g., "Use uv run pytest instead of pytest") so it can correct its behavior.
Actual Behavior
Claude only receives a generic "Hook PreToolUse:Bash denied this tool" message without the helpful guidance from the hook's markdown body.
Proposed Fix
Add permissionDecisionReason to the hookSpecificOutput:
return {
"hookSpecificOutput": {
"hookEventName": hook_event,
"permissionDecision": "deny",
"permissionDecisionReason": combined_message # Add this line
},
"systemMessage": combined_message
}
Environment Info
- Discovered after PermissionRequest hooks update (changelog: "Enable PermissionRequest hooks to process 'always allow' suggestions")
- Hookify was merged in PR #11752 before
permissionDecisionReasonwas available
Reproduction
- Create a hookify rule that blocks a command (e.g.,
hookify.require-uv.local.md) - Have Claude try to run the blocked command
- Observe that Claude only sees "denied" without the detailed guidance
Fix confirmed working locally.
Added permissionDecisionReason to hookSpecificOutput in rule_engine.py:
return {
"hookSpecificOutput": {
"hookEventName": hook_event,
"permissionDecision": "deny",
"permissionDecisionReason": combined_message # Added this line
},
"systemMessage": combined_message
}
Claude now receives the full detailed blocking message (tables, explanations, guidance) instead of just "Hook PreToolUse:Bash denied this tool".
Related: UserPromptSubmit hooks have the same problem
Just discovered that UserPromptSubmit hooks also don't pass messages to Claude when using systemMessage.
Root Cause
For UserPromptSubmit hooks, the message must be in hookSpecificOutput.additionalContext, not systemMessage.
Fix
# Before (broken)
return {
"systemMessage": message
}
# After (working)
return {
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": message
}
}
Summary of hook output fields needed for Claude to receive messages:
| Hook Event | Field Required |
|---|---|
| PreToolUse | hookSpecificOutput.permissionDecisionReason |
| PostToolUse | hookSpecificOutput.permissionDecisionReason |
| UserPromptSubmit | hookSpecificOutput.additionalContext |
| Stop | reason (for blocking) |
This should probably be documented more clearly in the hooks documentation - systemMessage appears to only be shown to the user, while hook-specific fields are needed to pass context to Claude.
This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.
So both warn and block reason does not get back to Claude. This defeats the purpose of these pretty much.