plugins/plugin-creator/skills/hooks-core-reference/SKILL.md
Hook system fundamentals — all events, configuration structure, matchers per event type, environment variables, execution behavior, security, and debugging. Use when creating hooks, understanding hook events, matchers, configuration locations, environment variables, or troubleshooting hook issues.
npx skillsauth add jamie-bitflight/claude_skills hooks-core-referenceInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Hooks execute custom commands or prompts in response to Claude Code events. Use for automation, validation, formatting, and security.
For JSON input/output schemas, activate Skill(skill: "plugin-creator:hooks-io-api").
For working examples and patterns, activate Skill(skill: "plugin-creator:hooks-patterns").
| Event | When Fired | Matcher Applies | Common Uses |
| -------------------- | ------------------------------------------------------------ | -------------------------------------- | ----------------------- |
| PreToolUse | Before tool execution | Yes — tool name | Validation, blocking |
| PermissionRequest | When user shown permission dialog | Yes — tool name | Auto-approval policies |
| PostToolUse | After successful tool execution | Yes — tool name | Formatting, linting |
| PostToolUseFailure | After tool fails | Yes — tool name | Error handling |
| Notification | When Claude wants attention | Yes — notification type | Custom notifications |
| UserPromptSubmit | User submits prompt | No | Input validation |
| UserPromptExpansion| Slash command expands into a full prompt | Yes — command name | Block expansions, inject context |
| Stop | Claude finishes response | No | Cleanup, final checks |
| SubagentStart | When spawning a subagent | Yes — agent type name | Subagent initialization |
| SubagentStop | Subagent (Agent tool) completes | Yes — agent type name | Result validation |
| TeammateIdle | Agent team teammate about to go idle | No | Quality gates |
| TaskCompleted | Task being marked as completed | No | Completion enforcement |
| InstructionsLoaded | CLAUDE.md or rules file loaded into context | No | Observability |
| ConfigChange | Configuration file changes during session | Yes — config source | Settings auditing |
| WorktreeCreate | Worktree being created (--worktree or isolation: worktree) | No | Custom VCS integration |
| WorktreeRemove | Worktree being removed at session exit or subagent finish | No | Custom VCS cleanup |
| PreCompact | Before context compaction | Yes — manual or auto | State backup |
| PostCompact | After context compaction completes | Yes — manual or auto | React to new state |
| Elicitation | MCP server requests user input mid-task | Yes — MCP server name | Programmatic responses |
| ElicitationResult | User responds to MCP elicitation | Yes — MCP server name | Observe/modify response |
| Setup | Repository setup/maintenance | Yes — init or maintenance | One-time operations |
| CwdChanged | Working directory changes during session | No | Reload env, activate toolchains |
| FileChanged | Watched file changes on disk | Yes — literal filename pattern | Monitor .env, direnv integration |
| PermissionDenied | Auto mode classifier denies a tool call | Yes — tool name | Log denials, allow retry |
| SessionStart | Session begins or resumes | Yes — startup, resume, etc. | Environment setup |
| SessionEnd | Session ends | Yes — exit reason | Cleanup, persistence |
Note: The Agent tool was renamed from Task in Claude Code v2.1.63. Use
Agentas the matcher name for tool-based hooks targeting subagent operations.
For a visual overview of the full event sequence, see the ../hooks-guide/references/hooks-lifecycle.png.
managed-settings.json (enterprise).claude/settings.local.json (gitignored).claude/settings.json (shared via git)~/.claude/settings.json (personal)hooks/hooks.json or frontmatterNote: Enterprise administrators can use allowManagedHooksOnly to block user, project, and plugin hooks.
Hooks are organized by matchers, where each matcher can have multiple hooks:
{
"hooks": {
"EventName": [
{
"matcher": "ToolPattern",
"hooks": [
{
"type": "command",
"command": "your-command-here"
}
]
}
]
}
}
Fields:
PreToolUse, PermissionRequest, PostToolUse); matches agent type name for SubagentStart/SubagentStop; matches exit reason for SessionEnd; matches config source for ConfigChange; matches MCP server name for Elicitation/ElicitationResult
Write matches only the Write toolEdit|Write or Notebook.** to match all tools. Also accepts empty string ("") or omit matchertype: "command" for bash commands, "prompt" for LLM evaluation, "http" for HTTP POST requests, or "agent" for agentic verifiers with tool accesscommand: (For type: "command") The bash command to executeurl: (For type: "http") The URL to POST the hook input toprompt: (For type: "prompt" or type: "agent") The prompt to send to the modeltimeout: (Optional) Seconds before canceling (default: 600 for commands, 30 for prompts, 60 for agent hooks)async: (For type: "command") If true, runs in background without blocking ClaudeasyncRewake: (For type: "command") If true, runs in background and wakes Claude when process exits with code 2 — stderr/stdout delivered as a system reminderUse $CLAUDE_PROJECT_DIR to reference scripts in your project:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-style.sh"
}
]
}
]
}
}
For UserPromptSubmit and Stop, omit the matcher. SubagentStart and SubagentStop support matchers filtered by agent type name. SessionEnd supports matchers filtered by exit reason. Example for events that don't use matchers:
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "/path/to/prompt-validator.py"
}
]
}
]
}
}
| Matcher | Description |
| ------------------- | ------------------------------ |
| Agent | Subagent operations |
| Bash | Shell commands |
| Glob | File pattern matching |
| Grep | Content search |
| Read | File reading |
| Edit | File editing |
| Write | File writing |
| WebFetch | Web fetching |
| WebSearch | Web search |
| Notebook.* | NotebookEdit, NotebookRead |
| mcp__<server>__.* | All tools from MCP server |
| mcp__.*__write.* | MCP write tools across servers |
| Matcher | Trigger |
| --------- | -------------------------------------- |
| startup | New session started |
| resume | --resume, --continue, or /resume |
| clear | /clear command |
| compact | Auto or manual compact |
| Matcher | Trigger |
| -------- | --------------------------- |
| manual | /compact command |
| auto | Auto-compact (full context) |
| Matcher | Trigger |
| ------------- | ------------------------------- |
| init | --init or --init-only flags |
| maintenance | --maintenance flag |
Matched against the agent type name. Values include built-in agents (Bash, Explore, Plan) and custom agent names from .claude/agents/.
Note: The Agent tool was renamed from Task in Claude Code v2.1.63. Use Agent as the matcher name for PreToolUse/PostToolUse hooks targeting the subagent-spawning tool call.
| Matcher | Trigger |
| ------------------------------ | ---------------------------------------------- |
| clear | Session cleared with /clear command |
| logout | User logged out |
| prompt_input_exit | User exited while prompt input was visible |
| bypass_permissions_disabled | Bypass permissions mode was disabled |
| other | Other exit reasons |
| Matcher | When it fires |
| ------------------- | ----------------------------------------- |
| user_settings | ~/.claude/settings.json changes |
| project_settings | .claude/settings.json changes |
| local_settings | .claude/settings.local.json changes |
| policy_settings | Managed policy settings (non-blocking) |
| skill | Skill file changes |
| Matcher | Trigger |
| -------- | --------------------------------------------------- |
| manual | After /compact command |
| auto | After auto-compact when the context window is full |
Matched against the MCP server name (the server requesting or receiving user input).
| Matcher | Trigger |
| -------------------- | ------------------------------------ |
| permission_prompt | Permission requests from Claude |
| idle_prompt | Claude waiting for input (60s+ idle) |
| auth_success | Authentication success |
| elicitation_dialog | MCP tool elicitation |
Runs when Claude Code is invoked with repository setup and maintenance flags (--init, --init-only, or --maintenance).
Use Setup hooks for:
Key characteristics:
CLAUDE_ENV_FILE for persisting environment variablesRuns when Claude Code starts a new session or resumes an existing session.
Use SessionStart hooks for:
Important: For one-time operations like installing dependencies or running migrations, use Setup hooks instead. SessionStart runs on every session, so keep these hooks fast.
Runs immediately after a tool fails (returns an error). This complements PostToolUse, which only runs on successful tool execution.
Use PostToolUseFailure hooks for:
Recognizes the same matcher values as PreToolUse and PostToolUse.
Runs when a Claude Code subagent (Agent tool call) is spawned.
Use SubagentStart hooks for:
Input includes:
agent_id: Unique identifier for the subagentagent_type: Agent name (built-in like "Bash", "Explore", "Plan", or custom agent names)For the defer permissionDecision and its constraints, see the hooks-guide reference.
| Variable | Description | Available In |
| -------------------- | ---------------------------------- | ------------------- |
| CLAUDE_PROJECT_DIR | Project root (absolute path) | All hooks |
| CLAUDE_CODE_REMOTE | "true" if remote, empty if local | All hooks |
| CLAUDE_ENV_FILE | Path for persisting env vars | SessionStart, Setup, CwdChanged, FileChanged |
| CLAUDE_PLUGIN_ROOT | Plugin directory (absolute) | Plugin hooks |
Example: Setting individual environment variables
#!/bin/bash
if [ -n "$CLAUDE_ENV_FILE" ]; then
echo 'export NODE_ENV=production' >> "$CLAUDE_ENV_FILE"
echo 'export API_KEY=your-api-key' >> "$CLAUDE_ENV_FILE"
echo 'export PATH="$PATH:./node_modules/.bin"' >> "$CLAUDE_ENV_FILE"
fi
exit 0
Example: Persisting all environment changes (e.g., nvm use)
#!/bin/bash
ENV_BEFORE=$(export -p | sort)
# Run setup commands that modify environment
source ~/.nvm/nvm.sh
nvm use 20
if [ -n "$CLAUDE_ENV_FILE" ]; then
ENV_AFTER=$(export -p | sort)
comm -13 <(echo "$ENV_BEFORE") <(echo "$ENV_AFTER") >> "$CLAUDE_ENV_FILE"
fi
exit 0
Variables in $CLAUDE_ENV_FILE are sourced before each Bash command.
MCP tools follow the pattern mcp__<server>__<tool>:
mcp__memory__create_entities - Memory server's create entities toolmcp__filesystem__read_file - Filesystem server's read file toolmcp__github__search_repositories - GitHub server's search tool{
"hooks": {
"PreToolUse": [
{
"matcher": "mcp__memory__.*",
"hooks": [
{
"type": "command",
"command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"
}
]
},
{
"matcher": "mcp__.*__write.*",
"hooks": [
{
"type": "command",
"command": "/home/user/scripts/validate-mcp-write.py"
}
]
}
]
}
}
| Aspect | Behavior | | ------------------- | --------------------------------------- | | Timeout | 600 seconds default for commands, 30s for prompts, 60s for agent hooks, configurable | | Parallelization | All matching hooks run in parallel | | Deduplication | Identical commands deduplicated | | Environment | Runs in cwd with Claude Code's env | | Hook order | Hooks from all sources execute together |
| Event | stdout Handling |
| ---------------------------------------------------------- | -------------------------------- |
| UserPromptSubmit, SessionStart, Setup | Added to Claude's context |
| PreToolUse, PostToolUse, Stop | Shown in verbose mode (Ctrl+O) |
| Notification, SessionEnd, SubagentStart, InstructionsLoaded | Logged to debug only (--debug) |
| PostCompact | Logged to debug only (--debug) |
| TeammateIdle, TaskCompleted, ConfigChange | Shown in verbose mode (Ctrl+O) |
| WorktreeCreate | Stdout must be the absolute path to the created worktree directory |
| WorktreeRemove | Non-blocking; logged to debug |
| CwdChanged, FileChanged | Non-blocking; logged to debug |
| PermissionDenied | Logged to debug only (--debug) |
| Elicitation, ElicitationResult | JSON response controls MCP input |
USE AT YOUR OWN RISK: Claude Code hooks execute arbitrary shell commands on your system automatically. By using hooks, you acknowledge that:
"$VAR" not $VAR.. in file paths$CLAUDE_PROJECT_DIR).env, .git/, keys, etc.Direct edits to hooks in settings files don't take effect immediately:
/hooks menu for changes to applyThis prevents malicious hook modifications from affecting your current session.
claude --debug
claude --debug "hooks" # Filter to hooks only
[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Getting matching hook commands for PostToolUse with query: Write
[DEBUG] Found 1 hook matchers in settings
[DEBUG] Matched 1 hooks for query "Write"
[DEBUG] Found 1 hook commands to execute
[DEBUG] Executing hook command: <Your command> with timeout 600000ms
[DEBUG] Hook command completed with status 0: <Your stdout>
/hooks to see if your hook is registeredclaude --debug to see hook execution detailsclaude plugin validate or /plugin validate for plugin-level hooks| Problem | Cause | Fix |
| -------------------- | -------------------------------- | ---------------------------------------- |
| Hook not running | Wrong matcher pattern | Check case-sensitivity, regex |
| Command not found | Relative path | Use $CLAUDE_PROJECT_DIR |
| JSON not processed | Non-zero exit code | Exit 0 for JSON processing |
| Hook times out | Slow script | Optimize or increase timeout |
| Quotes breaking | Unescaped in JSON | Use \" inside JSON strings |
| Plugin hook not load | Invalid plugin.json hooks config | Validate with claude plugin validate . |
| Path not found | Missing ${CLAUDE_PLUGIN_ROOT} | Use variable for plugin scripts |
For plugin hooks:
# CLI (from terminal)
claude plugin validate .
claude plugin validate ./path/to/plugin
# In Claude Code session
/plugin validate .
/plugin validate ./path/to/plugin
For settings hooks: JSON validation with:
python3 -m json.tool .claude/settings.json
echo '{"tool_name":"Write","tool_input":{"file_path":"test.txt"}}' | ./your-hook.sh
development
When an application needs to store config, data, cache, or state files. When designing where user-specific files should live. When code writes to ~/.appname or hardcoded home paths. When implementing cross-platform file storage with platformdirs.
testing
Enforce mandatory pre-action verification checkpoints to prevent pattern-matching from overriding explicit reasoning. Use this skill when about to execute implementation actions (Bash, Write, Edit) to verify hypothesis-action alignment. Blocks execution when hypothesis unverified or action targets different system than hypothesis identified. Critical for preventing cognitive dissonance where correct diagnosis leads to wrong implementation.
tools
Reference guide for the Twelve-Factor App methodology — 15 principles (12 original + 3 modern extensions) for building portable, resilient, cloud-native applications. Use when evaluating application architecture, designing cloud-native services, reviewing codebases for methodology compliance, advising on configuration, scaling, observability, security, and deployment patterns. Incorporates the 2025 open-source community evolution and cloud-native reinterpretations of each factor.
tools
Converts user-facing documentation (how-to guides, tutorials, API references, examples) in any format — Markdown, PDF, DOCX, PPTX, XLSX, AsciiDoc, RST, HTML, Jupyter notebooks, man pages, TOML/YAML/JSON configs, and plain text — into Claude Code skill directories with SKILL.md plus thematically grouped references/*.md files. Use when given a docs directory or mixed-format documentation to transform into an AI skill. Uses MCP file-reader server for binary formats.