How hooks work
Every time Claude uses a tool, Claude Code checks whether any hooks are registered for the corresponding event. Matching hooks execute and can:- Inspect the tool name and input
- Produce output that Claude sees (e.g. lint warnings)
- Block the action with an error message
- Approve or deny the tool use programmatically (for
PreToolUsehooks)
Available hook events
| Event | When it fires |
|---|---|
PreToolUse | Before a tool executes. Can approve, block, or modify the tool input. |
PostToolUse | After a tool completes successfully. |
Notification | When Claude Code sends a user notification. |
UserPromptSubmit | When the user submits a message. |
SessionStart | When a new session begins. |
SessionEnd | When a session ends. |
Stop | When Claude stops generating (top-level). |
SubagentStop | When a subagent stops generating. |
PreCompact | Before context compaction runs. |
PostCompact | After context compaction completes. |
TeammateIdle | When a teammate agent becomes idle. |
TaskCreated | When a new task is created. |
TaskCompleted | When a task finishes. |
Hook configuration format
Hooks are configured under thehooks key in any settings file. The value is a record keyed by event name. Each event maps to an array of matchers, and each matcher contains one or more hook commands.
Matcher
The optionalmatcher field filters hooks to specific tool names (e.g. "Write", "Bash"). When omitted, the hook runs for all tools in that event. Matchers use the same permission-rule syntax as the permissions key — you can write Bash(git *) to match only git Bash commands.
Hook types
Command hook (shell)
Runs a shell command. The tool input is passed as JSON via theCLAUDE_TOOL_INPUT environment variable and via stdin.
Must be
"command".The shell command to execute.
Shell interpreter.
"bash" uses $SHELL (bash/zsh/sh). "powershell" uses pwsh. Defaults to "bash".Permission-rule pattern to filter when this hook runs (e.g.
"Bash(git *)" ). If the tool call does not match the pattern, the hook is skipped without spawning a process.Timeout in seconds for this command. Overrides the global default.
When
true, the hook runs in the background without blocking Claude.When
true, the hook runs once and is automatically removed after execution.Custom message shown in the spinner while the hook runs.
HTTP hook
POSTs the hook input JSON to an HTTP endpoint. Useful for logging, audit trails, and integrations with external services.Must be
"http".URL to POST the hook input JSON to.
Additional headers. Values may reference environment variables with
$VAR_NAME syntax. Only variables listed in allowedEnvVars are interpolated.Explicit list of environment variable names that may be interpolated in header values. Required for env var interpolation to work.
Prompt hook (LLM evaluation)
Evaluates a prompt using a language model. Useful for semantic validation — e.g. “check that the test output shows all tests passing.”Must be
"prompt".Prompt to evaluate. Use
$ARGUMENTS as a placeholder for the hook input JSON.Model to use (e.g.
"claude-sonnet-4-6"). Defaults to the small fast model.Agent hook (agentic verifier)
Runs a full subagent to verify a condition. The agent can use tools to inspect the environment before returning an approve or block decision.Must be
"agent".What the agent should verify. Use
$ARGUMENTS for the hook input JSON.Model for the agent. Defaults to Haiku.
Registering hooks
Add hooks to any settings file. Use/hooks inside a session to manage them interactively:
Example hooks
Lint on file write
Run ESLint automatically after everyWrite tool use that touches a .ts or .js file:
Run tests after editing source files
Block dangerous shell commands
Use aPreToolUse hook to intercept Bash calls and block specific patterns:
Log all tool uses to a file
Notify on session start
Send a notification when a session begins:Hook output
Command hooks communicate back to Claude Code via stdout. Return a JSON object to influence behavior:PreToolUse hooks, the hookSpecificOutput field allows updating the tool input before execution:
If a hook exits with a non-zero code or returns
{"continue": false}, Claude Code treats it as a blocking error and shows the stopReason to the user.Enterprise hook controls
When
true (set in managed settings), only hooks from managed settings run. User, project, and local hooks are ignored.Disable all hook and status-line execution entirely.
Allowlist of URL patterns HTTP hooks may target. Supports
* as a wildcard. When set, HTTP hooks with non-matching URLs are blocked.