You keep telling Claude Code to run your tests after every change. You put it in CLAUDE.md. You repeated it in the prompts. And sometimes it does. And sometimes it doesn’t.
That’s exactly the problem that hooks solve.
Hooks turn your recommendations into guaranteed compliance. Not “Claude, please run the linter” — but a rule that fires automatically, always, no matter what Claude decides. That’s a different category of control.
What Are Hooks, Exactly?
Hooks are shell commands (or prompts, or agents) that you define and execute automatically at specific points in Claude Code’s lifecycle. Anthropic introduced them in mid-2025, and since then they’ve been one of the most powerful and least-used features of the tool.
The key difference from CLAUDE.md:
- CLAUDE.md / prompts: guidelines that Claude should follow. Non-deterministic.
- Hooks: commands that will execute, always, without exception.
If you’ve ever seen Claude skip a step you explicitly asked for, hooks are the solution.
The Lifecycle Events
Claude Code exposes multiple points where hooks can fire. The most important ones:
| Event | When it executes |
|---|---|
PreToolUse |
Before Claude executes any tool — can block the action |
PostToolUse |
After a tool completes successfully |
Stop |
When Claude finishes its response |
Notification |
When Claude needs your attention (idle, permission request, etc.) |
SessionStart |
At the start of a new session |
UserPromptSubmit |
When you submit a prompt, before Claude processes it |
TaskCompleted |
When a task is marked as completed (new in 2026) |
The critical one is PreToolUse. It’s the only hook that can block an action. If your hook returns a rejection signal, Claude cannot proceed. Everything else is reactive. PreToolUse is preventive.
Three Types of Handlers
Claude Code supports three types of handlers, each suited for different needs:
1. Command hooks — Execute a shell command, receive pass/fail back
{
"hooks": {
"PostToolUse": [{
"matcher": "Edit|Write",
"handler": {
"type": "command",
"command": "npx prettier --write $FILEPATH"
}
}]
}
}
2. Prompt hooks — Use a Claude model to evaluate conditions semantically (for decisions that need judgment, not just pattern matching)
3. Agent hooks — Invoke a full Claude agent with tool access for deep analysis
Start with command hooks. They’re the most predictable and easiest to debug. Move to prompt or agent hooks when you need semantic reasoning.
Getting Started: The /hooks Menu
The fastest way to set up your first hook is through the interactive menu — no JSON editing:
# Inside Claude Code
/hooks
You’ll see all available events. Select one, configure a matcher (use * for everything, or narrow it to a specific tool), and enter a shell command. The menu asks where to save — choose User settings to apply to all your projects, or Project settings for the current repo.
4 Practical Hooks to Add Today
1. Auto-format on every file edit
Every time Claude edits or writes a file, your formatter runs automatically:
{
"hooks": {
"PostToolUse": [{
"matcher": "Edit|Write|MultiEdit",
"handler": {
"type": "command",
"command": ".claude/hooks/auto-format.sh"
}
}]
}
}
# .claude/hooks/auto-format.sh
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
EXT="${FILE##*.}"
case "$EXT" in
js|ts|tsx|json) npx prettier --write "$FILE" ;;
py) black --quiet "$FILE" ;;
go) gofmt -w "$FILE" ;;
esac
exit 0
2. Security firewall — block dangerous commands
Use PreToolUse to intercept and deny shell commands matching dangerous patterns:
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"handler": {
"type": "command",
"command": ".claude/hooks/security-guard.sh"
}
}]
}
}
# .claude/hooks/security-guard.sh
COMMAND=$(cat | jq -r '.tool_input.command // empty')
DANGEROUS=('rm\s+-rf\s+/' 'curl.*\|\s*bash' 'mkfs\.' 'chmod\s+-R\s+777\s+/')
for pattern in "${DANGEROUS[@]}"; do
if echo "$COMMAND" | grep -qE "$pattern"; then
jq -n --arg r "Blocked: dangerous pattern detected" \
'{hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:$r}}'
exit 0
fi
done
exit 0
3. Desktop notification when Claude needs input
Never stare at the terminal waiting again:
# macOS
osascript -e 'display notification "Claude Code needs your attention" with title "Claude Code"'
Configure it as a Notification hook in the /hooks menu with matcher *.
4. Require tests to pass before any PR
Block Claude from creating a pull request until tests are green:
# .claude/hooks/require-tests-for-pr.sh
if npm test -- --reporter=dot; then
exit 0
else
echo "Tests are failing. Fix them before creating a PR." >&2
exit 2
fi
Configure it as a PreToolUse hook with matcher mcp__github__create_pull_request.
Teams and Enterprise: Hooks as a Guardrails Layer
This is where hooks become genuinely important at scale.
When you save hooks in .claude/settings.json at the repo root and commit it, every developer on the team inherits the same rules automatically. No onboarding, no documentation to remember, no “I forgot to run the linter.”
For enterprise teams, this means:
- Security compliance: Block modifications to protected directories. Prevent credentials from being written to files. Deny shell patterns associated with common mistakes.
- Audit logging: Every Bash command Claude runs is logged with timestamps — critical for compliance and post-incident review.
- Quality gates: No PR is created if tests don’t pass. No commit goes through if linting fails.
- HTTP hooks: Instead of running local scripts, you can point hooks to a team endpoint that applies organizational policies — a single place to update rules that propagate to all sessions of all developers.
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"handler": {
"type": "http",
"url": "https://your-team-server/hooks/security-check",
"timeout": 30,
"headers": { "Authorization": "Bearer $TEAM_TOKEN" }
}
}]
}
}
The difference between a team using Claude Code with hooks and one without: one has deterministic standards, the other has intentions.
Where Hooks Live
| File | Scope |
|---|---|
~/.claude/settings.json |
All your projects, only on your machine |
.claude/settings.json |
This project — commit it to share with the team |
.claude/settings.local.json |
This project, only on your machine (don’t commit) |
Learn More: Anthropic’s Free Official Course
If you want to go beyond hooks and understand the full architecture of Claude Code — context handling, tool chaining, MCP integration, SDK concepts — Anthropic has a free official course called Claude Code in Action, available on their Skilljar platform at anthropic.skilljar.com/claude-code-in-action.It’s free, takes a few hours, explicitly covers hooks, and upon completion grants an official Anthropic certificate that you can add to your LinkedIn profile. For developers who want to demonstrate professional knowledge of Claude Code, it’s the only official credential available at this time.
It’s also available on Coursera if you prefer that ecosystem.
The Mental Model to Take With You
Hooks answer a single question: what should always happen, no matter what Claude decides?
Your formatter should always run. Your security checks should always block. Tests should always pass before a PR goes out.
Those things go in hooks. Everything else goes in CLAUDE.md.
That combination — deterministic compliance for the non-negotiable, guidelines for everything else — is how you build a Claude Code workflow that you can actually trust at scale.
Are you already using hooks in your projects? Which hook has had the most impact on your workflow? Let us know in the comments.

