hook-creator
Guide for creating and configuring Claude Code hooks. This skill should be used when users want to create a new hook, update an existing hook, debug hook behavior, or configure hook-based automation — user-defined commands or prompts that execute at specific points in Claude Code's lifecycle. Use when users ask to create, design, configure, or troubleshoot hooks.
SKILL.md
| Name | hook-creator |
| Description | Guide for creating and configuring Claude Code hooks. This skill should be used when users want to create a new hook, update an existing hook, debug hook behavior, or configure hook-based automation — user-defined commands or prompts that execute at specific points in Claude Code's lifecycle. Use when users ask to create, design, configure, or troubleshoot hooks. |
name: hook-creator description: Guide for creating and configuring Claude Code hooks. This skill should be used when users want to create a new hook, update an existing hook, debug hook behavior, or configure hook-based automation — user-defined commands or prompts that execute at specific points in Claude Code's lifecycle. Use when users ask to create, design, configure, or troubleshoot hooks. license: Complete terms in LICENSE.txt
Hook Creator
This skill provides guidance for creating effective hooks.
About Hooks
Hooks are user-defined shell commands or LLM prompts that execute automatically at specific points in Claude Code's lifecycle. They intercept events like tool calls, session start, and prompt submission to add automation, validation, and guardrails.
Handler Types
| Type | Description | Use cases |
|---|---|---|
command | Runs a shell script. Receives JSON on stdin, communicates via exit codes and stdout | Security guards, auto-formatters, test runners, context injectors |
prompt | Sends a prompt to a Claude model for single-turn evaluation. Returns yes/no decision | Prompt validation, stop gates, simple policy checks |
agent | Spawns a subagent with tool access (Read, Grep, Glob) for multi-turn verification | Complex verification requiring file inspection, test result analysis |
Configuration Locations
| Location | Scope | Shareable |
|---|---|---|
.claude/settings.json | Current project | Yes, committable |
~/.claude/settings.json | All projects | No, local machine |
.claude/settings.local.json | Current project | No, gitignored |
| Managed policy settings | Organization-wide | Admin-controlled |
Core Principles
Keep Fast
Hooks block Claude's execution by default. Keep synchronous hooks under 1 second. Use "async": true for long-running operations like test suites or deployments.
Security First
Hooks run with full user permissions. Validate all input, quote shell variables ("$VAR" not $VAR), use absolute paths, and block path traversal.
Minimal Scope
Use specific matchers to limit when hooks fire. A Bash security hook should match Bash, not run on every tool call. An auto-formatter should match Write|Edit, not all PostToolUse events.
Fail Safe
Stop and SubagentStop hooks must always check stop_hook_active to prevent infinite loops. Use exit code 0 (not exit 2) as the default path. Only block when you have a clear reason.
Hook Creation Process
Follow these steps in order. Skip only when there is a clear reason.
Step 1: Understand the Purpose
Before creating a hook, gather concrete examples of what it should do:
- What event should trigger it? (tool call, session start, prompt submit, stop)
- Should it block actions, add context, or run side effects?
- Does it need to inspect files (agent hook) or just evaluate data (prompt/command hook)?
- Should it run synchronously (blocking) or asynchronously (background)?
Example questions to ask:
- "What specific behavior do you want to automate or enforce?"
- "Should this run on every tool call, or only specific tools?"
- "Does this need to block Claude, or just observe and log?"
Step 2: Plan the Configuration
Based on the use case, determine:
- Event: Which lifecycle point to hook into. See
references/hook-events.mdfor all 12 events with schemas and decision control options. - Matcher: Regex pattern to filter when the hook fires (tool name, session source, etc.)
- Handler type:
commandfor scripts,promptfor LLM evaluation,agentfor multi-turn verification - Scope: Project (
.claude/settings.json), user (~/.claude/settings.json), or local (.claude/settings.local.json) - Async: Whether to run in the background (command hooks only)
For established patterns that match common use cases, see references/hook-patterns.md.
Step 3: Initialize the Hook
Run the initialization script to generate a template:
scripts/init_hook.py <name> --event <EventName> --type <command|prompt|agent> --scope <project|user|local>
Or specify a custom directory:
scripts/init_hook.py <name> --event <EventName> --type <command|prompt|agent> --path <directory>
Optional: --matcher <regex> to include a matcher pattern.
The script:
- For
commandtype: creates.claude/hooks/<name>.shwith an event-specific template and prints the JSON settings snippet - For
prompt/agenttype: prints only the JSON settings snippet (no script file needed)
Step 4: Edit the Hook
Command hooks
Edit the generated .sh script:
- Read JSON input from stdin using
jq(the script template includes the pattern) - Extract event-specific fields (e.g.,
tool_input.commandfor PreToolUse) - Add your validation or processing logic
- Use exit codes:
exit 0to allow,exit 2to block, or print JSON to stdout for structured control
Key jq patterns:
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
Prompt hooks
Edit the prompt field in the JSON settings snippet:
- Use
$ARGUMENTSas a placeholder for the hook's JSON input data - The LLM must respond with
{"ok": true}to allow or{"ok": false, "reason": "..."}to block - Keep prompts focused on a single evaluation criterion
Agent hooks
Same prompt format as prompt hooks, but the subagent can use Read, Grep, and Glob tools to investigate before returning a decision. Use for verification requiring file inspection.
Settings JSON structure
Add the JSON snippet to the appropriate settings file. The structure is:
{
"hooks": {
"EventName": [
{
"matcher": "optional-regex",
"hooks": [
{
"type": "command",
"command": "path/to/script.sh"
}
]
}
]
}
}
Multiple matcher groups per event and multiple handlers per matcher group are supported.
Step 5: Validate
Run the validation script to check the settings file:
scripts/validate_hook.py <path-to-settings.json>
The validator checks:
- JSON structure and
hookskey presence - Event names (12 recognized events)
- Matcher patterns (valid regex)
- Handler objects (required fields per type)
- Type field values (
command,prompt,agent) - Timeout and async field types
- Referenced script file existence
Fix any errors and re-run until validation passes.
Step 6: Iterate
Test the hook with real usage and refine:
- Run
claude --debugto see hook execution details (which hooks matched, exit codes, output) - Toggle verbose mode with
Ctrl+Oto see hook progress in the transcript - Use the
/hooksmenu to view, add, and delete hooks interactively
Common troubleshooting:
- Hook not firing: Check the event name and matcher pattern. Verify the settings file location.
- Infinite Stop loop: Ensure Stop hooks check
stop_hook_activeand allow stopping when it'strue - JSON parse errors: Ensure stdout contains only the JSON object. Shell profile startup text can interfere.
- Hook blocked but tool proceeds: Use exit code 2 (not exit 1) to block. Exit 1 is non-blocking.
- Stale hooks: Settings are snapshotted at startup. Restart Claude Code or use
/hooksto apply changes.
Design Patterns
For detailed patterns with configuration examples and script skeletons, see references/hook-patterns.md. Key patterns include:
- Security Guard — PreToolUse/Bash, block dangerous commands
- Auto-Formatter — PostToolUse/Write|Edit, run linter after file changes
- Context Injector — SessionStart, add dynamic project context
- Test Runner — PostToolUse/Write|Edit, async test execution
- Permission Auto-Approver — PreToolUse, auto-allow safe operations
- Prompt Validator — UserPromptSubmit, prompt type, validate user input
- Stop Gate — Stop, prompt/agent type, verify task completeness
Also review the anti-patterns section to avoid common mistakes: infinite Stop loops, overly broad matchers, slow synchronous hooks, and exit code confusion.