Hooks
Deterministic automation at Claude Code lifecycle events — enforce rules regardless of what Claude decides
title: "Hooks" description: "Deterministic automation at Claude Code lifecycle events — enforce rules regardless of what Claude decides" section: "Core" readTime: "8 min" badge: "NEW"
Hooks
Hooks execute shell commands at fixed lifecycle events in Claude Code. Unlike CLAUDE.md instructions (which Claude reads and tries to follow), hooks are deterministic — they run regardless of what Claude decides to do.
Use hooks when you need guaranteed behavior: run a formatter after every file edit, block dangerous commands before they execute, post to Slack when a session ends.
Hook Events
| Event | When it fires |
|---|---|
PreToolUse | Before any tool call executes |
PostToolUse | After a tool call completes |
InstructionsLoaded | After CLAUDE.md and rules files are loaded into context |
Notification | When Claude sends a user-facing notification |
PreCommit | Before a git commit |
PreFileDeletion | Before a file is deleted |
Configuration
Hooks live in .claude/settings.json (project) or ~/.claude/settings.json (personal):
{
"hooks": [
{
"event": "PostToolUse",
"matcher": {
"tool": "Write",
"pattern": ".*\\.ts$"
},
"command": "npx prettier --write $CLAUDE_TOOL_OUTPUT_PATH"
},
{
"event": "PreToolUse",
"matcher": {
"tool": "Bash",
"pattern": "rm -rf"
},
"action": "ask"
},
{
"event": "PreToolUse",
"matcher": {
"tool": "Bash",
"pattern": "curl.*prod"
},
"action": "block",
"message": "Direct curl to prod is not allowed. Use the staging environment."
}
]
}Hook Actions
| Action | Behavior |
|---|---|
run (default) | Execute the shell command |
ask | Pause and ask the user for confirmation |
block | Cancel the tool call; show optional message |
notify | Send a desktop notification |
Available Variables
Hooks receive context via environment variables:
| Variable | Value |
|---|---|
$CLAUDE_TOOL_NAME | Name of the tool being called |
$CLAUDE_TOOL_INPUT | JSON input to the tool |
$CLAUDE_TOOL_OUTPUT | Tool output (PostToolUse only) |
$CLAUDE_TOOL_OUTPUT_PATH | File path written (for Write tool) |
$CLAUDE_SESSION_ID | Current session UUID |
$CLAUDE_HOOK_EVENT | Event name |
Common Patterns
Auto-format on write
{
"event": "PostToolUse",
"matcher": { "tool": "Write", "pattern": ".*\\.(ts|tsx|js|jsx)$" },
"command": "npx eslint --fix $CLAUDE_TOOL_OUTPUT_PATH && npx prettier --write $CLAUDE_TOOL_OUTPUT_PATH"
}Block secrets from being committed
{
"event": "PreCommit",
"command": "git diff --cached | grep -qE '(sk-|AKIA|password=)' && echo 'Possible secret detected' && exit 1 || exit 0"
}Log which instruction files were loaded (debugging)
{
"event": "InstructionsLoaded",
"command": "echo \"[$(date)] Loaded: $CLAUDE_INSTRUCTIONS_FILES\" >> ~/.claude/instruction-log.txt"
}The InstructionsLoaded event is particularly useful for debugging why a CLAUDE.md rule or path-scoped rule isn't being applied — you can see exactly which files were discovered and when.
Slack notification on session end
{
"event": "Notification",
"matcher": { "pattern": "session_end" },
"command": "curl -s -X POST $SLACK_WEBHOOK -d '{\"text\":\"Claude session $CLAUDE_SESSION_ID finished\"}'"
}Hooks in Skills
Hooks can be scoped to a skill's lifecycle using the hooks frontmatter field. These hooks only fire when the skill is active:
---
name: deploy
description: Deploy to production
disable-model-invocation: true
hooks:
- event: PreToolUse
matcher:
tool: Bash
pattern: ".*production.*"
action: ask
---
Deploy the application to production...Hooks vs CLAUDE.md Instructions
| CLAUDE.md | Hooks | |
|---|---|---|
| Enforcement | Claude reads and tries to follow | Executed by the runtime, always |
| Best for | Style guidance, conventions | Security policies, formatters, notifications |
| Can be overridden by Claude | Yes (it's context) | No |
| Runs shell commands | No | Yes |
If an instruction must run at a specific lifecycle point — before every commit, after every file write — use a hook. If it's guidance Claude should follow while coding, use CLAUDE.md.
Security Considerations
- Hooks in project
.claude/settings.jsontake effect after you accept the workspace trust dialog - Review project hooks before trusting a repository — they can run arbitrary shell commands
- Managed hooks (deployed by IT/DevOps) cannot be overridden by individual settings
Related
- Skills — Hooks can be scoped to individual skills
- Architecture — Where hooks fit in the 9-step pipeline
- Agent Development Kit — The full layer model