Claude Code Hook Events — Where matcher and if Actually Apply
The official documentation lists the events, what each matcher matches, and where if applies in separate places. What you need while writing a config is one table you can scan, so here it is.
Events and matchers
| Event | What the matcher is tested against | Example values |
|---|---|---|
PreToolUse | tool name | Edit|Write, Bash, mcp__server__.* |
PostToolUse | tool name | Edit|Write, Bash |
PostToolUseFailure | tool name | Bash |
PermissionRequest | tool name | Bash |
PermissionDenied | tool name | Bash |
SessionStart | how the session started | startup, resume, clear, compact, fork |
Setup | which CLI flag triggered setup | init, maintenance |
SessionEnd | why the session ended | clear, resume, logout, prompt_input_exit, other |
Notification | notification type | permission_prompt, idle_prompt, auth_success, agent_completed |
SubagentStart | agent type | general-purpose, Explore, Plan, custom names |
SubagentStop | agent type | same as SubagentStart |
PreCompact | what triggered compaction | manual, auto |
PostCompact | what triggered compaction | manual, auto |
PreModelSwitch | canonical name of the target model | claude-opus-5, .*opus.* |
PostModelSwitch | canonical name of the target model | claude-opus-5 |
ConfigChange | configuration source | user_settings, project_settings, local_settings, policy_settings, skills |
DirectoryAdded | how the directory was added | slash_command, register_repo_root |
FileChanged | literal filenames to watch | .envrc|.env |
StopFailure | error type | rate_limit, overloaded, authentication_failed, server_error |
InstructionsLoaded | load reason | session_start, nested_traversal, path_glob_match, include, compact |
UserPromptExpansion | command name | your skill or command names |
Elicitation | MCP server name | your configured MCP server names |
ElicitationResult | MCP server name | same as Elicitation |
Events that silently discard a matcher
The documentation states it outright: “If you add a matcher field to an event without matcher support, it is silently ignored.”
No error appears. The handler you thought was narrowed runs every time.
CwdChanged, UserPromptSubmit, PostToolBatch, Stop, TeammateIdle, TaskCreated, TaskCompleted, WorktreeCreate, WorktreeRemove, MessageDisplay
Events where if is evaluated
if matches the tool name and its arguments together, and it is only evaluated on the five tool events. Written anywhere else, that handler never runs.
PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, PermissionDenied
Required handler fields
Each type requires different fields. The old field surviving a type change is the common shape.
| type | Required |
|---|---|
command | command |
http | url |
mcp_tool | server, tool |
prompt | prompt |
agent | prompt |
Source: Hooks, as of 2026-09-04. This table is compiled from that documentation and is not the documentation itself. Where they disagree, the official page is correct.
There is an MIT tool that checks exactly this. It reads .claude/ and reports the settings that are ignored and the deprecated spellings, citing the documentation behind each finding.