Claude Code Hooks Setup Skill
This skill guides you through setting up Claude Code hooks with a thorough interview process to ensure the hook configuration exactly matches user requirements.
Critical Workflow
ALWAYS follow this interview-first approach:
- Interview the user - Never skip this step, even if they provide initial details
- Confirm understanding - Summarize back what you understood
- Generate the hook configuration - Create the JSON structure
- Safely apply to settings - Merge with existing settings or create new
Step 1: Interview Questions
Ask these questions to fully understand the user's needs. Ask 2-3 at a time max to avoid overwhelming them.
Essential Questions (Always Ask)
What should the hook do?
- "What specific action or behavior do you want to automate?"
- "Can you describe the problem this hook should solve?"
When should it trigger?
- "Which hook event should trigger this?" (Show the list below)
- "Should it run for all tools or only specific ones?"
What's the desired outcome?
- "Should it block operations, modify them, log them, or just observe?"
- "What should happen when the hook runs successfully vs fails?"
Hook Event Options (Present to User)
| Event | When It Runs | Common Use Cases |
|---|---|---|
PreToolUse |
Before any tool executes | Block/allow tools, validate inputs, log commands |
PostToolUse |
After tool completes | Auto-format, lint, run tests, notify |
PermissionRequest |
When permission dialog shows | Auto-approve safe operations |
UserPromptSubmit |
When user submits prompt | Add context, validate prompts |
Notification |
When Claude sends notifications | Custom alerts, desktop notifications |
Stop |
When Claude finishes responding | Continue work, verify completion |
SubagentStop |
When subagent task completes | Validate subagent work |
PreCompact |
Before context compaction | Save state, custom summary |
SessionStart |
When session begins/resumes | Load context, set env vars |
SessionEnd |
When session ends | Cleanup, save logs |
Matcher Questions (For PreToolUse, PostToolUse, PermissionRequest)
- Which tools should this affect?
- "Should this apply to all tools (
*) or specific ones?" - Common matchers:
Bash,Write,Edit,Read,Glob,Grep,Task,WebFetch,WebSearch - "You can combine with regex:
Edit|Writematches both"
- "Should this apply to all tools (
Implementation Questions
How should the hook be implemented?
commandtype: Run a bash command/scriptprompttype: Use LLM evaluation (only for Stop/SubagentStop)
What should the hook output?
- Exit code 0: Success (continues normally)
- Exit code 2: Block the operation (shows stderr to Claude)
- JSON output: For advanced control (decisions, modified inputs)
Where should this hook be stored?
- User settings (
~/.claude/settings.json): Applies to all projects - Project settings (
.claude/settings.json): Shared with team - Local settings (
.claude/settings.local.json): Personal, not committed
- User settings (
Context Questions
Does the hook need project context?
- Scripts can use
$CLAUDE_PROJECT_DIRfor project-relative paths - Environment variables available to hooks
- Scripts can use
Should there be a timeout?
- Default: 60 seconds
- Can specify custom timeout per hook
Step 2: Confirm Understanding
Before proceeding, summarize back:
Based on our discussion, here's what I'll set up:
- **Hook Event**: [event name]
- **Matcher**: [pattern or "all tools"]
- **Action**: [what the hook does]
- **Implementation**: [command/prompt and what it does]
- **Output Behavior**: [what happens on success/failure]
- **Storage Location**: [which settings file]
Does this match what you need? Any adjustments?
Step 3: Generate Hook Configuration
JSON Structure Reference
{
"hooks": {
"EventName": [
{
"matcher": "ToolPattern",
"hooks": [
{
"type": "command",
"command": "your-command-here",
"timeout": 60
}
]
}
]
}
}
For Events Without Matchers
UserPromptSubmit, Stop, SubagentStop, Notification, SessionStart, SessionEnd, PreCompact don't use matchers:
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "/path/to/validator.py"
}
]
}
]
}
}
Step 4: Safely Apply Configuration
CRITICAL: Never corrupt existing settings files.
Check for Existing Settings
# Check if settings file exists
if [ -f ".claude/settings.json" ]; then
echo "Existing settings found"
else
echo "No existing settings"
fi
Safe Merge Strategy
- Read existing file (if exists)
- Parse as JSON to validate
- Merge hooks - Don't overwrite, append to existing arrays
- Write back with proper formatting
Helper Script Usage
Use the provided scripts/apply_hooks.py script:
python3 "$SKILL_DIR/scripts/apply_hooks.py" \
--settings-file ".claude/settings.json" \
--hook-event "PostToolUse" \
--matcher "Edit|Write" \
--command "npx prettier --write \"\$(jq -r '.tool_input.file_path')\"" \
--timeout 30
Or use scripts/apply_hooks_json.py for full JSON input:
echo '{"hooks":{"PostToolUse":[...]}}' | python3 "$SKILL_DIR/scripts/apply_hooks_json.py" --settings-file ".claude/settings.json"
Common Hook Recipes
See references/hook-recipes.md for tested, ready-to-use configurations including:
- Code formatting (Prettier, Black, gofmt)
- File protection
- Command logging
- Desktop notifications
- Git safeguards
- Test runners
- Linting
Hook Input/Output Reference
See references/hook-io-reference.md for complete documentation on:
- Input JSON schemas for each event
- Output formats (exit codes vs JSON)
- Decision control options
- Advanced JSON output fields
Debugging Hooks
If hooks aren't working:
- Check registration: Run
/hooksin Claude Code - Verify syntax: Ensure valid JSON in settings
- Test commands: Run hook command manually with sample input
- Check permissions: Ensure scripts are executable
- Review logs: Use
claude --debugfor detailed output