Why This Matters#
Imagine you hired an assistant to work with code. Hooks are like instructions you leave for this assistant: “Before deleting a file — double-check,” “After every change — make sure nothing broke.”
A hook (from the English word “hook”) is a script or instruction that automatically runs at a specific moment during Claude Code’s work. Hooks let you:
- 🛡️ Block dangerous commands (e.g., deleting important files)
- ✅ Check code before saving
- 📋 Add context at the start of a session
- 🔍 Control work quality
When Hooks Trigger#
Claude Code supports several events (moments) to which you can “attach” a hook:
| Event | When It Triggers | What to Use It For |
|---|---|---|
SessionStart |
When a session starts | Load project settings |
UserPromptSubmit |
When you submit a request | Add context or validate the request |
PreToolUse |
Before performing an action | Block dangerous operations |
PostToolUse |
After performing an action | Check the result |
Stop |
When Claude finishes work | Verify everything is done |
SessionEnd |
When a session ends | Cleanup, logging |
Two Types of Hooks#
1. Command Hooks#
Run a script (program). Good for quick, precise checks:
{
"type": "command",
"command": "bash ./scripts/check.sh",
"timeout": 10
}2. Prompt Hooks (Recommended)#
Use AI to analyze the situation. Good for complex checks:
{
"type": "prompt",
"prompt": "Check if this file operation is safe. Return 'approve' or 'deny'.",
"timeout": 30
}Step-by-Step: Setting Up Hooks#
Step 1: Where Hooks Are Stored#
Hooks can be configured in two places:
- In user settings — file
.claude/settings.json(applies to all projects) - In a plugin — file
hooks/hooks.jsoninside the plugin folder
Step 2: Creating a Simple Hook — Blocking Dangerous Commands#
Create the file .claude/settings.json in your project:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/block-rm.sh"
}
]
}
]
}
}Now create the script .claude/hooks/block-rm.sh:
#!/bin/bash
# Read data about the command Claude wants to execute
COMMAND=$(cat | jq -r '.tool_input.command')
# If the command contains rm -rf — block it!
if echo "$COMMAND" | grep -q 'rm -rf'; then
echo '{"hookSpecificOutput": {"permissionDecision": "deny", "permissionDecisionReason": "Dangerous rm -rf command blocked by hook"}}'
else
exit 0 # All good, allow it
fiStep 3: Security Hook from the security-guidance Plugin#
The security-guidance plugin contains a hook that reminds about security when editing files:
{
"description": "Security reminder hook",
"hooks": {
"PreToolUse": [
{
"hooks": [
{
"type": "command",
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/security_reminder_hook.py"
}
],
"matcher": "Edit|Write|MultiEdit"
}
]
}
}Note:
matcher— a filter: the hook triggers only forEdit,Write, orMultiEditoperations${CLAUDE_PLUGIN_ROOT}— a variable pointing to the plugin folder (always use it for portability)
Step 4: Hooks from the Hookify Plugin#
The Hookify plugin is a powerful tool that lets you create hooks through simple .local.md files. Here’s an example blocking the dangerous rm command:
---
name: block-dangerous-rm
enabled: true
event: bash
pattern: rm\s+-rf
action: block
---
⚠️ **Dangerous rm command detected!**
This command may delete important files. Please:
- Verify the path is correct
- Consider a safer alternative
- Make sure you have a backupAnd here’s a hook that requires running tests before finishing:
---
name: require-tests-run
enabled: false
event: stop
action: block
conditions:
- field: transcript
operator: not_contains
pattern: npm test|pytest|cargo test
---
**No tests detected!**
Run tests before finishing to make sure the changes work.Hookify intercepts all major events: PreToolUse, PostToolUse, Stop, UserPromptSubmit.
Matchers — Filters for Hooks#
A matcher is a filter that determines exactly when a hook triggers:
"matcher": "Write" // Only for file writes
"matcher": "Read|Write|Edit" // For reading, writing, and editing
"matcher": "Bash" // Only for bash commands
"matcher": "*" // For all operations
"matcher": "mcp__.*" // For all MCP toolsImportant to Remember#
⚠️ Hooks are loaded at session start. If you change a hook, you need to restart Claude Code for changes to take effect.
For debugging, use:
claude --debugYou can check loaded hooks with the /hooks command inside Claude Code.
Lesson Summary#
- Hooks are automatic scripts that trigger at specific moments during Claude Code’s work
- There are command hooks (scripts) and prompt hooks (AI-based)
- Hooks let you block dangerous operations, check code quality, and add context
- Matchers filter which tools a hook applies to
- The Hookify plugin lets you create hooks through simple Markdown files
- Always use
${CLAUDE_PLUGIN_ROOT}for paths in plugins