claude-code-notifier
how it works guides faq
◐English
English العربية Deutsch Español Français עברית Italiano 日本語 한국어 Nederlands Polski Português (Brasil) Русский Türkçe Tiếng Việt 简体中文 繁體中文
Get started
All guides

Claude Code hooks explained: every event and what it is for

Updated 31 October 2026 · 7 min read
on this page 01How a hook is put together 02Where hooks live 03Handler types 04Matchers 05Input: what your hook receives 06Output: exit codes and JSON 07Every hook event 08Which events matter for notifications 09Where Claude Code Notifier fits 10FAQ

Claude Code hooks are commands (or HTTP calls, prompts and a few other handler types) that Claude Code runs automatically at fixed points in a session, such as before a tool runs, when a permission is needed or when Claude finishes responding. You define them under a hooks key in a settings file such as ~/.claude/settings.json. Each hook receives JSON about the event on stdin and can reply through its exit code or a JSON object on stdout, which lets it log, notify, block an action or answer on your behalf.

01How a hook is put together

A hook configuration has three levels:

  1. The hook event, such as PreToolUse or Stop.
  2. A matcher group, which filters when it fires, such as "only for the Bash tool".
  3. One or more hook handlers, the thing that actually runs.
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/lint-check.sh"
          }
        ]
      }
    ]
  }
}

This runs a lint script after Claude writes or edits a file. To add a second event, add a sibling key inside the same hooks object.

02Where hooks live

FileApplies toShared?
~/.claude/settings.jsonAll your projectsNo, your machine only
.claude/settings.jsonOne projectYes, can be committed
.claude/settings.local.jsonOne projectNo
Managed policy settingsYour organisationSet by admins
A plugin's hooks/hooks.jsonWhile the plugin is enabledYes

Hooks from different files add up rather than replacing each other. Type /hooks in Claude Code to see every active hook and where it came from.

In an interactive session, Claude Code holds back hooks, even your own, until you accept the workspace trust dialog for the folder.

03Handler types

Most hooks are "type": "command", which runs a shell command. There are four others:

  • http: POSTs the event JSON to a URL and reads the response body.
  • mcp_tool: calls a tool on an MCP server you have configured.
  • prompt: asks a Claude model a single-turn question and reads a JSON decision.
  • agent: starts a subagent that can read files before deciding (experimental).

Command hooks run with your full user permissions, through sh -c on macOS and Linux and Git Bash (or PowerShell) on Windows. Add "async": true to run one in the background; it can then no longer make decisions.

04Matchers

The matcher decides which occurrences of an event run the hook. What it matches against depends on the event: the tool name for tool events, the notification type for Notification, how the session started for SessionStart, and so on.

  • "*", "" or no matcher at all matches everything.
  • Letters, digits, _, -, spaces, | and , are treated as exact names. Edit|Write matches either tool.
  • Anything else is a JavaScript regular expression, so mcp__memory__.* matches every tool from one MCP server.

Matchers are case-sensitive. Some events, including Stop and UserPromptSubmit, ignore matchers. For tool events, an if field with a permission rule such as "Bash(git *)" narrows a single handler further.

05Input: what your hook receives

Every hook gets JSON on stdin with a few common fields, including session_id, transcript_path, cwd and hook_event_name, plus fields specific to the event. A PreToolUse hook for a Bash call, for example, also gets tool_name and tool_input.command. Read it with jq or any JSON parser:

#!/bin/bash
input=$(cat)
cmd=$(jq -r '.tool_input.command // empty' <<<"$input")
echo "Claude wants to run: $cmd" >> ~/claude-commands.log
exit 0

06Output: exit codes and JSON

A hook talks back in one of two ways.

Exit codes. 0 is success. 2 is a blocking error: on events that can block, the action stops and your stderr becomes the reason. Any other code, including the usual 1, is a non-blocking error, so the action goes ahead and you see a hook error notice. If a hook is meant to enforce a rule, exit 2, not 1.

JSON on stdout. Exit 0 and print a single JSON object for finer control. Some fields work everywhere, such as continue: false to stop Claude entirely. Others are per event: Stop uses decision: "block" with a reason, while PreToolUse and PermissionRequest put their decision inside hookSpecificOutput. Print nothing else on stdout: a stray line from your shell profile stops Claude Code reading the JSON.

07Every hook event

EventWhen it firesCan block?
SessionStartA session begins or resumesNo (adds context)
SetupStarted with --init-only, or --init / --maintenance with -pNo
InstructionsLoadedA CLAUDE.md or .claude/rules/*.md file is loadedNo
UserPromptSubmitYou submit a prompt, before Claude sees itYes
UserPromptExpansionA typed command expands into a promptYes
PreToolUseBefore any tool callYes
PermissionRequestA tool call needs a permission decisionAllows or denies through JSON
PermissionDeniedAuto mode denies a tool callNo
PostToolUseAfter a tool call succeedsNo (tool already ran)
PostToolUseFailureAfter a tool call failsNo
PostToolBatchAfter a batch of parallel tool calls, before the next model callYes
NotificationClaude Code sends a notificationNo
MessageDisplayWhile Claude's reply text is displayedNo (can change what is shown)
SubagentStart / SubagentStopA subagent starts or finishesSubagentStop only
TaskCreated / TaskCompletedA task is created or marked completeYes
StopClaude finishes respondingYes (keeps Claude going)
StopFailureThe turn ends with an API errorNo
TeammateIdleAn agent team teammate is about to go idleYes
ConfigChangeA settings file changes during a sessionYes
CwdChangedThe working directory changesNo
DirectoryAddedA directory is added with /add-dirNo
FileChangedA watched file changes on diskNo
WorktreeCreate / WorktreeRemoveA worktree is created or removedYes
PreCompact / PostCompactBefore and after context compactionPreCompact only
PreModelSwitch / PostModelSwitchBefore and after the model changesPreModelSwitch only
Elicitation / ElicitationResultAn MCP server asks for input, and after you answerYes
SessionEndA session endsNo

Anthropic adds events from time to time, so check the hooks reference for the current list and each event's input fields.

08Which events matter for notifications

Four events cover nearly everything people want to be told about:

  • Stop for "Claude has finished". See the Stop hook guide.
  • Notification for "Claude is waiting for you", with types such as permission_prompt and idle_prompt. See the Notification hook guide.
  • PermissionRequest to be told, or to answer, the instant a permission is needed. See the PermissionRequest guide.
  • PreToolUse on the AskUserQuestion tool, to see or answer Claude's multiple-choice questions. See answering questions from your phone.

For a ready-to-paste desktop setup, start with how to get a notification when Claude Code finishes.

09Where Claude Code Notifier fits

Claude Code Notifier is built entirely on these hooks. Its free command line tool, ccn, runs on Mac, Windows and Linux. Installing it adds seven hook entries to ~/.claude/settings.json, each running ccn hook, and keeps a one-time backup of the file. ccn runs for a few milliseconds per event, then exits, so nothing stays running.

On its own it shows desktop notifications. With the iPhone or Android app paired, the same hooks carry your answers back: allow or deny a permission, answer a question, or send the next instruction after Claude stops. It is independent and not made by Anthropic. If you only need a log or a lint step, a few lines of your own are simpler. Details are on the ccn page.

10FAQ

How do I test a hook without waiting for Claude?

Pipe sample JSON into the script and check the exit code: echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh; echo $?. Then run /hooks in Claude Code to confirm it is registered under the right event.

Why is my hook not running?

The usual causes are invalid JSON in settings.json (trailing commas, comments), a matcher that doesn't match exactly (they are case-sensitive), a script that isn't executable, or a folder you haven't trusted yet. Start Claude Code with claude --debug and read the debug log to see what ran. The full list is in the troubleshooting checklist.

How do I turn all hooks off for a while?

Set "disableAllHooks": true in a settings file. To skip them for one run, start Claude Code with --settings '{"disableAllHooks": true}'. There is no switch for one hook on its own; you remove its entry instead. Neither can turn off hooks that your organisation set in managed settings.

What is the default hook timeout?

Ten minutes (600 seconds) for command, HTTP and MCP tool hooks, 30 seconds for prompt hooks and 60 for agent hooks. A few events use shorter defaults, and you can set timeout in seconds on any handler.

Claude Code Notifier Get a push on your phone when Claude Code finishes or needs you, then approve, deny or answer from there. The ccn command line tool is free on Mac, Windows and Linux.
Download for iOS Download for Android Install ccn

Related guides

  • How to get a notification when Claude Code finishesUse a Stop hook for "finished" and a Notification hook for "needs input". Copy-paste setups for Mac, Windows and Linux, plus phone alerts.
  • The Claude Code Notification hook: when it fires and how to use itWhen Claude Code's Notification hook fires, what permission_prompt and idle_prompt mean, the input it gets, and why it waits before firing.
  • The Claude Code Stop hook: run something when Claude finishesHow Claude Code's Stop hook works, what input it gets, how to run a command when Claude finishes, and how to make Claude keep going safely.
  • Answering permission requests from a hook (PermissionRequest)How Claude Code's PermissionRequest hook works, how to allow or deny from a script, and why permission rules are often the better tool.
claude-code-notifier

Claude Code Notifier is an independent third-party application. It is not affiliated with, endorsed by, or sponsored by Anthropic, PBC. "Claude" and "Claude Code" are trademarks of Anthropic, PBC.

apps iOS App Android App ccn for macOS, Windows & Linux All guides
legal Privacy Policy Terms of Service Other languages © 2026 touchtap. All rights reserved. TouchTap Ltd is registered in England and Wales, company number 13942589.