Hooks allow you to automate actions based on Claude's activities. You can run commands, scripts, or notifications when Claude uses tools, completes tasks, or specific events occur.
- Press Cmd/Ctrl + Shift + H to open Hook Manager
- Or click Settings → Hooks in the menu
- Or use the command
/hooksin Claude
- Click Add Hook in the Hook Manager
- Choose an event type:
- PreToolUse: Before Claude uses a tool
- PostToolUse: After Claude uses a tool
- Notification: When Claude shows notifications
- Stop: When conversation is stopped
- SubagentStop: When subagent is stopped
- Set a matcher (regex pattern or leave empty for all)
- Enter your command
- Click Save
Triggers before Claude executes a tool (read_file, write_file, etc.)
Use cases:
- Create backups before file modifications
- Log tool usage
- Validate operations
Example:
# Backup files before editing
cp {{file}} {{file}}.backupTriggers after Claude completes a tool operation
Use cases:
- Run tests after code changes
- Format code after writing
- Commit changes automatically
Example:
# Auto-format Python files after editing
if [[ "{{file}}" == *.py ]]; then
black "{{file}}"
fiTriggers when Claude displays notifications
Use cases:
- Desktop notifications
- Slack/Discord alerts
- Sound alerts
Example:
# macOS notification
osascript -e 'display notification "{{message}}" with title "Claude"'Triggers when you stop Claude's execution
Use cases:
- Cleanup operations
- Save state
- Reset environment
Triggers when a subagent operation is stopped
Use cases:
- Cancel long-running processes
- Clean temporary files
- Leave empty to match all events
- Use exact text:
write_file - Use wildcards:
*.py
- File patterns:
.*\.js$(all JavaScript files) - Path patterns:
.*/tests/.*(files in tests folders) - Tool names:
^(read|write)_file$
Match Python files:
.*\.py$Match test files:
.*test.*\.(js|ts|py)$Match specific tools:
^(write_file|create_file)${{file}}- Current file path{{tool}}- Tool name being used{{message}}- Notification message{{content}}- File content (PostToolUse){{CLAUDE_INSTANCE_ID}}- Current instance ID{{CLAUDE_INSTANCE_NAME}}- Instance name
$HOME- User home directory$PWD- Current working directory$USER- Current user
Event: PostToolUse
Matcher: write_file
Command:
git add "{{file}}" && git commit -m "Auto-commit: Updated {{file}}"Event: PostToolUse
Matcher: .*\.test\.js$
Command:
npm test -- "{{file}}"Event: PreToolUse
Matcher: delete_file
Command:
mkdir -p ~/.claude-backups && cp "{{file}}" ~/.claude-backups/Event: Notification
Matcher: .*completed.*
Command:
say "Task completed" # macOS text-to-speechEvent: PostToolUse
Matcher: .*\.(js|ts|jsx|tsx)$
Command:
prettier --write "{{file}}"- Click Test button next to any hook
- Simulates the event with sample data
- Shows command output
- Helps debug before enabling
- Toggle the switch to enable/disable
- Disabled hooks remain saved but don't execute
- Useful for temporary deactivation
- Click on any hook to edit
- Modify event, matcher, or command
- Click Update to save changes
- Click the trash icon
- Confirm deletion
- Hook is permanently removed
Use && to chain multiple commands:
prettier --write "{{file}}" && eslint --fix "{{file}}"Use bash conditionals:
if [[ "{{file}}" == *.test.* ]]; then
npm test "{{file}}"
fiRun commands in background:
(sleep 5 && npm run build) &Create audit logs:
echo "[$(date)] {{tool}} used on {{file}}" >> ~/.claude-audit.log- Test with
echocommands first - Gradually add complexity
- Use the Test feature
- Use precise matchers
- Avoid overly broad patterns
- Target specific file types
- Add error checking to commands
- Use
|| trueto prevent failures - Log errors for debugging
- Keep commands fast
- Use background tasks for long operations
- Avoid blocking Claude's workflow
- Be cautious with file operations
- Validate inputs when possible
- Don't expose sensitive data
- Check if hook is enabled
- Verify matcher pattern
- Test with empty matcher
- Check Hook Manager for errors
- Test command in terminal first
- Check variable substitution
- Verify file paths exist
- Look for permission issues
- Simplify complex commands
- Use background execution
- Disable unnecessary hooks
- Check system resources
- Use
osascriptfor notifications - Use
sayfor text-to-speech - Use
opento launch applications
- Use
notify-sendfor notifications - Use
espeakfor text-to-speech - Check if commands exist first
- Use PowerShell for advanced features
- Escape paths with spaces
- Use forward slashes in paths
# Auto-stage changes
git add "{{file}}"
# Create feature branches
git checkout -b "claude-edit-$(date +%s)"# Trigger webpack rebuild
touch webpack.config.js
# Run specific npm scripts
npm run lint:fix -- "{{file}}"# Open in VS Code
code "{{file}}"
# Refresh IntelliJ
touch .idea/workspace.xmlRemember: Hooks are powerful but should enhance, not hinder, your workflow. Start small and build up as you discover useful patterns!