devAlice
← AI Agents

Claude Code hooks — 在会话和工具事件上自动运行 shell 命令

settings.json 中的 hooks 可在会话开始、工具调用前后及停止时插入 shell 命令。五个示例:安全拦截、自动格式化、日志记录、外部告警。

Claude Code 的 Hooks — 定义在 settings.jsonhooks 键下 — 让你能够在会话开始、工具调用前后以及会话结束时自动运行 shell 命令。可用于拦截 AI 即将执行的操作、事后修复,以及收尾清理。这是一个强大的扩展点。

我认为 Hooks 是 Claude Code 配置中最容易被低估的部分。不是工具数量决定自动化水平,而是事件响应能力——因为只有将行为锁定在事件钩子上,才能真正保证一致性。

本指南面向 Claude Code 1.x / 官方 Hooks 规范,在 Claude Code 配置 基础上进一步增加自动化和安全保障层。

TL;DR

Hook 事件触发时机典型用途
SessionStart会话开始后立即内存同步提示、环境验证
UserPromptSubmit用户提交 prompt 后立即斜杠命令识别、日志记录、后处理
PreToolUse工具调用前立即阻止危险命令、保护密钥文件
PostToolUse工具调用后立即自动格式化(prettier)、lint、副作用日志
Stop会话结束前立即变更摘要、备份、通知

关键规则

  • 退出码 2阻止工具调用(PreToolUse)。
  • JSON 通过 hook stdin 传入 — 用 jq 解析。
  • Hooks 是 shell 命令 — 注意 OS 差异(macOS/Linux/Windows WSL)。

前提条件

  • Claude Code 1.x 已安装 — Claude Code 配置
  • jq 已安装(brew install jq / apt install jq / winget install jqlang.jq
  • 有权编辑 settings.json(通常是 ~/.claude/settings.json

下载基础配置

devAlice 推荐的五条 Hook 基础配置 + 权限拒绝/允许列表 — 下载后按需定制。

settings.json
# 1. 下载
curl -fsSL https://devalice.jaceclub.com/assets/ai-agents/claude-code-hooks/settings.example.json -o settings.json
 
# 2. 验证 SHA-256
shasum -a 256 settings.json
# 期望值:30c1d4117a935cac03b601c71125c11b71733c8c59517ab129fd8913cfb8a69e
 
# 3. 检查(尤其是 PreToolUse hooks)
less settings.json
 
# 4. 复制到目标位置(macOS/Linux)
mkdir -p ~/.claude
cp settings.json ~/.claude/settings.json

⚠️ 注意:Hooks 会运行任意 shell 命令务必先检查他人的 Hooks 再应用。此示例是安全的五条 Hook 基础配置,但请根据自身环境审阅并调整。


1. Hook 结构 — 5 分钟

~/.claude/settings.json 中的 hooks 键:

{
  "hooks": {
    "EventName": [
      {
        "matcher": "正则或工具名",  // 可选
        "hooks": [
          {
            "type": "command",
            "command": "/bin/bash -lc '实际的 shell 命令'"
          }
        ]
      }
    ]
  }
}

匹配规则

  • matcher → 每次事件均触发
  • matcher = 工具名(BashWriteEditRead 等)→ 仅匹配该工具
  • matcher = 正则(^/(?:ej|euijinpro)\\b)→ 用于 UserPromptSubmit,匹配 prompt 文本

通过 stdin 传入的 JSON

{
  "session_id": "...",
  "transcript_path": "/path/to/transcript.jsonl",
  "cwd": "/Users/...",
  "tool_name": "Bash",
  "tool_input": { "command": "..." },
  "tool_response": { /* 仅 PostToolUse */ }
}

jq -r .tool_input.command 提取。


2. SessionStart — 加载上下文

最简单的 hook。会话开始时打印一行:

"SessionStart": [
  {
    "hooks": [
      {
        "type": "command",
        "command": "/bin/bash -lc 'printf \"[session start] %s\\nmemory sync: latest (skip)\\n\" \"$(date \"+%Y-%m-%d %H:%M:%S\")\"'"
      }
    ]
  }
]

stdout 会以系统消息的形式呈现。可用于:

  • 触发内存文件自动加载
  • 输出项目专属上下文
  • 启动时输出 git status 摘要
# 更丰富的示例
command='/bin/bash -lc "echo [session start]; git -C \"$PWD\" status -s; git -C \"$PWD\" log --oneline -3"'

3. PreToolUse — 阻止危险命令(价值最高的 Hook)

退出码为 2 即阻止。即使 AI 尝试执行危险的 shell 命令,也能在此拦截。

3.1 危险模式

"PreToolUse": [
  {
    "matcher": "Bash",
    "hooks": [
      {
        "type": "command",
        "command": "/bin/bash -lc 'cmd=$(jq -r .tool_input.command); case \"$cmd\" in *\"rm -rf /\"*|*\"sudo rm\"*|*\":(){\"*) echo \"blocked dangerous command: $cmd\" >&2; exit 2;; esac'"
      }
    ]
  }
]

拦截的危险模式:

  • rm -rf / — 破坏系统
  • sudo rm — 大范围删除(如有需要可加入 allow-list)
  • :(){ — fork bomb(:(){ :|: & };:

3.2 阻止对密钥文件的编辑

{
  "matcher": "Write|Edit",
  "hooks": [
    {
      "type": "command",
      "command": "/bin/bash -lc 'path=$(jq -r .tool_input.file_path); case \"$path\" in */.env|*/credentials.json|*/.aws/credentials) echo \"blocked secret-file edit: $path\" >&2; exit 2;; esac'"
    }
  ]
}

防止意外修改 .envcredentials.json~/.aws/credentials 等敏感文件。

3.3 保护特定目录

command='/bin/bash -lc "path=\$(jq -r .tool_input.file_path); case \"\$path\" in /etc/*|/System/*) echo \"blocked system path: \$path\" >&2; exit 2;; esac"'

4. PostToolUse — 自动格式化 / Lint / 日志记录

工具调用完成后的清理与后处理。

4.1 Prettier 自动格式化

"PostToolUse": [
  {
    "matcher": "Edit|Write|MultiEdit",
    "hooks": [
      {
        "type": "command",
        "command": "/bin/bash -lc 'path=$(jq -r .tool_input.file_path); case \"$path\" in *.ts|*.tsx|*.js|*.jsx) prettier --write \"$path\" 2>/dev/null || true ;; esac'"
      }
    ]
  }
]

AI 执行 Write/Edit 后,prettier 自动整理格式。每次编辑约增加 0.5 秒延迟。

4.2 记录变更文件

command='/bin/bash -lc "path=\$(jq -r .tool_input.file_path); echo \"[changed] \$(date +%T) \$path\" >> ~/.claude/change.log"'

会话中每次文件变更的时序记录。

4.3 类型检查 / Lint(慢速操作移至 Stop)

每次编辑都执行 tsc --noEmit 开销较大。建议放在 Stop Hook 中(§6)。


5. UserPromptSubmit — slash command 检测 / 后处理触发

"UserPromptSubmit": [
  {
    "matcher": "^/(?:ej|euijinpro)\\b",
    "hooks": [
      {
        "type": "command",
        "command": "/bin/bash -lc 'echo \"[ej skill] prompt earmarked for euijin.pro logging\" >&2'"
      }
    ]
  }
]
  • 检测 slash command → 触发外部系统(Slack、独立日志)
  • 自动标记特定关键词(urgentbug
  • token 预算阈值检查

6. Stop — 会话结束时的清理

"Stop": [
  {
    "hooks": [
      {
        "type": "command",
        "command": "/bin/bash -lc 'printf \"\\n[session end] %s\\n\" \"$(date \"+%Y-%m-%d %H:%M:%S\")\"'"
      }
    ]
  }
]

用途:

  • 已变更文件的 git status 摘要
  • 备份(rsyncgit stash
  • 外部关闭通知
  • 一轮类型检查 / 构建
command='/bin/bash -lc "if git diff --quiet; then echo \"[clean]\"; else echo \"[changes]\"; git diff --stat; fi"'

7. permissions — 拒绝 / 允许

独立于 Hooks,但同样是 settings.json 中最重要的安全配置项。

"permissions": {
  "deny": [
    "Bash(rm -rf /:*)",
    "Bash(sudo rm:*)",
    "Read(.env)",
    "Read(.env.local)",
    "Read(.aws/credentials)",
    "Read(*/credentials.json)"
  ],
  "allow": [
    "Bash(git status:*)",
    "Bash(git log:*)",
    "Bash(git diff:*)",
    "Bash(pnpm:*)",
    "Bash(npm:*)",
    "Bash(node:*)"
  ]
}
  • deny 无条件优先 — 与 Hook 拦截形成纵深防御
  • allow 中的命令无需用户确认,自动批准(常用的安全命令)
  • 其余所有操作每次都会询问用户

本指南的 Hooks 与 deny 规则形成叠加保护 — 构成纵深防御。


8. settings.json 位置和优先级

位置范围说明
~/.claude/settings.json用户全局所有项目
<project>/.claude/settings.json项目进入项目时与用户配置合并
<project>/.claude/settings.local.json项目 + 用户本地建议加入 .gitignore

合并顺序:用户 → 项目 → 项目本地,后者覆盖前者。

Hooks 采用追加而非覆盖合并 — 5 个用户 Hook + 3 个项目 Hook = 全部 8 个均会运行。


9. 调试 — Hook 不触发时的排查

9.1 检查 stdin payload

临时调试 hook:

{
  "matcher": "Bash",
  "hooks": [
    {
      "type": "command",
      "command": "/bin/bash -lc 'cat > /tmp/claude-hook-debug.json'"
    }
  ]
}

cat /tmp/claude-hook-debug.json | jq .

9.2 测试退出码

command='/bin/bash -lc "echo dbg >&2; exit 2"'

→ 验证阻止(PreToolUse)是否有效。

9.3 确认 Hook 触发

command='/bin/bash -lc "echo \"[hook fired $$ $(date +%T)]\" >> ~/.claude/hook-trace.log"'

会话后检查日志。

9.4 JSON 语法错误

settings.json 容错性低 — 尾随逗号和转义遗漏是最常见的问题。通过 jq . ~/.claude/settings.json 验证语法。


10. 故障排查

"command not found: jq"

brew install jq(macOS)/ sudo apt install jq(Linux)/ winget install jqlang.jq(Windows)。

Hook 触发但无任何效果

  • command 必须是单行。多行逻辑请用 \\n 分隔,或调用独立脚本文件。
  • 注意 shell 转义 — JSON 内部 \" 需要双重转义。

PreToolUse exit 2 未生效

  • 确认 exit 2 确实执行到 shell 命令的最后一行。
  • set -e 环境下 case ;; 可能以 exit 0 退出 — 请在匹配分支内显式写 exit 2

Prettier 不运行

  • 确认 prettier 已安装在项目根目录(pnpm prettier --version)。
  • Hook PATH 可能不包含 node_modules/.bin → 使用 npx prettier 或绝对路径。

settings.json 变更未生效

  • 需要重启会话,或使用 /config reload(如支持)。
  • 可能因 JSON 语法错误而被静默忽略。用 jq . ~/.claude/settings.json 验证。

后续步骤

参考资料

更新日志

  • 2026-05-12 — 初稿(devAlice M2 种子扩展)