---
title: "Claude Code × GitHub Actions：从 push 到 CI 修复全自动，你只管 merge"
author: deletexiumu
pubDatetime: 2026-04-14T23:30:00+08:00
featured: false
draft: false
tags:
  - Claude Code
  - 教程
  - AI 编程
  - 效率
description: "用 Claude Code GitHub Action 实现 CI 失败自动修复和 PR 评论自动响应。3 个可直接复制的 YAML 配置，含防无限循环的关键机制，以及新手必踩的 4 个坑全部讲清楚。"
---

![封面图：从 push 到 CI 修复全自动，你只管 merge](/blog/claude-code-github-actions-automation/cover.jpg)

---

**今天下午 15:00 有一场直播，长按图片二维码可预约。**

今天（04.15）下午 15:00，「云上OPC·创享会」由深圳国家高技术产业创新中心（深国创中心）主办，粤港澳大湾区大数据中心依托云上AI OPC社区承办。AI 产品实战专家手把手带练工具落地 + AI 法务专家讲合规保障，一场工作坊打通技术实践到合规运营的完整闭环。

![直播宣传图，长按识别二维码预约](/blog/claude-code-github-actions-automation/livestream-promo.png)

---

## 一个你不想再过的循环

推代码、等 CI、看到红叉、翻日志、改两行、再推、再等、再红——这个循环每天要走 5 到 10 次，每次 15 到 30 分钟里大半是在刷新页面。PR 那边也一样：开了 PR 就等 reviewer 留评论，评论回来就切分支改，改完再推，等 reviewer 下一轮。

问题不在于这些步骤复杂，而在于它们碎。每一环都要你亲自在场：终端里敲一下、浏览器里盯一下、IDE 里切一下。你没法离开，因为循环里每一步都在等你的手。

上一篇（序号 59）讲了 Claude Code Hooks——本地侧的自动化，拦危险命令、自动跑受影响的测试、push 前守一道门。这一篇聊云端的另一半：Claude Code GitHub Action。两者拼起来，就是一条可以放着跑的开发流水线：你下班前推一次，Hooks 在本地把关，Action 在云端接力，早上打开电脑看到的是绿灯 CI、已响应的 PR 评论，和一条待你 review 的修复分支。

---

## 一、先看全貌：这条流水线到底怎么跑

在动手配置之前，先把结构过一遍。配置细节不理解全貌容易写错。

```
你 push 代码
    ↓
GitHub CI 运行（测试 / lint / build）
    ↓  失败时
Claude Code Action 被触发
    ↓
读 CI 日志 → 分析失败原因 → 修改代码
→ commit 到新分支（claude-auto-fix-ci-*）→ push
    ↓
CI 在新分支上重跑（循环直到通过）
    ↓  PR 收到 @claude 评论时
Claude 读评论 → 修改对应代码 → commit → push
```

![CI/PR 全闭环架构流程图](/blog/claude-code-github-actions-automation/pipeline-diagram.svg)

三个核心组件就够了：

- `anthropics/claude-code-action@v1`——Anthropic 官方 GitHub Action，负责在 runner 上跑 Claude Code
- GitHub Actions Workflow——你写的 YAML，决定什么事件触发 Claude
- `ANTHROPIC_API_KEY`——存在 GitHub Secrets 里的 API 密钥

可选的还有仓库根目录的 `CLAUDE.md`，用来写一些跨 workflow 都要生效的行为约束。

一句话划清边界：这套流水线不是"让 Claude 自主上线到 production"，也不是"完全不用你看"。Claude 的修改永远 push 到新分支，merge 权限始终在你手里。这不是自动驾驶，是自动副驾——它把你从等待里解放出来，不是从决策里解放出来。

---

## 二、5 分钟跑通最小配置

先给一个能跑通的最小闭环，让你今天就能在 PR 评论区 `@claude` 一下看到回复。架构细节等你看到它动起来再深入。

**两个前提：**

1. 仓库 Settings → Secrets and variables → Actions，添加 `ANTHROPIC_API_KEY`（名字必须完全一致，大小写不能错）
2. 仓库里已经有至少一个在跑的 CI workflow，记住它的 `name:` 字段——后面配置 CI 自动修复时要用

**最小可用 YAML（PR 评论 `@claude` 触发）：**

```yaml
# .github/workflows/claude-interactive.yml
name: Claude Code
on:
  issue_comment:
    types: [created]
  pull_request_review_comment:
    types: [created]

permissions:
  contents: write
  pull-requests: write
  issues: write   # 在 issue/PR 评论区回复所需

jobs:
  claude:
    if: contains(github.event.comment.body, '@claude')
    runs-on: ubuntu-latest
    steps:
      # 注意：官方基础交互示例不需要显式 checkout
      # 如遇上下文异常，参考官方文档和仓库 issue 排查
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          # 不设置 prompt = Claude 从 @claude 后面的内容里读取指令
```

提交到 `main` 分支，然后验证——这一步别跳：

1. 随便挑一个已开 PR，在评论区输入 `@claude 解释一下这个 PR 改了什么`
2. 等待片刻（通常不到 1 分钟）
3. Claude 会在评论区直接回复

看到回复，配置就成了。这是最小验证配置，能跑通就足够。生产用的完整版在第三章——那一版会再加一条 bot 过滤，避免其他机器人在评论里写 `@claude` 把你 Action 拉起来。

如果没反应，按出现频率排查：

- `ANTHROPIC_API_KEY` 的 Secret 名字写错了——大小写、下划线都得一字不差
- `permissions` 块缺了或写少了 `pull-requests: write`——写权限不够会静默失败，Action 不会报错
- `if: contains(...)` 的条件评估为 false——打开那条评论看看有没有 `@claude`，注意全角字符不算

Action 页面（仓库顶栏 → Actions）能看到每次触发的运行记录，失败时点进去看 log，原因基本都在 `anthropics/claude-code-action@v1` 那一步的输出里。

---

## 三、两种自动化模式，配置细节

最小配置跑通之后，有两种模式值得展开讲：CI 失败自动修复（全自动），以及 PR 评论 `@claude` 响应（按需）。这两种模式对应的触发事件、权限边界、成本曲线都不同，分开配置比混在一个 workflow 里清晰得多。

### 模式一：CI 失败自动修复

这是最能省时间的一种——CI 挂了，Claude 自动读日志、定位问题、修好、推到新分支、再跑一次 CI。你不用再在聊天软件里看到 CI 失败通知、切换到终端、拉取分支、看日志、修改、推回去。

但是这种模式有一个最容易踩的坑，几乎每个第一次配置的人都会遇到：**无限循环**。

先说清楚为什么会循环。`workflow_run` 事件的语义是"某个 workflow 跑完了（成功或失败都算）"，而 Claude 修复后会往仓库推 commit——这次 push 再次触发 CI、CI 再次失败（因为修的可能还不对）、`workflow_run` 再次触发 Claude、Claude 再次修复、再次推……直到 API quota 烧完或者 GitHub Actions 额度告罄。

另一个容易踩的坑是 checkout 的 ref。`workflow_run` 触发的 job 运行在新的 workflow context 下，默认 checkout 的是**仓库默认分支（通常是 main）的 HEAD**，而**不是** CI 失败时所在的那条 feature 分支。不手动指定 `ref`，Claude 会在 main 分支上看一个 main 根本没有的错误，改完一堆无关代码。

把这两件事都处理好的完整配置长这样：

```yaml
# .github/workflows/auto-fix-ci.yml
name: Auto Fix CI Failures
on:
  workflow_run:
    workflows: ["CI"]   # 必须与你的 CI workflow 的 name 字段完全一致
    types: [completed]

permissions:
  contents: write
  pull-requests: write
  actions: read         # 必须：用于读取 CI 运行日志
  issues: write
  # id-token: write     # 若接入 Bedrock / Vertex / Foundry 等 OIDC 后端时再加上

jobs:
  auto-fix:
    if: |
      github.event.workflow_run.conclusion == 'failure' &&
      github.event.workflow_run.pull_requests[0] &&
      !startsWith(github.event.workflow_run.head_branch, 'claude-auto-fix-ci-')
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.workflow_run.head_branch }}  # 切到失败的分支
          fetch-depth: 0
          token: ${{ secrets.GITHUB_TOKEN }}

      - name: Setup git identity
        run: |
          git config --global user.email "claude[bot]@users.noreply.github.com"
          git config --global user.name "claude[bot]"

      - name: Create fix branch
        id: branch
        run: |
          BRANCH_NAME="claude-auto-fix-ci-${{ github.event.workflow_run.head_branch }}-${{ github.run_id }}"
          git checkout -b "$BRANCH_NAME"
          echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT

      - uses: anthropics/claude-code-action@v1
        with:
          prompt: |
            The CI pipeline failed. Diagnose the failure and fix the root cause.
            Failed run URL: ${{ github.event.workflow_run.html_url }}

            Rules:
            - Only modify files related to the CI failure
            - Do not modify .github/ directory (including this workflow file)
            - Do not delete existing test cases
            - Do not add new dependencies without explicit instruction
            - Run git diff HEAD before each commit to verify scope
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          claude_args: |
            --allowedTools 'Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash(git:*),Bash(npm:*)'
            --max-turns 10
```

`--allowedTools` 里的 `Bash(...)` 白名单按你仓库实际需要增减——用 pytest 的加 `Bash(pytest:*)`，用 go test 的加 `Bash(go:*)`，Makefile 驱动的就放 `Bash(make:*)`。白名单越窄越安全。

`if:` 里的三条缺一不可：

- `conclusion == 'failure'`——只在 CI 真的失败时介入
- `pull_requests[0]` 存在——失败发生在某个 PR 的 context 下，不是 main 分支自己的定时跑挂了
- `!startsWith(..., 'claude-auto-fix-ci-')`——触发的不是 Claude 自己刚推的修复分支。这一条是切断循环的闸门

Claude 修复后会 push 到以 `claude-auto-fix-ci-` 开头的新分支，下次 `workflow_run` 触发时第三个条件不满足，job 直接跳过，循环终止。顺便澄清一下：`--max-turns` 限制的是单次 Agent 跑多少步，无法阻止 workflow 被反复触发，别把希望寄托在它身上。

**这种模式适合什么 CI：**

- 单元测试、lint 检查、类型检查——失败原因都在错误日志里，Claude 有足够线索定位
- 失败原因可在代码里追溯的那种，比如断言不成立、语法错误、导入缺失

**这种模式不适合什么：**

- 集成测试——Claude 在 GitHub Actions runner 上没法访问你的 staging 数据库、消息队列、第三方服务，修复成功率低到不值得配
- 部署相关 CI——一旦给了 `deployments: write`，Claude 就能触发 production 发布，安全边界立刻失守，别碰

### 模式二：PR 评论 `@claude` 响应

这种模式按需触发，只在你或 reviewer 在 PR 评论区显式 `@claude` 时才启动。它比全自动模式灵活，成本曲线也稳定得多——没人 `@` 就不烧钱。

触发方式值得对比一下，因为选错的代价不小：

| 触发方式 | 适用场景 | 成本 | 噪音风险 |
|---------|---------|------|---------|
| `@claude` 按需 | 代码评审建议、"解释这段"、"按评论修改" | 低（仅 mention 时触发）| 低 |
| `prompt:` 全自动 | CI 失败修复、定时代码审查 | 中（每次 PR 事件都运行）| 中（可能重复评论）|

对多数日常 PR 工作流来说，按需模式更顺手：

```yaml
# .github/workflows/claude-comment.yml
name: Claude PR Comment Handler
on:
  pull_request_review_comment:
    types: [created]
  issue_comment:
    types: [created]

permissions:
  contents: write
  pull-requests: write
  issues: write   # 在 issue/PR 评论区回复所需

jobs:
  handle-comment:
    # Bot 评论不触发（防循环），只处理含 @claude 的人类评论
    if: |
      contains(github.event.comment.body, '@claude') &&
      github.event.comment.user.type != 'Bot'
    runs-on: ubuntu-latest
    steps:
      # 注意：官方基础交互示例不需要显式 checkout
      # 如遇上下文异常，参考官方文档和仓库 issue 排查
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          # 不设置 prompt = Claude 从 @claude 后面的内容直接读取指令
```

实际用起来，在 PR 评论区里可以直接这样写：

- `@claude 按这条评论的建议修改代码`
- `@claude 解释一下这个函数为什么要 defer close`
- `@claude 给这段代码补单元测试`
- `@claude 检查这个 PR 有没有 SQL 注入`

Claude 会读 PR 上下文和评论，做对应的事，然后直接回复评论或推新 commit。

有一点要提前讲清楚，免得你期待落空：这个模式**不会**在 Claude 修完后自动替你 re-request review。re-request 需要额外的 GitHub API 调用，当前官方示例里没有经过验证的可靠实现。Claude 改完之后 push 是 push 了，但 reviewer 那边是否再审，还得你手动点一下。

### 进阶想法：Stale PR 自动 rebase

有一种玩法是让 Claude 定时处理那些搁置了好几天、落后于 base branch 的 PR：自动 `git rebase`，让 Claude 解决低风险冲突（比如文档、注释冲突），高风险冲突（业务逻辑冲突）则由 Claude 打标签留给人工处理。

这个思路理论上可行，但需要比前两种模式更复杂的条件判断（PR 最后更新时间、base 落后程度、冲突分类），目前也没有一份真正经过生产验证的 YAML。如果你有这个需求，基于模式一的骨架改造即可——建议先在一个非关键仓库里试，稳了再铺开。

---

## 四、安全边界：这条线 Claude 不能越

让 Claude 在云端代你改代码，最怕的不是它改不好，是它改错地方。三层防护叠起来用，覆盖大部分已知风险。

### 第一层：GitHub permissions 最小权限

`permissions` 块决定了这个 workflow 能对仓库做什么。原则是"只要够用就别多给"：

```yaml
permissions:
  contents: write       # 允许 push commit（必须）
  pull-requests: write  # 允许评论 PR（必须）
  actions: read         # 读 CI 日志（CI 修复模式需要）
  issues: write         # 评论 issue（可选，按需添加）
  # 不给 deployments: write —— 不能触发部署
  # 不给 actions: write     —— 不能修改 CI 配置本身
  # 不给 packages: write    —— 不能发布 package
```

留一句给第一次配置的人：不要图省事写 `permissions: write-all`。一旦 Action 被 prompt injection 打穿，`write-all` 意味着它能改你仓库里的一切。

### 第二层：prompt 里写明禁令

每个 workflow 的 `prompt:` 里，都值得加一段禁令。这是对 Claude 行为的直接约束，在单次运行中优先级最高：

```
禁止操作：
- 不要 git push --force
- 不要修改 .github/ 目录下的任何文件（包括本 workflow）
- 不要删除已有的测试用例
- 不要安装新的依赖包（除非明确要求）
- 不要修改与触发事件无关的代码
- 每次 commit 前先执行 git diff HEAD 确认改动范围
```

"修改与触发事件无关的代码"这条特别关键——它能阻止 Claude 在修一个 lint 错误时顺手"优化"了三个无关函数。

### 第三层：CLAUDE.md 持久化约束

`prompt:` 的约束绑定在单个 workflow 上，换个 workflow 就要重写一遍。更稳的做法是在仓库根目录放一个 `CLAUDE.md`，写跨 workflow 都要生效的行为准则：

```markdown
## 在 GitHub Actions 中运行时

- 永远不要直接 push 到 main 或 release/* 分支
- 永远不要修改 /vendor/ 或 /generated/ 目录
- 标记所有硬编码的凭证或密钥为高危问题
- 为修改创建新分支，而不是直接 commit 到当前分支
```

这个文件会被 Claude Code 在每次运行时自动加载，不会因为你改了 workflow YAML 就失效。

### 两个 GitHub 层面的默认保护

有两条事实你最好提前知道，它们不是你配的，是官方 Action 默认的机制：

- **Fork 的 PR 默认无法访问 repository secrets**——这意味着外部贡献者提 PR 时，你的 `ANTHROPIC_API_KEY` 不会被消耗。这条保护是 GitHub 本身的安全模型，不需要你做任何事。如果你非要让 fork PR 也能用 Claude，需要手动切到 `pull_request_target`，但那会引入 secret 泄露和 prompt injection 的新风险，除非你清楚自己在做什么，否则别动。
- **Bot 用户默认被阻止触发 Claude**——防止其他 bot 在评论里注入 `@claude` 字符串就能让 Claude 跑起来。`anthropics/claude-code-action` 里有个参数 `allowed_bots`，默认 `false`，保持默认即可，公共仓库里强烈建议别开。

### 允许与禁止的操作对照

把上面三层防护的结果翻译成一张具体操作的对照表：

| 操作 | 是否允许 | 原因 |
|------|---------|------|
| push 到 feature 分支 | 允许 | 低风险，不会自动合并 |
| push 到 `claude-auto-fix-ci-*` 新分支 | 允许 | 专用分支，可溯 |
| `git push --force` | 禁止 | 依赖 prompt 约束 + 分支保护规则双层兜底 |
| merge 到 main/master | 禁止 | permissions 未给 merge 权限 |
| 修改 `.github/` 目录 | 禁止 | 避免 Claude 修改自身 workflow |
| 修改与失败无关的代码 | 禁止 | prompt 约束 |
| 安装新依赖 | 禁止 | 供应链风险 |

这里要点破一个容易被忽略的事实：`contents: write` 权限本身并不阻止 force push，prompt 里的"不要 force push"是软约束，Claude 在极端情况下有可能违反。真正的硬门禁是在 GitHub 仓库 Settings → Branches 里给关键分支配 Branch Protection Rules，勾上 "Do not allow force pushes"。prompt 层和 branch protection 互为兜底，两头都加才算稳。

---

## 五、成本控制：别让 Actions 账单给你惊喜

Claude Code Action 的账单实际上分两部分：一部分是 GitHub Actions 自己的分钟数（公开仓库免费，私有仓库按计划扣额度），另一部分是 Anthropic API 的 token 消耗。后者是更容易失控的那部分。

官方给的参考成本（按 Anthropic 直接 API 计算）：

- 小 PR（<200 行）：$0.01–$0.03/次
- 中 PR（200–1K 行）：$0.05–$0.15/次
- 大 PR（1K+ 行）：$0.20–$0.50/次
- 50 PR/月的典型团队通常月成本 < $5

看着便宜，但一个"自动修复 CI 失败"的 workflow 配错了，在十分钟内连续触发几十次是完全可能的。下面这几个配置分开放在各自对应的 workflow 里，不是一个 YAML 块，按需取用：

**并发控制**（加在 job 级别）——同一 PR 推新 commit 时，取消正在跑的旧任务：

```yaml
concurrency:
  group: claude-${{ github.event.pull_request.number }}
  cancel-in-progress: true
```

**路径过滤**（加在 `on.pull_request` 下）——纯文档变更不用启动 Claude：

```yaml
on:
  pull_request:
    paths-ignore:
      - '*.md'
      - 'docs/**'
      - '.github/**'
```

**超时限制**（加在 `jobs.<name>` 级别）——防止单次 job 卡住烧钱。注意这个跟第三章"防无限循环"是两件事，那个靠的是分支命名约定：

```yaml
jobs:
  claude:
    timeout-minutes: 10
```

**单次 Agent 步数**（加在 `claude_args`）：

```yaml
claude_args: "--max-turns 5"
```

**模型选择**——日常代码评审、lint 修复用 Sonnet 档就够了，Sonnet 比 Opus 通常便宜一大截。优先 Sonnet，只有当它多轮都改不对、任务明显需要跨大量文件推理时再升级 Opus。具体模型 ID 建议在你自己的 workflow 里用变量管理，别硬编码在文章里跟着一起过时：

```yaml
claude_args: "--model YOUR_MODEL_ID"
```

这几项里最划算的是前两项。并发控制能挡住"同一 PR 连推三次"的重复烧钱，路径过滤能直接把文档类 PR 排除在外——这两类加起来可能占你日常 PR 总量的一半。

---

## 六、高频踩坑：新手必经之路

不是吓你，这四个坑几乎每个第一次配的人都会踩至少一个：

- **`workflows:` 名称不匹配**——`workflow_run` 触发器里填的名字和 CI workflow 的 `name:` 字段必须**字符级一致**，哪怕多一个空格也不触发，且没有任何报错提示。这是最沉默、命中率最高的新手坑。排查方式：打开 CI workflow 文件第一行的 `name:`，原封不动复制过来
- **缺 `fetch-depth: 0`**——CI 自动修复 workflow 里的 `actions/checkout@v4` 默认是 shallow clone，Claude 跑 `git log` 看不到历史，做不出合理判断，也无法准确定位是哪次 commit 引入的问题
- **`permissions` 漏写 `actions: read`**——CI 自动修复 workflow 需要这个权限读 CI 日志。漏了之后 Claude 能感知到 CI 失败，但看不到失败原因，修起来基本靠猜
- **把 `--max-turns` 当成防循环机制**——它只管单次 Agent 的最大步数上限，防不了 workflow 被重复触发。防无限循环靠的是第三章讲的分支命名约定：Claude 推 `claude-auto-fix-ci-*` 前缀的分支，触发条件里的 `!startsWith(...)` 直接跳过

---

## 七、本地 Hooks + 云端 Action 合起来是什么

回到开头那句话：Hooks 管本地侧的守护，Action 管云端的闭环。两者职责正好互补，不重叠。

一个典型工作日的流水线长这样：

```
本地 Pre-commit Hook（序号 59）
  → 拦截危险命令 / 自动运行受影响测试
  → 本地验证通过后 git push

GitHub Action（本文）
  → CI 失败 → Claude 自动修复 → 推新分支 → CI 再跑
  → PR 评论 @claude → Claude 修改 → push
```

早上打开电脑看到的：CI 已通过或至少有一条修复分支在等你 review、`@claude` 评论已响应、唯一需要你亲自做的事是 review 那条修复分支并决定是否 merge。

两种工具的职责边界：

| 作用范围 | 工具 | 对应文章 |
|---------|------|---------|
| 本地 git 操作边界 | Claude Code Hooks | 序号 59 |
| 云端 CI / PR 闭环 | GitHub Action | 序号 60（本文） |

---

## 八、从读完到跑通的行动清单

看完这篇不动手就是白看。按顺序走一遍，按各步骤给的时间预估，一个下午就能配好：

1. 在 GitHub Secrets 添加 `ANTHROPIC_API_KEY`——5 分钟
2. 把第二章的最小配置 YAML 复制到你的仓库 `.github/workflows/`——10 分钟
3. 在任意开着的 PR 评论区输入 `@claude 你好` 验证——5 分钟
4. 确认通过后，添加第三章的 CI 失败自动修复 workflow，**务必留意三重 `if:` 条件**——30 分钟
5. 在仓库根目录放一份 `CLAUDE.md`，把第四章的行为约束写进去——10 分钟

跑通之后，再把第五章的并发控制、路径过滤、超时限制按需补到各自的 workflow 里。最省事的做法是先让它跑起来、跑顺了再优化——别一上来就追求配置完美。

下一次你推代码下班、关掉终端之前，留个小观察点：不再不自觉地盯着 CI 页面刷新的那天，这套流水线就真正生效了。

---

## 参考资料

Claude Code GitHub Actions 官方文档：https://code.claude.com/docs/en/github-actions

anthropics/claude-code-action 仓库：https://github.com/anthropics/claude-code-action

---

## 相关阅读

- [Prompt 会忘，Hook 不会：Claude Code 自动化守卫完全实战](/posts/claude-code-hooks-automation-guard/) — 本文的"本地守护"前传：Hook 控制本地行为，Action 管云端闭环，两者合在一起才是完整的无人值守工作流
- [Claude Code 安全三道防线：从权限模式到 Hook 兜底的纵深防护实战](/posts/claude-code-safety-three-defenses/) — 与本文第四章的安全边界设置形成互补，从整体框架理解权限控制的设计思路
