# Hooks 系统

Hooks 允许你在 Claude Code 的关键生命周期节点插入自定义逻辑 — 自动格式化代码、拦截危险命令、发送通知、审计日志等。Hooks 是 Claude Code 最强大的扩展机制之一。

---

## 一、核心概念

每个 Hook 由三部分组成：

```
事件（When）  →  匹配器（Which）  →  处理器（What）
PreToolUse       matcher: "Bash"     command: "check_safety.sh"
```

- **事件**：触发时机（如 `PreToolUse` — 工具执行前）
- **匹配器**：可选的工具名过滤（如只匹配 `Bash` 或 `Write`）
- **处理器**：Shell 命令、提示词注入 或 子代理

---

## 二、完整事件列表

### 核心事件

| 事件 | 触发时机 | 可阻断 | 典型用例 |
|------|---------|--------|---------|
| **PreToolUse** | 工具执行前 | 是（exit 2） | 安全拦截、参数校验 |
| **PostToolUse** | 工具执行后 | 否 | 自动格式化、日志记录 |
| **Notification** | Claude 发送通知 | 否 | Slack/飞书/钉钉告警 |
| **Stop** | Claude 完成响应 | 否 | 质检、自动提交 |
| **UserPromptSubmit** | 用户提交提示 | 是 | 上下文注入、策略检查 |
| **SessionStart** | 会话启动 | 否 | 环境初始化、欢迎信息 |

### 扩展事件（2026 新增）

| 事件 | 触发时机 | 可阻断 | 典型用例 |
|------|---------|--------|---------|
| **SubagentStop** | 子代理完成 | 否 | 收集子代理结果 |
| **SubagentToolUse** | 子代理使用工具 | 是 | 限制子代理权限 |
| **FileChanged** | 文件被修改 | 否 | 自动 lint、触发构建 |
| **CwdChanged** | 工作目录变更 | 否 | 加载目录特定配置 |
| **ModelChange** | 模型切换 | 否 | 记录模型使用统计 |
| **CompactComplete** | /compact 完成 | 否 | 上下文压缩后处理 |
| **ToolError** | 工具执行出错 | 否 | 错误收集、自动重试逻辑 |

---

## 三、Hook 处理器类型

### 类型 1：Command（Shell 命令）

最常用的类型，执行 Shell 命令：

```json
{
  "type": "command",
  "command": "npx prettier --write $FILEPATH"
}
```

**环境变量**：
| 变量 | 说明 | 可用事件 |
|------|------|---------|
| `$FILEPATH` | 操作的文件路径 | PreToolUse/PostToolUse |
| `$TOOL_INPUT` | 工具输入 JSON | PreToolUse |
| `$TOOL_NAME` | 工具名称 | PreToolUse/PostToolUse |
| `$SESSION_ID` | 会话 ID | 所有 |
| `$NOTIFICATION_MESSAGE` | 通知内容 | Notification |

**stdin 输入**：Hook 脚本还会从 **stdin** 收到一份 JSON，包含 `session_id`、`tool_name`、`tool_input`。需要结构化数据时读它，比解析环境变量更可靠。

**退出码**：
- `0`：允许继续
- `2`：阻断操作（仅 PreToolUse/UserPromptSubmit）
- 其他：视为错误但不阻断

### 类型 2：Prompt（提示注入）

将文本注入 Claude 的上下文：

```json
{
  "type": "prompt",
  "prompt": "记住：所有数据库操作必须使用事务"
}
```

适用场景：在 SessionStart 时注入额外的项目规则。

### 类型 3：Subagent（子代理）

生成子代理处理事件：

```json
{
  "type": "subagent",
  "prompt": "审查刚刚修改的代码，检查是否有安全漏洞"
}
```

适用场景：PostToolUse 后自动审查代码质量。

---

## 四、配置方式

在 `.claude/settings.json`（项目级）或 `~/.claude/settings.json`（用户级）中配置：

```json
{
  "hooks": {
    "事件名": [
      {
        "matcher": "工具名（可选，支持 | 分隔多个）",
        "hooks": [
          {
            "type": "command|prompt|subagent",
            "command": "..."
          }
        ]
      }
    ]
  }
}
```

---

## 五、实战 Recipe

### Recipe 1：文件保存后自动格式化

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

### Recipe 2：拦截危险的 Shell 命令

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo $TOOL_INPUT | grep -qE 'rm -rf /|sudo rm|git push --force|DROP TABLE|DROP DATABASE' && echo '危险命令已拦截' && exit 2 || exit 0"
          }
        ]
      }
    ]
  }
}
```

### Recipe 3：保护敏感文件

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Read|Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "echo $TOOL_INPUT | grep -qE '\\.env|\\.env\\.|credentials|secrets?\\.ya?ml|private.key' && echo '敏感文件访问已拦截' && exit 2 || exit 0"
          }
        ]
      }
    ]
  }
}
```

### Recipe 4：任务完成后系统通知

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

**Linux：**
```json
{
  "hooks": {
    "Notification": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "notify-send 'Claude Code' \"$NOTIFICATION_MESSAGE\""
          }
        ]
      }
    ]
  }
}
```

### Recipe 5：Slack 通知

```json
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "curl -s -X POST https://hooks.slack.com/services/xxx/yyy/zzz -H 'Content-Type: application/json' -d '{\"text\": \"Claude Code 任务完成\"}'"
          }
        ]
      }
    ]
  }
}
```

### Recipe 6：ESLint 自动修复

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "npx eslint --fix $FILEPATH 2>/dev/null; npx prettier --write $FILEPATH 2>/dev/null; exit 0"
          }
        ]
      }
    ]
  }
}
```

### Recipe 7：审计日志

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo \"$(date -u +%Y-%m-%dT%H:%M:%SZ) | session=$SESSION_ID | tool=$TOOL_NAME | file=$FILEPATH\" >> ~/.claude/audit.log"
          }
        ]
      }
    ]
  }
}
```

### Recipe 8：自动运行测试

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "echo $FILEPATH | grep -qE '\\.(ts|tsx|js|jsx)$' && echo $FILEPATH | grep -qvE '\\.test\\.|\\.spec\\.' && npx vitest related $FILEPATH --run 2>/dev/null || exit 0"
          }
        ]
      }
    ]
  }
}
```

### Recipe 9：保护迁移文件

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "echo $FILEPATH | grep -qE 'migrations/|alembic/versions/' && echo '禁止修改已有迁移文件，请创建新迁移' && exit 2 || exit 0"
          }
        ]
      }
    ]
  }
}
```

### Recipe 10：会话启动时注入上下文

```json
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "重要提醒：本项目正在进行 v3.0 大版本重构，所有新代码必须使用 React Server Components，不再支持 pages/ 目录。"
          }
        ]
      }
    ]
  }
}
```

---

## 六、企业级 Hooks

### managed-settings.d/ 配置

企业管理员可通过 `managed-settings.d/` 目录强制全组织的安全策略：

```bash
# 在企业管理目录中创建策略文件
mkdir -p /etc/claude-code/managed-settings.d/
```

```json
// /etc/claude-code/managed-settings.d/security.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "/opt/claude-policy/check_command.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/opt/claude-policy/audit_log.sh"
          }
        ]
      }
    ]
  }
}
```

企业策略**无法被用户或项目级配置覆盖**。

---

## 七、调试与排错

### Verbose 模式

按 `Ctrl+O` 开启 verbose 模式，可以看到：
- Hook 被触发的时机
- Hook 脚本的 stdout/stderr 输出
- Hook 的退出码

### 常见问题

| 问题 | 原因 | 解决方案 |
|------|------|---------|
| Hook 不触发 | matcher 拼写错误 | 检查工具名大小写：`Bash`、`Write`、`Edit`、`Read` |
| Hook 阻断了正常操作 | exit code 逻辑错误 | 确保正常情况 `exit 0`，只在需要拦截时 `exit 2` |
| Hook 执行很慢 | 脚本耗时过长 | Hook 应在 1-2 秒内完成，长任务用后台执行 |
| 环境变量为空 | 事件不提供该变量 | 检查上方环境变量表，确认变量在该事件中可用 |

### 测试 Hook 脚本

在终端中手动测试，再放入配置：

```bash
# 模拟 PreToolUse 的环境变量
FILEPATH="src/main.ts" TOOL_INPUT="rm -rf /" bash -c 'echo $TOOL_INPUT | grep -qE "rm -rf" && echo "blocked" && exit 2 || exit 0'
```

---

## 八、与 Codex Hooks 对比

| 维度 | Claude Code Hooks | Codex Hooks |
|------|------------------|-------------|
| 事件数量 | 17 种 | 较少 |
| 配置方式 | settings.json | config.toml |
| 处理器类型 | command/prompt/subagent | command |
| 企业管理 | managed-settings.d/ | 无 |
| 阻断能力 | exit code 2 | 有限 |

---

## 下一步

- [Skills 技巧](/docs/advanced/skills) — 更高级的扩展方式
- [MCP 服务器](/docs/advanced/mcp) — 连接外部工具
- [自动化与 CI/CD](/docs/advanced/headless) — 无头模式使用
- [CLI 技巧](/docs/usage/cli-tips) — 命令行使用技巧