冷蟊初退 孤灯野澜 志起鸡鸣 墓不悲秋 技术交流 软件开发 商业合作 加Q:411239339

Day 5 Hooks 系统:给 AI 装上自动挡

浏览:13次阅读
没有评论

共计 3758 个字符,预计需要花费 10 分钟才能阅读完成。

Claude Code 从入门到脱发 · Day 5

昨天聊了权限管理,那是 " 不让它做什么 "。今天聊 Hooks,这是 " 让它做完之后自动做点什么 "。

你有没有这样的经历:Claude Code 帮你改了一个文件,你看了一眼——缩进乱了。于是你手动跑一下 Prettier。然后它又改了一个文件,缩进又乱了。你又跑 Prettier。如此反复,你开始怀疑人生。

Hooks 就是解决这类问题的。它让你在 Claude Code 的操作前后,自动执行自定义的脚本。编辑文件后自动格式化、执行命令前自动检查、每次提交前自动跑 lint——全自动,你不用动手。

本文你将学到:

  • Hooks 的三种类型:PreToolUse、PostToolUse、Stop
  • 如何配置实用的 Hooks
  • 常见 Hooks 示例(格式化、类型检查、安全扫描)
  • Hooks 的调试技巧

阅读时间 :8 分钟 | 实操时间 :20 分钟 | 难度:中级


Hooks 是什么

Hooks 是 Claude Code 在执行操作前后自动触发的脚本。你定义好规则,它自动执行,不需要你每次手动干预。

三种 Hook 类型:

类型 触发时机 典型用途
PreToolUse 工具执行 拦截危险操作、修改参数
PostToolUse 工具执行 自动格式化、检查结果
Stop 会话结束时 最终审计、清理

配置文件

Hooks 配置在 ~/.claude/settings.json(全局)或 .claude/settings.json(项目级)的 hooks 字段里。

基本结构:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "工具匹配规则",
        "hooks": [
          {
            "type": "command",
            "command": "要执行的命令"
          }
        ]
      }
    ],
    "PostToolUse": [...],
    "Stop": [...]
  }
}

matcher 决定什么时候触发,可以匹配工具名(如 EditWriteBash)。


实用 Hooks 示例

示例一:编辑文件后自动格式化

这是最常用的 Hook。每次 Claude Code 编辑 JS/TS 文件后,自动跑 Prettier。

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "filepath=\"$CLAUDE_FILE_PATH\"; if echo \"$filepath\"| grep -qE'\\.(js|ts|jsx|tsx)$'; then npx prettier --write \"$filepath\"2>/dev/null; fi"
          }
        ]
      }
    ]
  }
}

效果:Claude Code 改完文件,Prettier 自动格式化。你再也不用手动跑了。

示例二:编辑 TypeScript 后自动类型检查

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "filepath=\"$CLAUDE_FILE_PATH\"; if echo \"$filepath\"| grep -qE'\\.tsx?$'; then npx tsc --noEmit 2>&1 | head -20; fi"
          }
        ]
      }
    ]
  }
}

效果:每次改完 .ts/.tsx 文件,自动跑类型检查。如果有类型错误,Claude Code 会看到错误信息并尝试修复。

示例三:拦截 console.log

你不想让代码里留下调试用的 console.log,配一个检查 Hook:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "filepath=\"$CLAUDE_FILE_PATH\"; if echo \"$filepath\"| grep -qE'\\.(js|ts|jsx|tsx)$'&& grep -n'console\\.log'\"$filepath\"2>/dev/null; then echo'WARNING: console.log detected in '$filepath; fi"
          }
        ]
      }
    ]
  }
}

效果:编辑后如果检测到 console.log,会输出警告。Claude Code 看到警告后通常会主动移除。

示例四:长时间命令提醒

有些命令(npm installdocker build)可能跑很久,用 PreToolUse Hook 提醒使用 tmux:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "cmd=\"$CLAUDE_BASH_COMMAND\"; if echo \"$cmd\"| grep -qE'^(npm|pnpm|yarn|cargo|docker) (install|build|run)'; then echo'TIP: Consider running long commands in tmux or background'; fi"
          }
        ]
      }
    ]
  }
}

示例五:Session 结束时审计

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "git diff --name-only | xargs grep -l'console.log'2>/dev/null && echo'Audit: Found console.log in modified files'|| echo'Audit: Clean'"
          }
        ]
      }
    ]
  }
}

效果:每次对话结束时,检查被修改的文件里有没有遗留的 console.log。


Hook 的环境变量

Hook 脚本可以使用 Claude Code 提供的环境变量:

变量 说明
$CLAUDE_FILE_PATH 被操作的文件路径
$CLAUDE_BASH_COMMAND Bash 工具要执行的命令
$CLAUDE_TOOL_NAME 当前工具名称

这些变量让你的 Hook 脚本能够根据具体操作做出不同反应。


Hook 的返回值

Hook 脚本的退出码和输出有特殊含义:

  • 退出码 0:操作继续
  • 退出码非 0(PreToolUse):阻止操作执行
  • stdout 输出:会显示给 Claude Code 看,它会据此调整行为

这意味着 PreToolUse Hook 可以真正 " 拦截 " 操作。比如阻止向超过 500 行的文件继续添加代码:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "filepath=\"$CLAUDE_FILE_PATH\"; if [-f \"$filepath\"] && [$(wc -l < \"$filepath\") -gt 500 ]; then echo \"BLOCKED: File exceeds 500 lines. Split first.\"; exit 1; fi"
          }
        ]
      }
    ]
  }
}

这比在 CLAUDE.md 里写 " 不要超过 500 行 " 强硬多了。CLAUDE.md 是建议,Hook 是铁门。


调试 Hooks

Hook 不生效?几个排查步骤:

  1. 检查 JSON 语法:配置文件一个逗号错了整个都不工作。用 cat ~/.claude/settings.json | python3 -m json.tool 验证语法。

  2. 手动测试命令:把 Hook 里的命令单独在终端跑一下,看有没有报错。

  3. 检查 matcher:matcher 是正则表达式。Edit|Write 匹配 Edit 或 Write 工具。确保工具名拼写正确。

  4. 查看输出:Hook 的 stdout 会显示在 Claude Code 的输出中,看看有没有意外的输出。


常见问题 Q&A

Q1:Hooks 会拖慢 Claude Code 吗?

轻量级的 Hook(格式化、grep 检查)基本没感觉。但如果你的 Hook 跑一个完整的测试套件,那确实会卡住。建议 Hook 脚本控制在几秒内完成。

Q2:Hook 报错了会怎样?

PreToolUse Hook 报错(非 0 退出码)会阻止操作。PostToolUse Hook 报错不会回滚操作,只会显示错误信息。

Q3:能不能用 Python 或 Node.js 写 Hook?

可以。command 字段可以执行任何 shell 命令,包括 python3 script.pynode script.js。对于复杂逻辑,建议写成独立脚本文件,Hook 里只调用脚本。


小结

今天学了 Hooks 系统:

  • 三种类型:PreToolUse(执行前)、PostToolUse(执行后)、Stop(结束时)
  • 实用场景:自动格式化、类型检查、console.log 拦截、文件行数限制
  • PreToolUse 返回非 0 可以阻止操作,是真正的 " 硬约束 "
  • CLAUDE.md 是建议,Hooks 是规则——两者配合使用效果最好

到目前为止,Claude Code 已经能在你的终端里读代码、改代码、遵守你的规范、自动执行检查。但它还是个 " 单机游戏 "——只能操作本地文件和命令。

如果它能连数据库查数据呢?能操作浏览器测试页面呢?能调用 Slack 发通知呢?

明天 Day 6,我们聊 MCP——Model Context Protocol,让 Claude Code 拥有连接外部世界的能力。


系列进度:5/10

正文完
创作不易,扫码加点动力
post-qrcode
 0
果较瘦
版权声明:本站原创文章,由 果较瘦 于2026-03-29发表,共计3758字。
转载说明:除特殊说明外本站文章皆由果较瘦原创发布,转载请注明出处。