Claude Code hooks explained: every event, with real Australian examples
Every Claude Code hook type, when each fires, and 6 real hooks we run across our businesses, formatters, audit logs, Slack pings, lint gates.
Hooks are shell commands Claude Code runs automatically when specific events happen (a tool runs, a session ends, a notification fires). They give you deterministic guardrails, formatters, lint gates, audit logs, Slack pings, that always happen, regardless of what the model decides.
Slash commands are shortcuts you choose to run. Hooks are guardrails that run themselves. If “every time Claude edits a TypeScript file, format it with Prettier” sounds useful, you want a hook.
The hook events
Configured in .claude/settings.json. Every event is optional. The full list as of May 2026:
| Event | Fires | Can block? | Common use |
|---|---|---|---|
PreToolUse | Before any tool call (Edit, Write, Bash, etc) | Yes | Secret scanner, dangerous-command gate |
PostToolUse | After a tool call completes | No | Formatter, linter, audit log |
UserPromptSubmit | When you send a message | Yes | Inject project rules, redact secrets |
SessionStart | New Claude Code session begins | No | Log session, sync git, warm cache |
SessionEnd | Session ends | No | Save transcripts, send Slack summary |
Notification | Claude asks for permission or sends an alert | No | Desktop ping, Slack DM |
Stop | Claude pauses for input | No | Background work while you read |
SubagentStop | A subagent finishes its task | No | Aggregate results |
PreCompact | Before context compression | No | Save full transcript |
Configuration shape
Here’s a minimal .claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "npx prettier --write $CLAUDE_FILE_PATH"
}
]
}
]
}
}
Every hook is a shell command that runs on your machine. Claude Code passes context via environment variables: $CLAUDE_FILE_PATH, $CLAUDE_TOOL_NAME, $CLAUDE_TOOL_INPUT, etc. Exit code 0 means continue; non-zero on PreToolUse events blocks the action.
Six hooks we actually run
1. Prettier on every TypeScript edit
{
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true" }
]
}
]
}
Files stay formatted regardless of what Claude does. The || true swallows errors on files Prettier doesn’t know about.
2. Block writes to production data files
{
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "case \"$CLAUDE_FILE_PATH\" in *prod-*|*.env*|*credentials*) echo 'Blocked: production/secrets file'; exit 1 ;; esac"
}
]
}
]
}
Refuses any edit to a file matching production or secret patterns. Saved us once when Claude tried to “tidy up” a .env file.
3. Session-end Slack ping
{
"SessionEnd": [
{
"hooks": [
{
"type": "command",
"command": "curl -s -X POST $SLACK_HOOK_URL -H 'Content-Type: application/json' -d '{\"text\":\"Claude Code session ended in '$(basename $(pwd))', cost $CLAUDE_SESSION_COST\"}'"
}
]
}
]
}
Pings #dev with a session summary. Easy to spot expensive sessions.
4. Auto-stage edits as a git WIP commit
{
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "git add \"$CLAUDE_FILE_PATH\" && git commit -m 'wip: $CLAUDE_FILE_PATH' --no-verify || true"
}
]
}
]
}
Every Claude edit becomes a tiny WIP commit. Trivial to undo, easy to audit what happened.
5. Inject the day’s date on every prompt
{
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "echo \"Today is $(date '+%A %d/%m/%Y'). I'm in Melbourne. Use Australian English.\""
}
]
}
]
}
The hook stdout gets prepended to your prompt. Cheap, always-on Australian-English enforcement.
6. Audit log of every Claude action
{
"PostToolUse": [
{
"hooks": [
{
"type": "command",
"command": "echo \"$(date '+%Y-%m-%dT%H:%M:%S') $CLAUDE_TOOL_NAME $CLAUDE_FILE_PATH\" >> .claude/audit.log"
}
]
}
]
}
A grep-able log of every tool call. Useful for “what changed today” forensics, especially when you’re letting Claude run long.
Matchers
The matcher field is a regex against the tool name. Common values:
Edit|Write, any file modificationBash, any shell commandRead, any file readWebFetch|WebSearch, anything that hits the network.*or omitted, all tools
You can scope hooks tightly (matcher: "Edit" only fires on Edit, not Write) for targeted automation.
Performance and ordering
- Hooks run in the order they’re declared.
PreToolUseis synchronous, Claude waits for it. Keep these fast (under 500ms is the rule of thumb).PostToolUseruns without blocking Claude, but if it takes longer than the next tool call, you may see them interleave in unexpected ways.- If a
PreToolUsehook hangs, Claude Code will eventually time out. Always include a sensible timeout in any network-calling hook.
When to use a hook vs a slash command vs a skill
- Hook: “this should always happen on event X.” Deterministic. No model in the loop.
- Slash command: “I want to fire this exact prompt with one keystroke.” You initiate.
- Skill: “Claude should choose when to invoke this capability.” Model in the loop.
A formatter is a hook. “Draft me a quote” is a slash command. “Find a relevant a client product image when I’m writing a blog post” is a skill.
Common gotchas
- Quoting on Windows. PowerShell handles quotes differently to bash. If a hook works on macOS but breaks on Windows, the problem is almost always quoting. Use PowerShell-native commands where possible.
- Hooks run as you. They inherit your shell environment, your credentials, your filesystem permissions. Treat them like cron jobs, same risk model.
- Long-running hooks block other work. A 30-second linter on every Edit makes the session feel sluggish. Move slow things to a Stop or SessionEnd hook.
What to do next
Add the date-injection hook (number 5 above) to your ~/.claude/settings.json right now. Two minutes, zero risk, instant Australian-English upgrade. Once you see what hooks feel like, the rest follow naturally.
If you want a starter pack of hooks plus a battle-tested .claude/settings.json shaped for Australian small business work, it’s part of our Claude Code starter pack.
Common questions
Do hooks count against my token budget?
Can a hook prevent Claude from doing something?
Where do I configure hooks?
Want this built for your business?
Book a free 30-minute AI audit. We'll map your business and show you exactly which systems we'd build first. No pitch deck, no scoping fee.
Book my free AI audit