Hooks System

Customize Claude Code behavior with Hooks β€” auto-formatting, security interception, notifications, and more

Hooks System

Hooks allow you to insert custom logic at key lifecycle points in Claude Code, such as automatically formatting code, intercepting dangerous commands, sending notifications, and more.

Core Concepts

Each Hook consists of three parts:

  • Event: When it triggers (e.g., PreToolUse β€” before a tool executes)

  • Matcher: Optional tool name filter (e.g., match only Bash or Write)

  • Handler: Shell command, prompt, or sub-agent

Common Events

Event When It Triggers Can Block? Typical Use Cases
PreToolUse Before tool execution Yes (exit code 2) Security interception, file protection
PostToolUse After tool execution No Auto lint/formatting
Notification When Claude sends a notification No Slack/webhook alerts
UserPromptSubmit When user submits a prompt Yes Context augmentation
Stop When Claude finishes responding No Quality checks, summaries
SessionStart When a session starts No Environment initialization

Configuration

Add hooks to .claude/settings.json (project-level) or ~/.claude/settings.json (user-level):

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "prettier --write $FILEPATH"
          }
        ]
      }
    ]
  }
}

Practical Examples

1. Auto-format After File Save

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write $FILEPATH"
          }
        ]
      }
    ]
  }
}

2. Block Dangerous Shell Commands

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo $TOOL_INPUT | grep -qE 'rm -rf|sudo|git push --force' && exit 2 || exit 0"
          }
        ]
      }
    ]
  }
}

exit 2 blocks tool execution; exit 0 allows it to proceed.

3. Protect Sensitive Files from Being Read

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Read",
        "hooks": [
          {
            "type": "command",
            "command": "echo $TOOL_INPUT | grep -qE '\\.env|credentials|secret' && exit 2 || exit 0"
          }
        ]
      }
    ]
  }
}

4. Send Notification on Task Completion

{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"$NOTIFICATION_MESSAGE\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

Input/Output Mechanism

  • Hook scripts receive JSON data via stdin (containing session_id, tool_name, tool_input)

  • Environment variables: $FILEPATH, $TOOL_INPUT, $NOTIFICATION_MESSAGE, etc.

  • PreToolUse exit codes: 0 = allow, 2 = block

Debugging Tips

  • Press Ctrl+O to enable verbose mode and view hook stdout/stderr output

  • Before deploying a hook script, test it manually in the terminal to verify the logic

Important Notes

  • Hook scripts should not take too long to execute, as they will block Claude Code's interaction

  • Project-level hooks take priority over user-level hooks

  • Enterprise plans can enforce organization-wide security hooks via managed-settings.json

Next Steps

  • See Skills for more advanced extensibility

  • See MCP Servers for external tool integration

  • See CLI Tips for command-line usage tips

πŸš€
Get Started with QCode β€” AI Coding Assistant
Official Claude Code relay, fast and reliable, ready to use
View Pricing Plans β†’ Create Account