Response schema
The LLM must respond with JSON containing:
json
{
"ok": true | false,
"reason": "Explanation for the decision",
"impossible": true | false
}| Field | Description |
|---|---|
ok | true to allow. For false, see the per-event behavior below |
reason | Required when ok is false |
impossible | Optional. The model returns it with ok: false when it judges the condition can never be satisfied. On Stop and SubagentStop, Claude Code then lets the turn end instead of feeding the reason back. Agent hooks and other events ignore it |
What happens on ok: false depends on the event:
StopandSubagentStop: the reason is fed back to Claude as its next instruction and the turn continues, unless the response also setsimpossible: true, in which case Claude Code allows the stop and the turn endsPreToolUse: the tool call is denied; by default the turn ends and the deny reason appears in the chat as a warning line. SetcontinueOnBlock: trueto instead return the reason to Claude as the tool error so it can adjust and continue, equivalent to a command hook'spermissionDecision: "deny". Before v2.1.210, the deny reason was returned to Claude as the tool error and the turn continuedPostToolUse: by default the turn ends and the reason appears in the chat as a warning line. SetcontinueOnBlock: trueto feed the reason back to Claude and continue the turn insteadPostToolBatch,UserPromptSubmit, andUserPromptExpansion: the turn ends and the reason appears as a warning line. These events end the turn ondecision: "block"regardless ofcontinuePostToolUseFailureandTaskCreated: the reason is returned to Claude as a tool error and the turn continues, regardless ofcontinueOnBlockTaskCompleted: when it fires because a task is marked completed during a turn, the reason is returned to Claude as a tool error and the turn continues, regardless ofcontinueOnBlock. When it fires because a teammate stops, it behaves likeTeammateIdleand halts the teammate by defaultTeammateIdle: by default the teammate stops and the reason appears as a warning line. SetcontinueOnBlock: trueto feed the reason back to the teammate and keep it working insteadPermissionRequest:ok: falsehas no effect. To deny an approval from a hook, use a command hook returninghookSpecificOutput.decision.behavior: "deny"PermissionDenied:ok: falsehas no effect because the denial already happened. The only output this event reads ishookSpecificOutput.retry, which prompt and agent hooks can't set. They run on this event, but their output is discarded. Use a command hook to returnretry
If you need finer control on any event, use a command hook with the per-event fields described in Decision control.