[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
8 Comments
Fix confirmed working locally.
Added
permissionDecisionReasontohookSpecificOutputinrule_engine.py: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, notsystemMessage.Fix
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 -
systemMessageappears 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.
This is now fixed in hookify-plus!
Added
permissionDecisionReasonto the hookSpecificOutput so Claude sees the detailed blocking message:hookify-plus aggregates community fixes that Anthropic hasn't merged. Feel free to use it! 🚀
Feature was implemented in v2.1.9.
-Added support for PreToolUse hooks to return additionalContext to the model
👍
Confirmed: Still broken in hookify@claude-plugins-official (January 2026)
Just tested with Claude Code 2.1.11 and the official hookify plugin. The fix described above was never merged.
Test Setup
enabled: true(native plugin handling)Result
When the rule blocks a command, Claude receives only:
Claude does NOT receive the detailed message explaining why it was blocked or what alternatives to use.
Proof - Current hookify source still missing the fix
Source: https://github.com/anthropics/claude-plugins-official/blob/main/plugins/hookify/core/rule_engine.py#L60-L79
The
combined_messagehas the detailed explanation, but it's only insystemMessage(shown to user). Claude needs it inpermissionDecisionReasonto understand why the command was blocked.Workaround
We use a native hook bridge that outputs to stderr + exit 2, which Claude Code properly routes to the model. This works, but it's a workaround for what should be fixed in the plugin.
Request
Please add
permissionDecisionReasonto thehookSpecificOutput:This is a one-line fix that would make hookify actually useful for guiding Claude's behavior.
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.