[Docs] Clarify behavior and precedence of advanced JSON output fields for Hooks
Title: [Docs] Clarify behavior and precedence of advanced JSON output fields for Hooks
Labels: documentation, improvement, hooks
Body
Overview
The current documentation for Claude Code Hooks, specifically the "Advanced: JSON Output" section, is powerful but can be ambiguous for developers. The subtle yet critical differences in behavior between control fields like continue, decision, and permissionDecision are not explicitly contrasted, which can lead to implementation errors and unexpected agent behavior.
Location
This feedback pertains to the documentation page found at en/docs/claude-code/hooks.
Problem Details
The "Advanced: JSON Output" section introduces several keys that a hook can return in a JSON payload to control the agent's behavior. While each field is explained, the documentation lacks a clear comparison of their effects, especially in combination or across different hook events.
A critical point of confusion is the distinction between stopping a single tool call versus stopping the entire agent loop.
For example, for a PreToolUse hook, the outcomes of these two payloads are vastly different:
- Payload to block a single tool call:
``json``
{
"permissionDecision": "deny",
"permissionDecisionReason": "Tool not allowed for this file type."
}
- Actual Outcome: Blocks the current tool call, feeds the reason back to Claude, and allows the agent to replan and attempt a different action.
- Payload to terminate the agent loop:
``json``
{
"continue": false,
"stopReason": "Aborting agent due to security policy violation."
}
- Actual Outcome: Terminates the entire agent loop for the current task, stopping all further action from Claude.
This distinction is not immediately obvious from the current documentation, and a developer could easily implement the second behavior when they intended the first.
Impact
This ambiguity can cause developers to write hooks with unintended side effects. A hook designed to prevent a single unsafe Bash command might accidentally be written to halt the entire development task, leading to user frustration and difficult debugging. Clearer documentation will lead to more robust and predictable hook implementations.
Concrete Recommendations for Improvement
To make this section more concrete and prevent errors, I suggest the following improvements:
- Add a Comparison Table: Create a table that explicitly contrasts the key control fields. This would be invaluable for quick reference.
| Field | Applies To (Events) | Effect | Key Distinction |
| :--- | :--- | :--- | :--- |
| permissionDecision: "deny" | PreToolUse | Blocks a single tool call. The agent is informed and can try an alternative. | Agent continues, but this specific action is prevented. |
| decision: "block" | PostToolUse, Stop, etc. | Feeds an error back to the agent. The agent must respond to the feedback. | The agent is forced to react to the hook's feedback. |
| continue: false | All Events | Terminates the entire agent loop. The session stops processing the current task. | Agent stops completely. This is a hard stop, not a course correction. |
- Provide Contrasting Code Examples: For
PreToolUseandPostToolUse, provide side-by-side examples demonstrating:
- How to block just one tool call (using
permissionDecision). - How to stop the entire agent (using
continue: false). - How to give feedback to the agent after a tool has run (using
decision: "block").
- Explicitly State Precedence Rules: The documentation should clearly state the order of operations or precedence. For example:
- "If a hook's JSON output includes
continue: false, it will always terminate the agent loop, regardless of other fields likepermissionDecision." - "For
PreToolUsehooks,permissionDecisiontakes precedence over the deprecateddecisionfield."
By making these changes, the documentation would empower developers to use the advanced hook features with greater confidence and precision.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗