Skip to content

Chapter 13 · Hooks Automation ​

Chapter goals: Understand Claude Code's Hooks mechanism — automatically executing custom commands at key tool call lifecycle nodes to实现 code formatting, security audits, notification pushing, and other automations.

13.1 What Are Hooks ​

Hooks are shell commands that Claude Code自动 executes at specific lifecycle nodes. You don't手动 trigger them — they run automatically on every tool call.

text
User input → Claude thinks → Calls a tool
                              ↑
                         PreToolUse hook (intercept before execution)
                              ↓
                         Tool actually executes
                              ↓
                         PostToolUse hook (post-processing)

Core value: turn engineering conventions from "verbal agreements" into "forced execution." For example, if you tell Claude "run lint after every code write," it might forget; but configure a PostToolUse hook, and lint runs自动 after every file write — impossible to bypass.

13.2 Hook Types ​

Claude Code supports the following hook events:

EventTrigger TimingTypical Use
PreToolUseBefore tool callIntercept dangerous commands; block writing to sensitive files
PostToolUseAfter tool callAuto-format, run tests, update indexes
NotificationWhen Claude sends a notificationPush to Slack/DingTalk/desktop notification
StopWhen Claude completes a responseSend completion notification; trigger CI
SubagentStopWhen a sub-agent completesCollect子代理 results

13.3 Configuring Hooks ​

Configure hooks in .claude/settings.json (project-level) or ~/.claude/settings.json (global):

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx prettier --write \"$CLAUDE_FILE_PATHS\" 2>/dev/null || true"
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo \"$TOOL_INPUT\" | grep -q 'rm -rf /' && echo 'BLOCK: Dangerous command' && exit 1 || exit 0"
          }
        ]
      }
    ],
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

Key concepts:

  • matcher: regex matching tool names (Write|Edit matches write-file tools);
  • command: the shell command to execute;
  • Exit code: exit 0 to continue, exit 1 to block (only effective for PreToolUse).

13.4 Practical Scenarios ​

Scenario 1: Auto-format After Writing Files ​

json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          { "type": "command", "command": "npx prettier --write \"$CLAUDE_FILE_PATHS\" 2>/dev/null || true" },
          { "type": "command", "command": "npx eslint --fix \"$CLAUDE_FILE_PATHS\" 2>/dev/null || true" }
        ]
      }
    ]
  }
}

Every time Claude writes code, prettier and eslint run自动 — code style never drifts.

Scenario 2: Block Modifications to Sensitive Files ​

json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "echo \"$CLAUDE_FILE_PATHS\" | grep -qE '(\\.env|credentials|secrets)' && echo 'BLOCK: Sensitive files cannot be modified' && exit 1 || exit 0"
          }
        ]
      }
    ]
  }
}

Any attempt to modify .env, credentials, or other sensitive files is自动 intercepted.

Scenario 3: Slack Notification ​

json
{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "curl -s -X POST $SLACK_WEBHOOK -H 'Content-Type: application/json' -d '{\"text\":\"Claude Code: needs human confirmation\"}'"
          }
        ]
      }
    ]
  }
}

13.5 Debugging Hooks ​

Troubleshooting steps when hooks don't take effect:

bash
# 1. Confirm settings.json syntax is correct
cat .claude/settings.json | python3 -m json.tool

# 2. Test the hook command manually
echo '{"file_path": "/tmp/test.ts"}' | npx prettier --stdin-filepath test.ts

# 3. Check Claude Code's hook logs
claude --debug

Security Reminder

Hooks execute arbitrary shell commands with your user权限. Do not blindly accept hooks configurations in untrusted projects — a malicious hook can do anything. Claude Code will ask you to confirm the first time it encounters new hooks.

Chapter Summary ​

  • Hooks自动 execute at tool call lifecycle nodes; turn conventions from "agreements" into "enforcement";
  • Five events: PreToolUse (intercept), PostToolUse (post-process), Notification, Stop, SubagentStop;
  • Configured in settings.json; matcher matches tool names; exit 1 blocks execution;
  • Typical scenarios: auto-formatting, sensitive file protection, notification pushing.

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. To auto-run prettier after Claude writes a file each time, which hook event should be used?

2. What happens when a PreToolUse hook's command returns exit 1?

3. What is the purpose of the matcher field in hooks configuration?

4. Regarding hook security, what is the correct approach?

🛠️ Hands-on Practice ​

  1. Configure a PostToolUse hook: auto-run ruff check --fix after Claude writes a Python file each time.
  2. Configure a PreToolUse hook: block any Bash命令 containing DROP TABLE or DELETE FROM (without a WHERE clause).
  3. Configure a Notification hook: send a system desktop notification when Claude completes a long task.

After completing, proceed to Chapter 14: IDE Integration.