Learn · Permissions, hooks & security · CCAR-F
Hooks: events, matchers and exit codes
Hooks are handlers Claude Code runs at lifecycle events. Learn the events, matcher syntax, the stdin JSON and what exit code 2 does.
Key ideas
- Hooks are configured under hooks.<EventName> in settings: a matcher plus a list of handlers.
- Common events: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, Stop, SubagentStop, PreCompact, Notification, SessionEnd.
- Matchers: exact names or | lists (Edit|Write), otherwise an unanchored regex (mcp__memory__.*); * or empty matches all.
- Input arrives as JSON on stdin with session_id, cwd, hook_event_name, and tool_name and tool_input for tool events.
- Exit 0 is success, exit 2 blocks (stderr becomes the reason), any other code is a non-blocking error.
- PreToolUse JSON output can return permissionDecision allow, deny, ask or defer, plus updatedInput.
- Hooks from user, project, local, managed and plugin sources merge; handler types are command, http, mcp_tool, prompt and agent.
Worked example: Load today's tickets at session start
On SessionStart, plain text a command hook prints to stdout with exit 0 is added to Claude's context, so the session starts with the open tickets already known.
Exam traps
- Using exit 1 to block a tool call. Only exit 2 blocks; 1 is a non-blocking error.
- Expecting a PostToolUse hook to undo an action; the tool has already run.
- Assuming a hook's allow overrides a deny rule; deny and ask rules are still evaluated.
- Forgetting that a matcher with regex characters is unanchored: use ^...$ when you need a whole-name match.
Official docs
Practise CCAR-F questions · Next lesson: Prompt injection and sandboxing