Configure, create, or troubleshoot Claude Code hooks (PreToolUse, PostToolUse, UserPromptSubmit), debug hook failures, or set up any automation within Claude Code. Examples include "I want to run tests before every file edit", "My hook isn't firing", "1 out of 2 hooks ran", or "How do I create a hook that formats JSON output with jq?"
Configure, create, or troubleshoot Claude Code hooks (PreToolUse, PostToolUse, UserPromptSubmit), debug hook failures, or set up any automation within Claude Code. Examples include "I want to run tests before every file edit", "My hook isn't firing", "1 out of 2 hooks ran", or "How do I create a hook that formats JSON output with jq?"
Reference for creating and configuring Claude Code hooks. When uncertain about syntax or features, use the Agent tool with subagent_type='claude-code-guide' to consult official docs.
Exit with no output to allow without modification.
Async
"async": true on a command hook backgrounds it so the turn does not wait. Nothing above reaches the model: no permissionDecision, no updatedInput, no additionalContext, and exit code 2 does not block. Verified on 2.1.220 that stderr and a nonzero exit are both dropped. "asyncRewake": true backgrounds the hook but wakes the model on exit code 2, delivering stderr (or stdout when stderr is empty) as a system reminder. Neither field applies to prompt or agent hooks.
Use async only for a hook that is a pure side effect: a notifier, a status bridge, a terminal bell, a state export. Keep it off when the hook returns any of the output above, mutates state a later step reads, or gates a tool call.
Two events behave differently from the rest, measured on 2.1.220:
Stop kills the backgrounded process almost immediately. Anything past a few milliseconds never finishes. A Stop notifier must stay synchronous.
SessionEnd outlives the CLI. A backgrounded hook there runs to completion after the process exits, making it safe to background.
SubagentStop, SessionStart, UserPromptSubmit, and PostToolUse all run to completion when backgrounded.
Hooks on the same event already run concurrently with each other, so async only shortens the turn when the side-effect hook is the slowest one on its event. It is still worth setting on a hook that qualifies, because the payoff moves as sibling hooks change.
Script Storage
Store complex hooks in .claude/hooks/ or a project hooks/ directory, referenced with: