Automate actions with hooks changedhooks-guide
Upstream edited this page at 7 Nov 2026 19:18 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 7 Nov 2026 19:37 UTC.
Upstream edited
Recorded here
Lines+6added
Lines−16removed
From line
417
where the diff opens
First seen
14 Aug 2026
this site's first read of the page
Recorded edits52to this page, all time
The whole hunk
from line 417, old and new numbered
/
from line 417
417417
418418Skip the approval dialog for tool calls you always allow. This example auto-approves `ExitPlanMode`, the tool Claude calls when it finishes presenting a plan and asks to proceed, so you aren't prompted every time a plan is ready.
419419
420Unlike the exit-code examples above, auto-approval requires your hook to write a JSON decision to stdout. Claude Code runs `PermissionRequest` hooks when it's about to ask you for permission, and if your hook returns `"behavior": "allow"`, Claude Code answers the request on your behalf.
420Unlike the exit-code examples above, auto-approval requires your hook to write a JSON decision to stdout. Claude Code runs `PermissionRequest` hooks when it's about to ask you for permission, and if your hook returns `"behavior": "allow"`, Claude Code answers the request on your behalf. For a tool that [requires user interaction](https://code.claude.com/docs/en/hooks.md#allow-with-updatedinput), such as `ExitPlanMode`, the allow also needs `updatedInput`, or Claude Code ignores it and still shows the prompt.
421421
422422The matcher scopes the hook to `ExitPlanMode` only, so no other prompts are affected. Add this to `~/.claude/settings.json`:
423423
from line 430
430430 "hooks": [
431431 {
432432 "type": "command",
433 "command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"behavior\": \"allow\"}}}'"
433 "command": "jq -c '{hookSpecificOutput: {hookEventName: \"PermissionRequest\", decision: {behavior: \"allow\", updatedInput: .tool_input}}}'"
434434 }
435435 ]
436436 }
from line 449
449449>
450450> Claude Code never saves it as `defaultMode`.
451451
452To switch the session to `acceptEdits`, your hook writes this JSON to stdout:
452To switch the session to `acceptEdits`, replace the `command` line in that hook with this one:
453453
454454```json theme={null}
455{
456 "hookSpecificOutput": {
457 "hookEventName": "PermissionRequest",
458 "decision": {
459 "behavior": "allow",
460 "updatedPermissions": [
461 { "type": "setMode", "mode": "acceptEdits", "destination": "session" }
462 ]
463 }
464 }
465}
455"command": "jq -c '{hookSpecificOutput: {hookEventName: \"PermissionRequest\", decision: {behavior: \"allow\", updatedInput: .tool_input, updatedPermissions: [{type: \"setMode\", mode: \"acceptEdits\", destination: \"session\"}]}}}'"
466456```
467457
468458Keep the matcher as narrow as possible. Matching on `.*` or leaving the matcher empty would auto-approve every tool permission prompt, including file writes and shell commands. See the [PermissionRequest reference](https://code.claude.com/docs/en/hooks.md#permissionrequest-decision-control) for the full set of decision fields.
No line in this hunk matches that.