
Photo: cottonbro studio / Pexels
Claude Code Hooks: 6 Production Patterns That Enforce Quality Without Prompting
Chris Harper
2 min read
Jun 17, 2026 · 17:43 UTC
TL;DR: Hooks turn your Claude Code setup from advisory prompts into enforced rules — these six patterns fire every time, with working JSON you can drop into .claude/settings.json today.
CLAUDE.md is advisory — Claude follows it roughly 70% of the time. Hooks are deterministic: a PreToolUse hook can block an action entirely (exit 1); a PostToolUse hook fires every time a file changes. Anything that must always happen belongs in a hook.
The two event types that matter most:
PreToolUse— fires before the tool call; exit 1 blocks it completelyPostToolUse— fires after completion; use for formatting, linting, type-checking
All patterns go in .claude/settings.json under "hooks".
Pattern 1: Auto-format on every write
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"handler": { "type": "command", "command": "npx prettier --write $FILEPATH" }
}
]
}
}
Pattern 2: Block edits to critical files
// scripts/block-critical.js
const blocked = ['src/middleware.ts', '.env', 'src/app/api/auth']
if (blocked.some(f => process.env.FILEPATH?.includes(f))) process.exit(1)
Wire it as a PreToolUse command handler with matcher "Edit|Write". Exit code 1 = denied.
Pattern 3: Block production dependency installs
// scripts/block-prod-deps.js
const cmd = process.env.COMMAND || ''
if (/npm install|yarn add|pnpm add/.test(cmd) && !cmd.includes('--save-dev'))
process.exit(1)
Pattern 4: Type-check after every TypeScript edit
{
"PostToolUse": [
{ "matcher": "Edit|Write",
"handler": { "type": "command", "command": "npx tsc --noEmit 2>&1 | tail -20" } }
]
}
The compiler error output appears in Claude's next turn — it self-corrects without you asking.
Pattern 5: Semantic security gate (prompt hook) When a regex can't capture intent, use a prompt-type hook:
{
"PreToolUse": [
{
"matcher": "Edit",
"handler": {
"type": "prompt",
"prompt": "Review this edit to $FILEPATH. If it touches auth, DB schema, payment paths, or secrets — DENY. Otherwise ALLOW."
}
}
]
}
Pattern 6: Notify on Stop
{
"Stop": [
{ "handler": { "type": "command",
"command": "osascript -e 'display notification \"Task complete\" with title \"Claude Code\"'" } }
]
}
Fires the moment a long-running session ends — step away without polling.
The rule: CLAUDE.md for what you want most of the time. Hooks for what must happen without exception.
Sources: Claude Code Hooks: 6 Production Patterns, Designing CLAUDE.md correctly (2026 architecture), SmartScope: Claude Code advanced best practices, Official Claude Code best practices