Skip to main content
Hooks let you attach custom logic to specific lifecycle events in Claude Code. When a hook event fires, Claude Code runs the configured command, evaluates a prompt, or spawns a sub-agent — before or after the triggering action takes place.

Hook events

Each hook is registered under one of the following events:

Configuration

Hooks are defined in your settings JSON file (e.g. ~/.claude/settings.json for user-level hooks, or .claude/settings.json for project-level hooks) under the hooks key. The value is a map from event name to an array of matcher configurations.
Each matcher object has:
  • matcher (optional) — a string pattern matched against the tool name (e.g. "Bash", "Write")
  • hooks — an array of hook definitions to run when the matcher matches

The if condition

Every hook supports an if field that uses permission rule syntax to filter when the hook runs. The condition is evaluated against the hook input’s tool_name and tool_input fields.
Only calls where the tool matches the pattern will trigger the hook. This avoids spawning hooks for non-matching commands. Examples:
  • "Bash(git *)" — any Bash call starting with git
  • "Read(*.ts)" — any Read call on a .ts file
  • "Write" — any Write call, regardless of path

Hook types

Runs a shell command. The hook input is passed as JSON via stdin.
Exit code behaviour:
  • 0 — success, continue normally
  • 2 (with asyncRewake: true) — the model is woken and given the hook’s stdout as a new message
  • Any other non-zero — the hook is treated as an error
Sends a prompt to an LLM. Use $ARGUMENTS in the prompt string to inject the hook input JSON.
Spawns a sub-agent to verify or act on the hook event. The agent receives a prompt describing what to check, with $ARGUMENTS replaced by the hook input JSON.
POSTs the hook input JSON to a URL. Useful for integrating with external systems or webhooks.

Background execution

By default hooks run synchronously and block the agent until they complete. Use async to run a hook in the background:
If you also want the background hook to be able to wake the model — for example to report a problem discovered asynchronously — use asyncRewake:
When the command exits with code 2, Claude Code treats the stdout as a new user message and resumes the model. Any other exit code is treated as normal background completion.

Full example

The following settings configuration uses all four hook types across multiple events:
Hook scripts receive the full hook input as JSON on stdin. For PreToolUse and PostToolUse events this includes tool_name, tool_input, session_id, transcript_path, and cwd.