Claude Code Hooks 2026 — Lifecycle Automation for AI Coding Agents
Claude Code Hooks let you run shell commands at specific lifecycle points of the AI agent. 22+ events, 4 hook types, and practical configurations explained.

I added one PostToolUse hook to my Claude Code setup. It runs Prettier every time Claude edits a file. Three minutes of configuration. I haven't manually formatted a single file since.
Claude Code Hooks are user-defined shell commands that execute at specific lifecycle points of the AI coding agent. Think Git Hooks, but for Claude Code itself. The key difference from asking Claude to "please run Prettier after edits" is determinism. Hooks don't rely on the LLM remembering your instruction. They fire every time, no exceptions.
If Part 1 of this series covered MCP as the way to extend Claude Code's capabilities, Hooks are about controlling Claude Code's behavior. Extension and control together make an agent you can actually trust in production.
22 Events You Can Hook Into
Claude Code exposes 22+ lifecycle events. SessionStart fires when a session begins or resumes. UserPromptSubmit triggers before Claude processes your prompt. PreToolUse and PostToolUse bracket every tool execution. PermissionRequest catches the moment a permission dialog would appear. Stop fires when Claude finishes responding.
There are also events for subagent management (SubagentStart, SubagentStop), context compaction (PreCompact, PostCompact), configuration changes (ConfigChange), and more specialized ones like TaskCompleted, InstructionsLoaded, and WorktreeCreate.
Three events handle 90% of real-world use cases. PreToolUse acts as a security gate — you can block tool execution before it happens. PostToolUse handles post-processing like auto-formatting. Notification connects to desktop alerts so you can stop staring at the terminal.
4 Hook Types and How They Work
Each hook has a type that determines its behavior.
The command type is the workhorse. It runs a shell command directly. Here is what auto-formatting with Prettier looks like after every file edit.
{
"hooks": {
"PostToolUse": [{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }]
}]
}
}
The matcher field is a regex pattern. This hook only fires when the Edit or Write tool runs. No other tools trigger it.
The http type sends a POST request to a URL endpoint — useful for external service integration. The prompt type runs a single-turn LLM evaluation for yes/no decisions. The agent type spins up a multi-turn subagent with tool access for verification tasks. The prompt and agent types are particularly powerful for Stop hooks that verify "is this task actually complete?"
Exit codes determine behavior. Exit 0 means proceed (stdout becomes context for some events). Exit 2 means block the action — stderr feeds back to Claude as an explanation. Any other exit code proceeds but logs stderr.
Three Hooks I Actually Use
First, .env file protection. A PreToolUse hook checks if the file path contains .env. If it does, exit 2 blocks the edit entirely.
#!/bin/bash
FILE=$(jq -r '.tool_input.file_path // empty')
if [[ "$FILE" == *".env"* ]]; then
echo "BLOCKED: .env file editing prohibited" >&2
exit 2
fi
exit 0
jq parses the tool input to extract the file path. The exit 2 return tells Claude the action was blocked, and the stderr message explains why. Claude adapts accordingly — it won't keep trying to edit the file.
Second, desktop notifications. A command hook on the Notification event calls macOS osascript to display a native notification. When Claude needs input or finishes a task, I see it immediately even if I'm in another app.
Third, context re-injection after compaction. A SessionStart hook with a compact matcher automatically re-injects critical context when a session resumes after context compaction. Long sessions where Claude loses track of project context are no longer a problem.
Configuration: Where Hooks Live
Settings go in one of three files. ~/.claude/settings.json is global — applies to every project. .claude/settings.json is project-level and version-controlled, so your team shares the same hooks. .claude/settings.local.json is project-level but gitignored, for personal preferences.
The trade-off between global and project-level hooks is straightforward. Security hooks like .env protection belong in global settings — you want them everywhere. Project-specific hooks like a custom linter belong in .claude/settings.json so every contributor gets them. Personal convenience hooks go in .claude/settings.local.json.
Hooks vs Git Hooks
Git Hooks react to Git events: commits, pushes, merges. Claude Code Hooks react to AI agent behavior: "about to edit a file", "about to run a tool", "about to finish responding." They occupy different layers of the development workflow.
Git Hooks guard code quality. Claude Code Hooks guard agent behavior. They complement each other. You run ESLint in a pre-commit hook and block .env edits in a PreToolUse hook. Different mechanisms, same goal: preventing mistakes before they happen.
The next part of this series covers Claude Code's Agent system. Once you combine Hooks for behavior control with Agents for task distribution, Claude Code stops being a coding assistant and becomes a reliable automation engine.
The best automation is the kind you set up once and forget exists.
Sources
AI 트렌드를 앞서가세요
매일 아침, 엄선된 AI 뉴스를 받아보세요. 스팸 없음. 언제든 구독 취소.
