Claude Code Hooks: Event-Driven Customization Deep Dive
Master Claude Code hooks for event-driven automation. Learn PreToolUse, PostToolUse, and Stop hooks with practical examples and security patterns.
Master Claude Code hooks for event-driven automation. Learn PreToolUse, PostToolUse, and Stop hooks with practical examples and security patterns.
Hooks are Claude Code's event-driven automation system. They let you intercept actions, validate operations, and trigger custom behavior at key moments. Whether you want to prevent dangerous commands, log all file changes, or generate summaries at session end, hooks make it possible.
This guide covers everything about hooks: the event types, how to create them, security considerations, and practical examples for real-world use cases.
Hooks are Markdown files that execute in response to specific Claude Code events. They're like middleware in a web framework—they intercept the flow, can modify or block operations, and add custom behavior.
User Request → PreToolUse Hook → Tool Execution → PostToolUse Hook → Response
↓ ↓
(can block) (can log/notify)
Unlike commands (which users invoke) or skills (which provide context), hooks run automatically when their trigger conditions are met.
Claude Code supports several hook events:
Fires before a tool executes. Can block or modify the operation.
Use cases:
Fires after a tool executes successfully. Cannot block (already happened).
Use cases:
Fires when a conversation ends or Claude Code stops.
Use cases:
Fires when a subagent completes its task.
Use cases:
Fires when a new session begins.
Use cases:
Fires when a session terminates.
Use cases:
Fires when the user submits a prompt.
Use cases:
Fires before context compaction.
Use cases:
Fires when Claude Code sends a notification.
Use cases:
Hooks are Markdown files with YAML frontmatter:
---
name: my-hook
event: PreToolUse
tools: [Bash]
---
# Hook Title
Instructions for what this hook should do.
| Field | Required | Description |
|---|---|---|
name | Yes | Unique identifier for the hook |
event | Yes | Event type (PreToolUse, PostToolUse, etc.) |
tools | No | Filter by tool (Bash, Write, Edit, etc.) |
description | No | What this hook does |
enabled | No | Whether hook is active (default: true) |
Hooks can be placed in:
# Project-level hooks
.claude/hooks/
.claude/hooks/pre-tool-use/
.claude/hooks/post-tool-use/
# User-level hooks
~/.claude/hooks/
# Plugin hooks
~/.claude/plugins/my-plugin/hooks/
Create .claude/hooks/command-safety.md:
---
name: command-safety
event: PreToolUse
tools: [Bash]
---
# Command Safety Check
Before executing any bash command, validate it for safety.
## Blocked Patterns
These commands should NEVER be executed:
- `rm -rf /` or variations targeting root
- `sudo rm -rf` without explicit user confirmation
- `chmod 777` on sensitive directories
- `curl | bash` or `wget | sh` (remote execution)
- Any command containing credentials in plain text
## Warning Patterns
These require explicit confirmation:
- `git push --force` (destructive to history)
- `DROP TABLE` or `DELETE FROM` without WHERE
- `npm publish` (public release)
- Modifications to `/etc/` or system directories
## Response
If a blocked pattern is detected:
1. STOP execution immediately
2. Explain why the command is blocked
3. Suggest a safer alternative
If a warning pattern is detected:
1. Ask for explicit user confirmation
2. Explain the risks
3. Only proceed with "yes" or "confirm"
PreToolUse is the most powerful hook type—it can block operations before they happen.
---
event: PreToolUse
tools: [Bash]
---
Available tools:
Bash - Shell command executionRead - File readingWrite - File creationEdit - File modificationGlob - File pattern matchingGrep - Content searchingTo block an operation, the hook should instruct Claude to refuse:
---
name: protect-env-files
event: PreToolUse
tools: [Write, Edit]
---
# Protect Environment Files
Never modify `.env` files directly through Claude Code.
## Protected Patterns
- `.env`
- `.env.local`
- `.env.production`
- `.env.*`
- Any file containing `API_KEY`, `SECRET`, or `PASSWORD` in the name
## When Triggered
If an operation targets a protected file:
1. BLOCK the operation
2. Explain that env files should be edited manually for security
3. Suggest the user edit the file directly in their editor
Hooks can transform operations:
---
name: sanitize-sql
event: PreToolUse
tools: [Bash]
---
# SQL Sanitization
When executing SQL commands, ensure safety.
## Instructions
If the bash command contains SQL:
1. Check for parameterized queries
2. If raw string interpolation is detected, warn the user
3. Suggest using prepared statements instead
Hooks can have complex conditions:
---
name: production-safeguard
event: PreToolUse
tools: [Bash]
---
# Production Safeguard
Prevent accidental production modifications.
## Detection
Check if the command targets production:
- Contains `prod` or `production` in arguments
- References production URLs or IPs
- Uses production database connection strings
## Branch Check
Also verify current git branch:
- If on `main` or `master`, require extra confirmation
- If on `production` branch, block all destructive operations
## Response
For production-targeting commands:
1. Clearly identify this is a production operation
2. List what the command will do
3. Require explicit confirmation: "Yes, execute in production"
4. Log the confirmation for audit trail
PostToolUse hooks run after successful tool execution. They're perfect for logging, notifications, and triggering side effects.
---
name: change-logger
event: PostToolUse
tools: [Write, Edit]
---
# Change Logger
Log all file modifications for audit trail.
## Instructions
After any file write or edit:
1. Note the file path
2. Note the type of change (create, modify, delete)
3. Note the timestamp
4. If significant change, summarize what was modified
## Log Format
Maintain a mental log of changes that can be summarized when requested:
| Time | File | Action | Summary |
|------|------|--------|---------|
| HH:MM | path/file.ts | Modified | Added error handling |
## Usage
When user asks for "what changed" or "session summary", provide this log.
---
name: test-failure-alert
event: PostToolUse
tools: [Bash]
---
# Test Failure Alert
Alert when tests fail.
## Detection
After any bash command that appears to be a test:
- `npm test`
- `yarn test`
- `pytest`
- `go test`
- `cargo test`
## On Failure
If the command output indicates test failures:
1. Clearly highlight the failure
2. Extract the failing test names
3. Show relevant error messages
4. Suggest next steps (examine specific test, check recent changes)
---
name: slack-notify
event: PostToolUse
tools: [Bash]
---
# Slack Notification
Notify on significant operations.
## Significant Operations
- Deployments (`deploy`, `publish`, `release`)
- Database migrations (`migrate`, `db:push`)
- Major git operations (`merge`, `push to main`)
## Notification
When a significant operation completes:
1. Format a summary message
2. If Slack MCP is available, send notification
3. If not, inform user that notification would be sent
## Message Format
:rocket: **Deployment Complete**
- Environment: staging
- Branch: feature/new-auth
- Time: 2025-01-16 10:30 UTC
- Status: Success
Stop hooks run when a conversation or session ends. They're ideal for summaries and cleanup.
---
name: session-summary
event: Stop
---
# Session Summary Generator
Generate a summary when the session ends.
## Summary Contents
1. **Duration**: How long the session lasted
2. **Files Modified**: List of all files changed
3. **Commands Run**: Significant bash commands executed
4. **Key Decisions**: Important choices made
5. **Pending Tasks**: Anything left incomplete
6. **Next Steps**: Recommended follow-up actions
## Format
### Session Summary - [Date]
**Duration**: X hours Y minutes
**Files Changed**:
- `path/file.ts` - Description of change
- `path/other.ts` - Description
**Key Accomplishments**:
- Implemented feature X
- Fixed bug in Y
**Next Steps**:
- [ ] Run full test suite
- [ ] Update documentation
- [ ] Deploy to staging
---
name: cleanup
event: Stop
---
# Session Cleanup
Clean up temporary resources when session ends.
## Cleanup Tasks
1. **Temporary Files**: Note any temp files created
2. **Pending Changes**: Warn about uncommitted changes
3. **Running Processes**: Identify any background processes started
4. **Open Connections**: Note any database or API connections
## Warnings
If any of these exist, warn the user:
- Uncommitted git changes
- Background processes still running
- Temporary files that should be deleted
- Draft files that need review
Hooks have significant power—they can block operations and modify behavior. Use them responsibly.
Only hook into events you need:
# Good - specific tools
tools: [Bash]
# Risky - all tools
# (no tools filter = matches everything)
Be specific in pattern matching:
# Too broad - blocks legitimate rm commands
Block: Any command containing "rm"
# Better - specific dangerous patterns
Block: `rm -rf /`, `rm -rf ~`, `sudo rm -rf`
Allow users to bypass hooks when needed:
## User Override
If user explicitly says "bypass safety check" or "I understand the risks":
- Log the override
- Proceed with the operation
- Note that safety was bypassed
Log sensitive operations:
## Audit Requirements
For any blocked or overridden operation:
1. Log the operation attempted
2. Log the hook that triggered
3. Log the outcome (blocked/allowed/overridden)
4. Include timestamp
---
name: commit-validator
event: PreToolUse
tools: [Bash]
---
# Commit Message Validator
Ensure commits follow conventional commit format.
## Conventional Commit Format
type(scope): description
[optional body]
[optional footer]
Types: feat, fix, docs, style, refactor, test, chore
## Validation
When detecting a git commit command:
1. Check if message follows format
2. If not, suggest the correct format
3. Block commit until format is correct
## Example
git commit -m "fixed stuff"
git commit -m "fix(auth): resolve login redirect issue"
---
name: dependency-audit
event: PostToolUse
tools: [Bash]
---
# Dependency Audit
Check for security issues after dependency changes.
## Trigger Commands
- `npm install`
- `yarn add`
- `pnpm add`
## After Dependency Installation
1. Check for `npm audit` warnings in output
2. If vulnerabilities found, summarize severity levels
3. Suggest `npm audit fix` for automatic fixes
4. For critical vulnerabilities, recommend immediate action
---
name: branch-protection
event: PreToolUse
tools: [Bash]
---
# Branch Protection
Prevent direct modifications to protected branches.
## Protected Branches
- main
- master
- production
- release/*
## Blocked Operations
On protected branches, block:
- `git commit` (should use feature branches)
- `git push --force`
- `git reset --hard`
## Allowed Operations
On protected branches, allow:
- `git pull`
- `git fetch`
- `git status`
- `git log`
## Response
If blocked:
"Direct commits to [branch] are not allowed. Please:
1. Create a feature branch: `git checkout -b feature/your-change`
2. Make your changes there
3. Open a pull request"
---
name: secret-detection
event: PreToolUse
tools: [Write, Edit, Bash]
---
# Secret Detection
Prevent accidental exposure of secrets.
## Secret Patterns
Detect and block:
- API keys: `sk-`, `pk_`, `api_key=`
- AWS credentials: `AKIA`, `aws_secret`
- Private keys: `-----BEGIN RSA PRIVATE KEY-----`
- Tokens: `ghp_`, `gho_`, `github_pat_`
- Generic: `password=`, `secret=`, `token=`
## In File Operations
If writing content containing secrets:
1. BLOCK the operation
2. Highlight the detected secret pattern
3. Suggest using environment variables instead
## In Bash Commands
If command contains hardcoded secrets:
1. BLOCK the operation
2. Suggest using environment variables
3. Show secure alternative
---
name: style-enforcement
event: PreToolUse
tools: [Write, Edit]
---
# Code Style Enforcement
Ensure code follows project standards.
## TypeScript Standards
- Use strict TypeScript (no `any`)
- Prefer `interface` over `type` for objects
- Use named exports
- Add JSDoc for public functions
## File Naming
- Components: PascalCase (`Button.tsx`)
- Utilities: camelCase (`formatDate.ts`)
- Tests: `*.test.ts` or `*.spec.ts`
- Styles: `*.module.css`
## Before Writing/Editing
Check if the proposed changes follow standards:
1. Correct file naming
2. Proper TypeScript types
3. Appropriate exports
4. Documentation where needed
If violations detected, suggest corrections before proceeding.
For project-specific behavior:
.claude/
└── hooks/
├── pre-commit-check.md
├── deploy-safety.md
└── test-requirements.md
For personal preferences across all projects:
~/.claude/
└── hooks/
├── global-safety.md
├── my-preferences.md
└── notification-prefs.md
Bundled with plugins for distribution:
my-plugin/
├── plugin.json
└── hooks/
├── plugin-specific-hook.md
└── another-hook.md
Hooks are loaded in this order:
Later hooks can override earlier ones.
> /hooks
Active hooks:
- command-safety (PreToolUse, Bash)
- change-logger (PostToolUse, Write, Edit)
- session-summary (Stop)
> I want to run: rm -rf /
[command-safety hook triggers]
This command is blocked for safety. The `rm -rf /` pattern
could delete your entire filesystem. If you need to delete
files, please specify the exact path.
If hooks conflict:
Hooks transform Claude Code from a reactive assistant to a proactive guardian of your development workflow. They prevent mistakes, enforce standards, and automate tedious tasks.
Start with safety hooks—prevent destructive commands and protect sensitive files. Then expand to logging and notifications. Finally, add workflow automation that fits your team's needs.
The best hooks are invisible when things go right but invaluable when they prevent disasters. Build yours with that philosophy in mind.
Deciding between commands, skills, and agents? Check out our Decision Framework to choose the right extension type.
Build Model Context Protocol (MCP) servers and integrations. Create custom tools and capabilities for Claude.