hooks-core-reference

Installation
SKILL.md

Claude Code Hooks — Core Reference (January 2026)

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").


All Hook Events

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
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
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 Agent as 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.


Configuration

Configuration Locations (Precedence highest to lowest)

  1. Managed - managed-settings.json (enterprise)
  2. Local - .claude/settings.local.json (gitignored)
  3. Project - .claude/settings.json (shared via git)
  4. User - ~/.claude/settings.json (personal)
  5. Plugin - hooks/hooks.json or frontmatter
  6. Capability - Skill/Command/Agent frontmatter

Note: Enterprise administrators can use allowManagedHooksOnly to block user, project, and plugin hooks.

Structure

Hooks are organized by matchers, where each matcher can have multiple hooks:

{
  "hooks": {
    "EventName": [
      {
        "matcher": "ToolPattern",
        "hooks": [
          {
            "type": "command",
            "command": "your-command-here"
          }
        ]
      }
    ]
  }
}

Fields:

  • matcher: Pattern to match tool names, case-sensitive (for 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
    • Simple strings match exactly: Write matches only the Write tool
    • Supports regex: Edit|Write or Notebook.*
    • Use * to match all tools. Also accepts empty string ("") or omit matcher
  • hooks: Array of hooks to execute when pattern matches
    • type: "command" for bash commands, "prompt" for LLM evaluation, "http" for HTTP POST requests, or "agent" for agentic verifiers with tool access
    • command: (For type: "command") The bash command to execute
    • url: (For type: "http") The URL to POST the hook input to
    • prompt: (For type: "prompt" or type: "agent") The prompt to send to the model
    • timeout: (Optional) Seconds before canceling (default: 600 for commands, 30 for prompts, 60 for agent hooks)

Project-Specific Hook Scripts

Use $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"
          }
        ]
      }
    ]
  }
}

Events Without Matchers

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"
          }
        ]
      }
    ]
  }
}

Event-Specific Matchers

PreToolUse / PermissionRequest / PostToolUse Common Matchers

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

SessionStart Matchers

Matcher Trigger
startup New session started
resume --resume, --continue, or /resume
clear /clear command
compact Auto or manual compact

PreCompact Matchers

Matcher Trigger
manual /compact command
auto Auto-compact (full context)

Setup Matchers

Matcher Trigger
init --init or --init-only flags
maintenance --maintenance flag

SubagentStart / SubagentStop Matchers

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.

SessionEnd Matchers

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

ConfigChange Matchers

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

PostCompact Matchers

Matcher Trigger
manual After /compact command
auto After auto-compact when the context window is full

Elicitation / ElicitationResult Matchers

Matched against the MCP server name (the server requesting or receiving user input).

Notification Matchers

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

Important Hook Events

Setup Hook

Runs when Claude Code is invoked with repository setup and maintenance flags (--init, --init-only, or --maintenance).

Use Setup hooks for:

  • One-time or occasional operations (dependency installation, migrations, cleanup)
  • Operations you don't want on every session start

Key characteristics:

  • Requires explicit flags because running automatically would slow down every session start
  • Has access to CLAUDE_ENV_FILE for persisting environment variables
  • Output added to Claude's context

SessionStart Hook

Runs when Claude Code starts a new session or resumes an existing session.

Use SessionStart hooks for:

  • Loading development context (existing issues, recent changes)
  • Setting up environment variables

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.

PostToolUseFailure Hook

Runs immediately after a tool fails (returns an error). This complements PostToolUse, which only runs on successful tool execution.

Use PostToolUseFailure hooks for:

  • Error recovery actions
  • Logging tool failures
  • Custom error handling and reporting

Recognizes the same matcher values as PreToolUse and PostToolUse.

SubagentStart Hook

Runs when a Claude Code subagent (Agent tool call) is spawned.

Use SubagentStart hooks for:

  • Subagent initialization
  • Logging subagent creation
  • Context injection for specific agent types

Input includes:

  • agent_id: Unique identifier for the subagent
  • agent_type: Agent name (built-in like "Bash", "Explore", "Plan", or custom agent names)

Environment Variables

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
CLAUDE_PLUGIN_ROOT Plugin directory (absolute) Plugin hooks

SessionStart Environment Persistence

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.


Working with MCP Tools

MCP tools follow the pattern mcp__<server>__<tool>:

  • mcp__memory__create_entities - Memory server's create entities tool
  • mcp__filesystem__read_file - Filesystem server's read file tool
  • mcp__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"
          }
        ]
      }
    ]
  }
}

Execution Details

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

Output Handling by Event

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
Elicitation, ElicitationResult JSON response controls MCP input

Security Considerations

Disclaimer

USE AT YOUR OWN RISK: Claude Code hooks execute arbitrary shell commands on your system automatically. By using hooks, you acknowledge that:

  • You are solely responsible for the commands you configure
  • Hooks can modify, delete, or access any files your user account can access
  • Malicious or poorly written hooks can cause data loss or system damage
  • Anthropic provides no warranty and assumes no liability for any damages
  • You should thoroughly test hooks in a safe environment before production use

Security Best Practices

  1. Validate and sanitize inputs - Never trust input data blindly
  2. Always quote shell variables - Use "$VAR" not $VAR
  3. Block path traversal - Check for .. in file paths
  4. Use absolute paths via the $CLAUDE_PROJECT_DIR variable - Specify full paths for scripts (use $CLAUDE_PROJECT_DIR)
  5. Skip sensitive files - Avoid .env, .git/, keys, etc.

Configuration Safety

Direct edits to hooks in settings files don't take effect immediately:

  1. Hooks snapshot captured at startup
  2. Snapshot used throughout the session
  3. Warns if hooks are modified externally
  4. Requires review in /hooks menu for changes to apply

This prevents malicious hook modifications from affecting your current session.


Debugging

Enable Debug Mode

claude --debug
claude --debug "hooks"  # Filter to hooks only

Debug Output Example

[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>

Basic Troubleshooting

  1. Check configuration - Run /hooks to see if your hook is registered
  2. Verify syntax - Ensure your JSON settings are valid
  3. Test commands - Run hook commands manually first
  4. Check permissions - Make sure scripts are executable
  5. Review logs - Use claude --debug to see hook execution details
  6. Validate plugin hooks - Use claude plugin validate or /plugin validate for plugin-level hooks

Common Issues

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

Validation Commands

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

Test Commands Manually

echo '{"tool_name":"Write","tool_input":{"file_path":"test.txt"}}' | ./your-hook.sh

Sources

Related skills

More from jamie-bitflight/claude_skills

Installs
5
GitHub Stars
40
First Seen
Mar 29, 2026