1. 为什么你的 Claude Code 需要一套 Hook 刹车系统Claude Code 的 Hook 机制说白了就是在 Claude Code 执行工具调用的关键节点上插入你自己写的 Shell 脚本或 HTTP 请求用来做命令拦截、审计日志、自动格式化这些事。它适合谁适合所有已经在本地用 Claude Code 写代码、但又担心它手滑执行rm -rf或者误提交的开发者。核心检索词就三个Claude Code、PreToolUse、PostToolUse。我刚开始用 Claude Code 的时候最怕的不是它写错代码而是它太自信。有一次它为了清理构建产物直接生成了一条rm -rf ./dist ./build虽然没删到根目录但那个瞬间我意识到AI 编程工具的执行权限不能只靠它自己的判断。Claude Code 的 Hook 生命周期里有两个节点最关键。PreToolUse 在工具真正执行之前触发你可以在这里检查命令、拒绝危险操作相当于刹车。PostToolUse 在工具执行完成之后触发你可以在这里做审计、格式化、安全扫描相当于安全带。再加上 UserPromptSubmit 在用户提交提示词时做入口校验这三个节点配合起来就能把 Claude Code 从“黑盒执行”变成“可控流程”。这篇文章不会只讲概念。我会给出可以直接复制到settings.json的配置片段配合echo和日志验证 Hook 是否真的生效并且把 Base URL、API Key、Model ID 这三件套在 TaoToken 统一 Key 下的配置方式讲清楚。你跟着做十分钟内就能在自己的项目里跑起来。2. TaoToken 统一 Key 的前置准备与 Claude Code 接入在配置 Hook 之前得先让 Claude Code 能正常跑起来。这里我用 TaoToken 的统一 Key 来接入原因是它把多个模型的调用统一到一个 API Key 下省得你在不同模型之间来回切换配置。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。Claude Code 接入 TaoToken 的核心是三件套Base URL、API Key、Model ID。Base URL 填https://taotoken.net/apiAPI Key 在控制台的 API Keys 页面生成Model ID 根据你用的模型填比如claude-sonnet-4-20250514这类。这三者缺一不可少一个就会报 401 或者 model not found。具体操作路径是这样的先打开 https://taotoken.net/api-keys 生成一个 Key然后打开 https://taotoken.net/console 确认你的账户状态和可用模型列表。如果你用的是 Claude Code 的 CLI可以在项目根目录或者用户目录下配置。我习惯在项目级配置这样团队共享的时候不会互相干扰。配置方式有两种。一种是通过环境变量在~/.zshrc或~/.bashrc里加export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEYsk-你的TaoTokenKey export ANTHROPIC_MODELclaude-sonnet-4-20250514另一种是写进 Claude Code 的配置文件。如果你用的是 Claude Code 的 settings 体系可以在~/.claude/settings.json里加{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的TaoTokenKey, ANTHROPIC_MODEL: claude-sonnet-4-20250514 } }这里要注意ANTHROPIC_BASE_URL后面不要加/v1或者/chat/completionsClaude Code 会自己拼接路径。我踩过的坑就是多写了一个/v1结果一直报 404。改回https://taotoken.net/api之后立刻正常。如果你用的是 Codex 或者 Cline 这类工具配置逻辑类似但文件位置不同。Codex 的auth.json里需要填base_url和api_keyCline 的 MCP 配置里需要填baseUrl和apiKey。不管哪个工具三件套的逻辑是一样的Base URL 指向 TaoToken 的 API 入口Key 用你生成的Model ID 填你实际要调用的模型。配置完成后先别急着配 Hook。先用一个最简单的请求验证 Claude Code 能不能正常调用模型。你可以在终端里跑claude -p 用一句话说明什么是 Hook如果返回了正常的文本说明三件套配置没问题。如果报 401检查 Key 是否复制完整如果报 model not found检查 Model ID 是否拼写正确如果报连接超时检查 Base URL 是否写成了https://taotoken.net/api。3. settings.json 可复制配置PreToolUse 与 PostToolUse 拦截现在进入正题。Claude Code 的 Hook 配置写在settings.json里项目级路径是.claude/settings.json用户级路径是~/.claude/settings.json。我建议先在项目级配置这样不影响其他项目。先看 PreToolUse 的配置。它的作用是在 Bash 命令执行之前拦截。配置结构是这样的{ hooks: { PreToolUse: [ { matcher: Bash, hooks: [ { type: command, command: bash \$CLAUDE_PROJECT_DIR/.claude/hooks/pre-tool-check.sh\, timeout: 10 } ] } ] } }这里的matcher填Bash表示只拦截 Bash 工具调用。command里的$CLAUDE_PROJECT_DIR是 Claude Code 内置的环境变量指向项目根目录。timeout是超时时间单位秒。对应的拦截脚本.claude/hooks/pre-tool-check.sh长这样#!/bin/bash input$(cat) command$(echo $input | jq -r .tool_input.command) blocked_patterns( rm -rf / rm -rf /* mkfs. dd if/dev/zero dd if/dev/random :(){ :|: };: ) for pattern in ${blocked_patterns[]}; do if echo $command | grep -qF $pattern; then echo {\hookSpecificOutput\:{\hookEventName\:\PreToolUse\,\permissionDecision\:\deny\,\permissionDecisionReason\:\检测到危险命令: $command\}} exit 0 fi done warn_patterns(rm -rf git push --force git reset --hard DROP TABLE) for pattern in ${warn_patterns[]}; do if echo $command | grep -qE $pattern; then echo {\hookSpecificOutput\:{\hookEventName\:\PreToolUse\,\permissionDecision\:\allow\,\additionalContext\:\警告: 检测到敏感操作 $pattern但已放行\}} exit 0 fi done exit 0这个脚本的逻辑很直接从 stdin 读取 JSON用jq提取出tool_input.command然后做两轮匹配。第一轮是硬拦截匹配到就直接返回denyClaude Code 不会执行这条命令。第二轮是软警告匹配到返回allow但附带additionalContext命令会执行但 Claude Code 会看到警告信息。再看 PostToolUse 的配置。它的作用是在文件写入之后做审计和格式化{ hooks: { PostToolUse: [ { matcher: Edit|Write, hooks: [ { type: command, command: bash \$CLAUDE_PROJECT_DIR/.claude/hooks/post-tool-audit.sh\, timeout: 30 } ] } ] } }对应的审计脚本.claude/hooks/post-tool-audit.sh#!/bin/bash input$(cat) file_path$(echo $input | jq -r .tool_input.file_path) tool_name$(echo $input | jq -r .tool_name) log_dir$CLAUDE_PROJECT_DIR/.claude/logs mkdir -p $log_dir echo $(date %Y-%m-%d %H:%M:%S) | $tool_name | $file_path $log_dir/audit.log if [[ $file_path ~ \.env|\.git/ ]]; then exit 0 fi warnings if grep -qE (password|passwd|pwd)\s*\s*[\][^\][\] $file_path 2/dev/null; then warnings发现硬编码密码\n fi if grep -qE (api_key|apikey|secret_key|access_token)\s*\s*[\][^\][\] $file_path 2/dev/null; then warnings发现硬编码 API 密钥\n fi if grep -qE -----BEGIN (RSA |EC )?PRIVATE KEY----- $file_path 2/dev/null; then warnings发现私钥文件\n fi if [ -n $warnings ]; then echo {\hookSpecificOutput\:{\hookEventName\:\PostToolUse\,\additionalContext\:\安全扫描发现以下问题\n$warnings\}} fi exit 0这个脚本做了两件事第一把每次文件修改记录到.claude/logs/audit.log方便你事后审计第二扫描文件内容检测硬编码密码、API 密钥、私钥文件发现后通过additionalContext返回警告。还有一个 UserPromptSubmit 的配置用来在用户提交提示词时做入口校验{ hooks: { UserPromptSubmit: [ { hooks: [ { type: command, command: bash \$CLAUDE_PROJECT_DIR/.claude/hooks/validate-prompt.sh\, timeout: 10 } ] } ] } }对应的脚本.claude/hooks/validate-prompt.sh#!/bin/bash input$(cat) prompt$(echo $input | jq -r .prompt) blocked_keywords(删除数据库 drop database rm -rf / format c: 删库跑路) for keyword in ${blocked_keywords[]}; do if echo $prompt | grep -qi $keyword; then echo {\decision\:\block\,\reason\:\你的提示词包含危险操作: $keyword已被安全钩子拦截。\} 2 exit 2 fi done exit 0注意这里用的是exit 2这是 Claude Code Hook 的阻断约定exit 0 表示继续exit 2 表示阻断其他 exit code 表示非阻断错误。4. 用 echo 与日志验证 Hook 是否真的生效配置写完了怎么确认 Hook 真的在跑最直接的办法是用echo模拟输入手动触发脚本。先验证 PreToolUse 的拦截脚本echo {tool_name:Bash,tool_input:{command:rm -rf /}} | bash .claude/hooks/pre-tool-check.sh echo exit code: $?如果脚本正常你会看到类似这样的输出{hookSpecificOutput:{hookEventName:PreToolUse,permissionDecision:deny,permissionDecisionReason:检测到危险命令: rm -rf /}} exit code: 0注意这里的 exit code 是 0因为脚本本身执行成功拦截决策是通过 JSON 里的permissionDecision传递的。Claude Code 读到deny之后就不会执行这条命令。再验证一个安全命令echo {tool_name:Bash,tool_input:{command:ls -la}} | bash .claude/hooks/pre-tool-check.sh echo exit code: $?这次应该没有任何 JSON 输出exit code 也是 0表示放行。验证 PostToolUse 的审计脚本echo {tool_name:Write,tool_input:{file_path:/tmp/test-hook.txt}} | bash .claude/hooks/post-tool-audit.sh cat .claude/logs/audit.log你应该能在audit.log里看到一条记录格式是时间 | 工具名 | 文件路径。如果文件里有硬编码密码还会看到警告 JSON。验证 UserPromptSubmit 的拦截脚本echo {prompt:帮我删除数据库} | bash .claude/hooks/validate-prompt.sh echo exit code: $?这次 exit code 应该是 2并且 stderr 会输出阻断原因。因为脚本里用了2把 JSON 写到标准错误exit 2 表示阻断。最后在真实的 Claude Code 会话里验证。启动 Claude Code让它执行一条rm -rf /tmp/test-dir观察它是否被拦截。如果配置生效Claude Code 会显示 Hook 返回的拒绝原因并且不会真正执行删除。你还可以在.claude/logs/audit.log里看到 PostToolUse 的记录确认整个链路都通了。如果 Hook 没生效先检查三件事第一settings.json的 JSON 格式是否正确可以用jq . .claude/settings.json验证第二脚本是否有执行权限chmod x .claude/hooks/*.sh第三$CLAUDE_PROJECT_DIR是否指向了正确的项目根目录。5. 本篇常见报错排查401、local proxy failed、reading choices、OAuth配置 Hook 和接入 TaoToken 的过程中最容易遇到四类报错。我逐个拆解。第一类401 Unauthorized。这个通常出现在模型调用阶段不是 Hook 本身的问题。原因一般是 API Key 没填对、Key 过期、或者 Base URL 写错了。排查步骤先确认ANTHROPIC_API_KEY的值是不是从 https://taotoken.net/api-keys 生成的完整 Key注意不要有多余空格再确认ANTHROPIC_BASE_URL是https://taotoken.net/api不要加/v1最后确认账户状态正常可以在 https://taotoken.net/console 查看。第二类local proxy failed。这个报错通常出现在 Claude Code 启动时提示本地代理连接失败。原因可能是环境变量里配置了额外的代理或者 Base URL 指向了一个不可达的地址。排查步骤检查~/.zshrc或~/.bashrc里有没有HTTP_PROXY、HTTPS_PROXY这类变量如果有先注释掉然后确认ANTHROPIC_BASE_URL能正常访问可以用curl -I https://taotoken.net/api测试连通性。第三类reading choices。这个报错一般出现在模型返回格式不符合预期的时候比如返回了一个空响应或者非 JSON 格式的内容。原因可能是 Model ID 填错了或者请求参数不匹配。排查步骤确认ANTHROPIC_MODEL填的是 TaoToken 支持的模型 ID不要自己编然后在 Claude Code 里跑一个最简单的请求比如claude -p hello看是否正常返回。如果还是报错检查settings.json里有没有多余的字段干扰请求。第四类OAuth 相关报错。Claude Code 某些版本会尝试 OAuth 登录如果你用的是 API Key 模式可能会冲突。排查步骤确认你没有同时配置 OAuth token 和 API Key如果settings.json里有oauth相关字段先删掉然后重启 Claude Code让它重新读取环境变量。除了这四类还有一个常见问题是 Hook 脚本没有输出合法的 JSON。Claude Code 对 Hook 的 stdout 有格式要求如果不是合法 JSON会被忽略或者报错。排查方法用echo {tool_name:Bash,tool_input:{command:ls}} | bash .claude/hooks/pre-tool-check.sh | jq .验证输出是否是合法 JSON。如果不是检查脚本里的echo语句有没有转义问题。另外如果你在 Hook 脚本里用了jq确保系统里已经安装了。macOS 可以用brew install jqUbuntu 用apt install jq。没有jq的话脚本会直接报错Hook 也不会生效。6. 把 Hook 变成你的日常开发安全网Hook 配好之后你不需要每次盯着 Claude Code 执行命令。PreToolUse 帮你拦住危险操作PostToolUse 帮你记录审计日志和扫描密钥UserPromptSubmit 帮你在入口处过滤危险意图。这三个节点配合起来就是一套完整的安全网。如果你还想进一步验证模型调用是否正常可以打开 https://taotoken.net/chat 用模型对话功能测试一下确认 Key 和模型都可用。如果你打算长期用 Claude Code 做编码和 Agent 任务可以看看 https://taotoken.net/coding-plan 里的方案把日常开发流程固定下来。接入文档在 https://taotoken.net/doc API Keys 管理在 https://taotoken.net/api-keys 控制台在 https://taotoken.net/console 。最后提醒一句Hook 脚本里的拦截规则要根据你的项目实际情况调整。比如git push --force在某些团队是允许的但在另一些团队是禁止的。先把规则配得严格一点跑一段时间后再根据审计日志放宽这样比较稳妥。