让 Claude 在 GitHub Issue 里自己开 PR

让 Claude 在 GitHub Issue 里自己开 PR

目标很简单:在一个 issue 里写一句 @claude 帮我修一下这个 bug,然后 Claude 自动建分支、改代码、提 PR,我只管 review 和合并。

听起来一行配置就该搞定,实际上中间卡了两个权限的坑。这篇把完整过程和踩坑记录下来。

一、想要的效果

你:    在 issue 里 @claude + 描述问题
Claude: 读 issue → 在新分支上改代码 → push → 开一个 PR
你:    review → 合并

整个链路靠 GitHub 官方的 anthropics/claude-code-action 实现。它是一个 GitHub Action,被 issue/PR 评论里的 @claude 触发。

二、第一步:把 workflow 装上

最省事的方式是在本地 Claude Code 里跑:

/install-github-app

它会引导你授权 Claude 的 GitHub App,并把一份 workflow 模板写进仓库:.github/workflows/claude.yml。同时它会在仓库的 Secrets 里写入 CLAUDE_CODE_OAUTH_TOKEN(模型侧的鉴权,后面要用)。

⚠️ 小插曲:如果你的 gh CLI 缺少 workflow scope,第一次安装可能报 GitHub CLI is missing required permissions: workflow。 重新授权 gh(gh auth refresh -s workflow)或者直接在网页上完成 App 安装即可,多试一次通常就过了。

装完后拿到的模板长这样(关键部分):

on:
  issue_comment:
    types: [created]
  issues:
    types: [opened, assigned]
  # ...还有 pull_request_review 等

jobs:
  claude:
    if: contains(github.event.comment.body, '@claude') # 只有提到 @claude 才跑
    runs-on: ubuntu-latest
    permissions:
      contents: read          # 👈 注意这里
      pull-requests: read      # 👈 还有这里
      issues: read
      id-token: write
      actions: read
    steps:
      - uses: actions/checkout@v4
      - uses: anthropics/claude-code-action@v1
        with:
          claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}

到这里你可能以为已经能用了。并没有。

三、坑 #1:默认是只读权限,Claude 开不了 PR

注意上面 permissions 那块,默认全是 read:

permissions:
  contents: read          # 不能建分支 / 提交
  pull-requests: read      # 不能开 PR

claude-code-actiongit pushgh pr create 用的是 workflow 的 GITHUB_TOKEN,它的能力被这个 permissions 块限死。只读权限下,Claude 顶多读 issue、在底下回个评论,推不了分支、也开不了 PR。

修复很简单,把两个 read 改成 write:

 permissions:
-  contents: read
-  pull-requests: read
+  contents: write
+  pull-requests: write
   issues: read
   id-token: write
   actions: read

最小权限原则提醒:只放开 contentspull-requests 就够了,其它保持 read。不要图省事直接给全局 write。

改完提个 PR 合进 main这里有个容易忽略的点:GitHub Actions 读取的是目标分支(main)上的 workflow 文件,你在功能分支里改的 permissions 不会立刻生效——必须先合并。

四、坑 #2:组织把那个开关锁死了

光给 workflow 写权限还不够。GitHub 默认禁止 GITHUB_TOKEN 创建 PR,这是一道独立的安全闸,在仓库设置里:

Settings → Actions → General → Workflow permissions → 勾上 “Allow GitHub Actions to create and approve pull requests”

结果打开一看,这个勾选框是灰的,点不动:

灰掉的设置项

连上面的 “Read and write permissions” 单选也是灰的。这说明:这个设置被组织(Organization)层级的策略锁定了,仓库层级只是只读地展示组织策略,改不动。

解法 A:去组织层级打开(推荐)

如果你是组织 owner,去组织的 Actions 设置:

https://github.com/organizations/<你的组织>/settings/actionsWorkflow permissions → 勾上 “Allow GitHub Actions to create and approve pull requests” → Save

回到仓库那个页面,灰色就解除了。不是 owner 的话,把这个链接甩给管理员。

解法 B:组织不肯放开?用 GitHub App token 绕过

“Allow GitHub Actions to create and approve pull requests” 这个开关只管默认的 GITHUB_TOKEN。如果改用 GitHub App 生成的 token 来做 git 操作,就不受这条策略约束——哪怕组织锁着也能开 PR。

做法是在 workflow 里先用 App 换 token,再喂给 action:

steps:
  - name: Generate app token
    id: app-token
    uses: actions/create-github-app-token@v1
    with:
      app-id: ${{ secrets.APP_ID }}
      private-key: ${{ secrets.APP_PRIVATE_KEY }}

  - uses: actions/checkout@v4

  - uses: anthropics/claude-code-action@v1
    with:
      claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
      github_token: ${{ steps.app-token.outputs.token }}   # 👈 关键

代价是你得自己建一个 GitHub App(给它 contents/pull-requests 的 write 权限、装到仓库),再把 APP_ID 和私钥存成 secret。设置成本比解法 A 高不少。

结论:能改组织设置就走 A,只有当组织出于安全原因坚决不放开时才走 B。

五、别忘了:这是个公开触发器

@claude 是写在 if 条件里的——任何能在你 issue/PR 下评论的人,只要打一句 @claude,就会触发 workflow 并消耗你的额度

  • 私有仓库、协作者可控 → 基本没问题。
  • 公开仓库 → 强烈建议加一层触发者白名单,比如只允许特定用户或具备 write 权限的成员触发:
if: |
  contains(github.event.comment.body, '@claude') &&
  (github.event.comment.author_association == 'OWNER' ||
   github.event.comment.author_association == 'MEMBER' ||
   github.event.comment.author_association == 'COLLABORATOR')

六、最终配置一览

name: Claude Code

on:
  issue_comment:
    types: [created]
  pull_request_review_comment:
    types: [created]
  issues:
    types: [opened, assigned]
  pull_request_review:
    types: [submitted]

jobs:
  claude:
    if: |
      (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
      (github.event_name == 'issues' && contains(github.event.issue.body, '@claude'))
    runs-on: ubuntu-latest
    permissions:
      contents: write          # ← 从 read 改过来
      pull-requests: write      # ← 从 read 改过来
      issues: read
      id-token: write
      actions: read
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 1
      - uses: anthropics/claude-code-action@v1
        with:
          claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
          additional_permissions: |
            actions: read

七、验证

  1. 在仓库新建一个 issue。
  2. 正文写:@claude 把首页标题的拼写错误改一下(或任意具体任务)。
  3. Actions 标签看 workflow 有没有跑起来。
  4. 顺利的话,过几分钟 Claude 会推一个分支并开出 PR,在 issue 底下留言附上链接。

八、Checklist:跑通需要的全部条件

#条件在哪
1.github/workflows/claude.yml 存在/install-github-app 生成
2CLAUDE_CODE_OAUTH_TOKEN secret 已配置Settings → Secrets → Actions
3permissionscontents / pull-requestswriteworkflow 文件,且已合进 main
4允许 Actions 创建 PROrg 或 Repo 的 Workflow permissions
5(公开仓库)触发者白名单workflow 的 if 条件

小结

  1. workflow 自己的 permissions 默认只读;
  2. GitHub(及组织策略)默认禁止 GITHUB_TOKEN 创建 PR。

两道都放开、并把改动合进默认分支,@claude 自动开 PR 就跑通了。