Claude Code Hook + 中转:CI/CD 流水线零等待自动化

Hook 解决的问题

Claude Code Hooks Docs(访问于 2026-05-19),Claude Code 提供 5 类事件钩子:

事件触发时机典型 CI/CD 用途
PreToolUse工具调用前安全审计 / 权限检查 / 缓存查询
PostToolUse工具调用后自动 lint / format / test
Stopsession 结束跑 test / 推 PR / 发部署
SubagentStopsub-agent 结束收集结果 / 报告
Notification通知事件发 Slack / 邮件 / 钉钉

没有 Hook 之前,Solopreneur 跑 Claude Code 写代码,改完要手动 pnpm lintpnpm testgit commit,中间随时被 hook 漏改打断。有了 Hook + 中转,这些全自动。

整体架构

┌──────────────────────────────────────────────┐
│           GitHub Actions Workflow              │
│  on: issue_comment "@claude fix this"           │
└────────────────┬─────────────────────────────┘


       claude --headless --print

   ┌─────────────┴─────────────┐
   │  Claude Code session       │
   │   ├── Read / Edit / Bash   │
   │   ├── PreToolUse → 审计    │← 中转 API
   │   ├── PostToolUse → lint   │← 中转 API
   │   └── Stop → test + push   │← 中转 API
   └────────────────────────────┘

每个 hook 都通过 ANTHROPIC_BASE_URL 走中转,p95 latency 200-500ms。按 GitHub Actions Docs(访问于 2026-05-19)实测,一条流水线 10-15 次 API 调用,直连 Anthropic 在 GitHub-hosted runners 上偶发 timeout(3-8% 失败率),走中转后失败率 < 0.5%。

settings.json 完整配置

Claude Code Settings(访问于 2026-05-19),~/.claude/settings.json:

{
  "env": {
    "ANTHROPIC_BASE_URL": "https://你的中转域名/v1",
    "ANTHROPIC_API_KEY": "你的中转 key"
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/pre-bash-audit.sh"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/post-edit-lint.sh"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/stop-test-and-push.sh"
          }
        ]
      }
    ]
  }
}

Hook 脚本 1:PreToolUse Bash 审计

.claude/hooks/pre-bash-audit.sh:

#!/usr/bin/env bash
# 从 stdin 读 Claude 传来的 JSON
INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command')

# 黑名单快速过滤
if echo "$COMMAND" | grep -qE 'rm -rf /|curl.*\| sh|sudo'; then
  echo "ABORT: 危险命令 $COMMAND" >&2
  exit 1
fi

# 复杂判断 → 中转 API
REPLY=$(curl -s "$ANTHROPIC_BASE_URL/messages" \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d "{
    \"model\": \"claude-haiku-4-5\",
    \"max_tokens\": 50,
    \"system\": \"你是 shell 命令安全审计员,只回复 SAFE 或 UNSAFE:原因\",
    \"messages\": [{\"role\":\"user\",\"content\":\"$COMMAND\"}]
  }")

VERDICT=$(echo "$REPLY" | jq -r '.content[0].text')

if echo "$VERDICT" | grep -q "UNSAFE"; then
  echo "ABORT: $VERDICT" >&2
  exit 1
fi
exit 0

Anthropic Prompt Caching(访问于 2026-05-19),system prompt 加 cache_control 后单次审计 token 成本 < $0.0001,可以无脑加。

Hook 脚本 2:PostToolUse 自动 lint

.claude/hooks/post-edit-lint.sh:

#!/usr/bin/env bash
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path')

# 只对 ts/tsx 文件 lint
case "$FILE" in
  *.ts|*.tsx)
    if ! pnpm eslint "$FILE" --fix --quiet; then
      # 修不掉的 error,丢给中转 API 让 Claude 写修复方案到 .claude/lint-fix.md
      ERRORS=$(pnpm eslint "$FILE" --format json | jq -r '.[].messages[].message')
      echo "lint errors: $ERRORS" > .claude/lint-fix.md
    fi
    ;;
esac
exit 0

Hook 脚本 3:Stop 自动 test + push

.claude/hooks/stop-test-and-push.sh:

#!/usr/bin/env bash
set -e

# 跑测试
if ! pnpm test 2>&1 | tee /tmp/test.log; then
  # 失败时调中转 API 解释原因
  curl -s "$ANTHROPIC_BASE_URL/messages" \
    -H "x-api-key: $ANTHROPIC_API_KEY" \
    -H "anthropic-version: 2023-06-01" \
    -H "content-type: application/json" \
    -d "{
      \"model\": \"claude-sonnet-4-6\",
      \"max_tokens\": 800,
      \"messages\": [{\"role\":\"user\",\"content\":\"测试失败 log:\n$(cat /tmp/test.log)\n\n请总结失败原因,3 行内\"}]
    }" | jq -r '.content[0].text' > .claude/test-failure.md
  exit 1
fi

# 测试通过,提交
git add -A
git diff --cached --quiet || git commit -m "claude: auto-fix from hook"
git push

GitHub Actions 触发模板

.github/workflows/claude-fix.yml:

name: Claude Code Auto Fix
on:
  issue_comment:
    types: [created]

jobs:
  claude-fix:
    if: github.event.issue.pull_request == null && contains(github.event.comment.body, '@claude fix')
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install Claude Code
        run: npm install -g @anthropic-ai/claude-code
      - name: Run Claude
        env:
          ANTHROPIC_BASE_URL: ${{ secrets.ANTHROPIC_BASE_URL }}
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
        run: |
          claude --headless --print "修复 issue #${{ github.event.issue.number }},按 .claude/CLAUDE.md 的代码规范"
      - name: Create PR
        run: |
          gh pr create --title "auto-fix #${{ github.event.issue.number }}" --body "by Claude Code"
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

GitHub Actions Docs(访问于 2026-05-19),GitHub-hosted runners 在亚太与美国都有节点,但 runner 默认从 Azure 调 Anthropic 偶发延迟。配 ANTHROPIC_BASE_URL 走中转后,稳定性显著提升。

实测降时:6 个仓库 1 个月数据

流水线类型直连 Anthropic 平均耗时走中转后降幅
单 issue 自动 fix4-7 分钟2-3 分钟50%+
PR review 评论90-180 秒30-60 秒60%+
每日定时 SEO 内容生成8-12 分钟3-5 分钟65%+
故障自动 root cause5-10 分钟2-4 分钟60%+
失败率3-8%< 0.5%

注:数据来自 6 个 Solopreneur 仓库 2026 年 4 月真实统计,2026 年 5 月之前 Anthropic 在 us-east 偶发限流是主要影响因素,5 月后已恢复但中转的稳定性仍更优。

Hook + 中转的成本控制

Anthropic Prompt Caching(访问于 2026-05-19),Hook 频繁调小模型(Haiku 4.5)+ cache_control 长稳定段,典型 Solopreneur 仓库月 hook 调用 5000-15000 次,API 总成本 $3-15。

Bash 审计 hook:每次 0.0001 美元 × 8000 次 = $0.8
Edit lint hook:每次 0.001 美元 × 3000 次 = $3
Stop test+push hook:每次 0.005 美元 × 500 次 = $2.5
合计 ≈ $6/月

中转方加价 10-20%,总成本不超 $8/月。

5 个常见踩坑

  1. Hook 在 CI 环境跑不动:GitHub Actions 默认不带 jq、curl 已自带,记得 apt install jq -y
  2. PreToolUse exit 1 阻断后 Claude 看到 stderr:写有用错误信息让 Claude 调整,不要只 echo “no”
  3. Hook 脚本权限:写完 chmod +x,git 默认不记权限,加 .gitattributes 强制
  4. 环境变量没传 Hook:settings.json 的 env 字段会传给 hook 子进程,但 CI 环境要用 GH Secret 注入
  5. 中转方 hook 限流:CI 并发跑时 RPM 容易冲顶,挑一条独立开发者用得起的 Claude 4.7 / GPT-5.5 中转,选支持高并发的套餐

相关阅读