首页 › tutorials › 裸模式入CI:PR审查机器人

裸模式入CI:用 Claude Code 跑通自动 PR 审查机器人

概述

本教程聚焦 Claude Code 的无头自动化能力(-p 模式),并以 2026 年新增的 --bare 裸模式为核心,带你把 Claude Code 嵌进 GitHub Actions,做成一个「PR 一开就自动审查、自动评论、可选自动修复」的机器人。读完你将掌握:-p 的管道化用法、裸模式为何是 CI 的唯一正确姿势、六种权限模式在 CI 中的取舍、stream-json 事件流与会话续接、以及一个可立即落地的完整 workflow。适合已跑通过本地 Claude Code、想把 AI 能力工程化进交付流水线的中后端工程师与 DevOps/SRE。

前置条件


一、-p 无头模式:把 Claude 当 Unix 命令用

最简调用

给任意 claude 命令加上 -p(或 --print),它就进入非交互模式——读一条 prompt,打印结果到 stdout,然后退出。所有 CLI 选项都和交互模式通用:

claude -p "What does the auth module do?"

它接受的输入位置参数就是 prompt,输出就是模型回答。这意味着你可以像对待 grep、jq 一样把它接进管道。

管道进、管道出

-p 模式会读取 stdin,因此可以把数据喂进去、把回答重定向出来。最经典的用法是把构建日志喂给 Claude,让它定位根因:

cat build-error.txt | claude -p 'concisely explain the root cause of this build error' > output.txt

PR 审查场景同样靠管道:把 git diff 喂进去,让它逐段评审:

git diff origin/main...HEAD | claude -p "Review this diff for security vulnerabilities and bugs. Be concise, cite file:line." > review.md

预期结果:review.md 里是一份带 src/auth.py:42 式行号引用的审查清单。

自动批准工具,避免卡在权限提示

默认情况下,Claude 要用 Bash、Edit 等工具时会请求权限。CI 里没有人按回车,必须用 --allowedTools 预批准:

claude -p "Run the test suite and fix any failures" --allowedTools "Bash,Read,Edit"

--allowedTools 用的是权限规则语法,支持前缀匹配。注意 git diff 后面那个空格加星号——它决定匹配范围:

# 正确:允许任何以 "git diff " 开头的命令
--allowedTools "Bash(git diff *)"

# 危险:没有空格,连 "git diff-index" 也会被放行
--allowedTools "Bash(git diff*)"

一个典型提交生成例子——审查暂存改动并生成提交信息:

claude -p "Look at my staged changes and create an appropriate commit" \
  --allowedTools "Bash(git diff *),Bash(git log *),Bash(git status *),Bash(git commit *)"

常见问题


二、--bare 裸模式:CI 可复现性的关键

这是 2026 年 CI 自动化最值得学的一个标志。默认的 claude -p 会加载与交互会话相同的上下文——包括工作目录和 ~/.claude 下配置的一切:hooks、skills、plugins、MCP 服务器、auto memory、CLAUDE.md。

问题在于:CI 跑在不同机器上。某位同事在 ~/.claude 里挂了一个 hook,或者项目 .mcp.json 引了一个本地 MCP,CI 环境读不到,结果就和本地不一致——「在我机器上能跑」的翻版。

--bare 就是为了消除这种不可复现性:

claude --bare -p "Summarize this file" --allowedTools "Read"

裸模式跳过自动发现 hooks、skills、plugins、MCP servers、auto memory 和 CLAUDE.md。只有你显式传入的 flag 才生效。裸模式下 Claude 默认拥有 Bash、文件读、文件写三类工具;需要别的上下文时,用 flag 显式加载:

要加载的东西 使用的 flag
系统提示补充 --append-system-prompt、--append-system-prompt-file
设置(含权限) --settings <json>
MCP 服务器 --mcp-config <path>
自定义子代理 --agents <path>
插件 --plugin-dir <path>、--plugin-url <url>

认证也要改:裸模式跳过 OAuth 和 keychain 读取,必须用 ANTHROPIC_API_KEY 环境变量,或在传给 --settings 的 JSON 里配 apiKeyHelper。Bedrock / Vertex / Foundry 照常用各自的 provider 凭据。

官方明确表态:--bare 是脚本和 SDK 调用的推荐模式,未来会成为 -p 的默认行为。 现在 CI 里就该默认带上它。

常见问题


三、权限模式:CI 安全的核心抉择

除了用 --allowedTools 列白名单,还有一条整段控制轴:权限模式(permission mode) 设定整个会话的基线行为。选对模式,--allowedTools 列表能缩到几乎为空;选错,就是一堆没人审计的瑞士奶酪式白名单。

六种模式,从严到松:

模式 免询问即可执行 适用场景
default 仅读取 入门、敏感操作
dontAsk 仅 permissions.allow 中预批准的工具 锁定型 CI / 脚本
plan 仅读取;只提议不改码 探索代码库
acceptEdits 读写、文件编辑、常见文件系统命令 在你审阅中的代码上迭代
auto 几乎全部(带后台分类器安全检查) 长任务、减少打断
bypassPermissions 除受保护路径外的一切 仅限隔离容器 / VM

dontAsk:CI 唯一该认真考虑的模式

官方原文:dontAsk 模式会自动拒绝一切未显式批准的工具。只有匹配 permissions.allow 规则的动作能执行;显式 ask 规则也会被拒绝而非弹出提示。 这使它对 CI 流水线完全非交互。

这正是 CI 想要的属性——「无人值守」与「不会静默越权」同时满足。其他模式要么是交互式(default、plan),要么过松(acceptEdits、auto、bypassPermissions)。

代价是:你必须有一份真正覆盖任务所需的 permissions.allow 列表,否则第一次遇到未批准工具就中止。这是个 feature 不是 bug——一次 dontAsk 大声报错,胜过一次 acceptEdits 默默写了个没人预期的文件。

完整写法:

claude --bare -p "Run the test suite and fix any failures" \
  --permission-mode dontAsk \
  --settings '{ "permissions": { "allow": [
    "Read", "Edit", "Grep",
    "Bash(npm test)", "Bash(git diff *)", "Bash(git add *)"
  ] } }'

--bare(可复现)+ dontAsk(权限有界)= 两条让生产级无值守运行安全的属性。

acceptEdits:留给交互式工作

acceptEdits 会自动批准工作目录内的文件写入,外加一串特定文件系统命令:mkdir、touch、rm、rmdir、mv、cp、sed(以及被 timeout/nice/nohup 包裹、或加了 LANG=C 之类安全环境变量的同类命令)。其他——任意 shell、网络请求、工作目录外的写入——仍然会弹提示。

这让它适合有人盯着的长会话:你让 Claude 迭代,最后审 diff。它不是 CI 模式——没人盯着提示,进程就会卡住。

常见问题


四、结构化输出与会话续接

--output-format json:拿到成本与结构

加 --output-format json,返回的 payload 里会带 total_cost_usd 和按模型的成本拆解,方便脚本统计每次调用花了多少钱。session_id 也在里面——这是续接会话的关键。

claude -p "Review this codebase for performance issues" --output-format json

--output-format stream-json:事件流

stream-json 按行输出 JSON 事件,每个事件一个类型:system(含 session_id、加载的插件与插件错误)、user、assistant、tool_use、tool_result、result。它是构建实时看板、把工具调用挂回调的基础。

一个常被忽视的 CI 用法:system/init 事件里的 plugin_errors 字段。当 CLAUDE_CODE_SYNC_PLUGIN_INSTALL 环境变量被设置时,会先于首轮发出 plugin_install 事件。你可以据此让 CI 在某个插件没加载成功时直接失败——这是 CI 上的正确防御姿态。

会话续接:--continue 与 --resume

--continue 续接最近一次会话;--resume <session-id> 续接指定会话。注意:session ID 查找按当前项目目录及其 git worktree 限定范围,两次调用要在同一目录跑。

经典多轮审查:

# 第一轮
claude -p "Review this codebase for performance issues"
# 续最近一次
claude -p "Now focus on the database queries" --continue
claude -p "Generate a summary of all issues found" --continue

跑多个独立会话时,从 json 捕获 session_id 再精确续接:

session_id=$(claude -p "Start a review" --output-format json | jq -r '.session_id')
claude -p "Continue that review" --resume "$session_id"

常见问题


五、实战案例:GitHub Actions 自动 PR 审查机器人

现在把上面所有零件拼起来。目标是:任何 PR 打开或更新时,自动跑 Claude 审查,把结果作为评论贴回 PR。这是「-p 模式 + 裸模式 + dontAsk + 结构化输出」最典型的落地形态。

方案选型:用官方 Action 还是裸 -p?

官方提供 anthropics/claude-code-action@v1,支持在 PR/issue 评论里 @claude 触发,自动认证、自动回帖、支持 Bedrock/Vertex。如果你的诉求是「人 @ 一下让 AI 改代码并开 PR」,直接用它最省事。

但如果你的诉求是「每个 PR 一开就无条件跑只读审查并贴评论」这种确定性流水线,裸 -p 反而更可控:审查范围、权限、模型、prompt 全在你手里,不依赖 @claude 触发,也不会有「忘了 @ 就不跑」的盲区。下面给两套配置。

配置 A:官方 Action(推荐给团队协作场景)

.github/workflows/claude-review.yml:

name: Claude PR Review

permissions:
  contents: write
  pull-requests: write
  issues: write
  id-token: write   # 仅 Bedrock/Vertex 需要

on:
  pull_request:
    types: [opened, synchronize]
  issue_comment:
    types: [created]

jobs:
  claude-review:
    if: |
      github.event_name == 'pull_request' ||
      (github.event_name == 'issue_comment' &&
       contains(github.event.comment.body, '@claude'))
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0   # 需要 diff 历史时拉全

      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          github_token: ${{ secrets.GITHUB_TOKEN }}
          # 只读审查:限制轮数、锁定模型、plan 模式不改码
          claude_args: "--model claude-sonnet-4-6 --max-turns 6 --permission-mode plan"
          prompt: |
            Review the diff of this pull request as a senior engineer.
            Focus on: security, correctness, error handling, and tests.
            Output a markdown checklist. Cite file:line. Do not modify code.

要点:

配置 B:裸 -p(推荐给确定性审查流水线)

.github/workflows/pr-audit.yml:

name: PR Audit (headless)

permissions:
  contents: read
  pull-requests: write

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  audit:
    runs-on: ubuntu-latest
    env:
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Collect diff
        run: |
          git diff origin/${{ github.base_ref }}...HEAD > /tmp/pr.diff
          echo "Diff lines: $(wc -l < /tmp/pr.diff)"

      - name: Run Claude review
        id: review
        run: |
          # 裸模式 + dontAsk + 只读工具 + 角色注入
          cat /tmp/pr.diff | claude --bare -p "$(cat <<'PROMPT'
          You are a security-focused code reviewer. Review the diff piped on stdin.
          Output ONLY a markdown checklist of issues by severity (High/Med/Low).
          Cite path:line. If no issues, say "LGTM".
          PROMPT
          )" \
            --append-system-prompt "Reject any request to modify code. You are read-only." \
            --permission-mode dontAsk \
            --settings '{ "permissions": { "allow": ["Read","Grep"] } }' \
            --allowedTools "Read,Grep" \
            > /tmp/review.md

      - name: Post review comment
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const body = fs.readFileSync('/tmp/review.md', 'utf8');
            await github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: `### 🤖 Claude Code 自动审查\n\n${body}`
            });

这套配置的工程亮点:

  1. --bare:CI runner 上不读任何本地配置,全靠显式 flag,跨机器可复现。
  2. --permission-mode dontAsk + 只允许 Read,Grep:审查机器人物理上无法改码。dontAsk 会拒绝任何越界工具调用,结合「系统提示二次声明只读」形成纵深防御。
  3. --append-system-prompt 注入角色:保留默认行为的同时叠加「安全审查员」人设,比 --system-prompt 全量替换更稳。
  4. --output-format 省略:审查结果直接 stdout 重定向到 /tmp/review.md,再回贴评论,链路最短。

预期结果:每次 PR 更新,机器人几秒后贴出一份「High/Med/Low + path:line」清单;无问题时回「LGTM」。

本地联调(推上 CI 前)

在本地用同样命令复现 CI 行为,省 CI 额度:

export ANTHROPIC_API_KEY=sk-ant-...
git diff origin/main...HEAD \
  | claude --bare -p "Review this diff for bugs and security. file:line." \
      --permission-mode dontAsk \
      --settings '{ "permissions": { "allow": ["Read","Grep"] } }' \
      --allowedTools "Read,Grep"

六、批量任务:单会话顺序化跑全仓

「批量任务」不等于必须并行扇出。许多场景下,一条 -p 会话顺序处理 N 个对象就够,且更省 token、更易调试。关键是复用同一 session 避免重复加载上下文。

模式 1:管道喂多个文件

把多个文件拼接后一次性喂入,让 Claude 产出结构化汇总:

for f in src/**/*.py; do
  echo "===== $f ====="; cat "$f"
done | claude --bare -p "For each file above, list functions lacking docstrings. Output as: path:func" \
  --allowedTools "Read" --permission-mode dontAsk

模式 2:捕获 session_id 续接多轮

需要分阶段处理(先扫描、再深挖、再汇总)时,复用 session:

SID=$(claude --bare -p "Scan repo for TODO/FIXME and rank by risk" \
      --output-format json --allowedTools "Read,Grep" | jq -r '.session_id')

claude --bare -p "For the top 3 riskiest, propose a fix plan" --resume "$SID" \
  --permission-mode plan --allowedTools "Read,Grep"

claude --bare -p "Summarize all findings into one report" --resume "$SID" \
  --output-format json | jq -r '.result'

注意三段都在同一目录(CI 的 ${{ github.workspace }})执行,--resume 才能找到 session。

模式 3:大块改动的自动修复(受控)

把审查升级为「审查 + 修复 + 测试」,但用 dontAsk 把可执行动作锁死在白名单内:

claude --bare -p "Apply the lint fixes the linter reports, then run tests" \
  --permission-mode dontAsk \
  --settings '{ "permissions": { "allow": [
    "Read","Edit","Grep",
    "Bash(npm run lint:fix)","Bash(npm test)"
  ] } }'

超出白名单的任何动作(比如装新依赖 npm install)都会被 dontAsk 立即拒绝并中止——只读审查与受控修复之间,差的就是这份 allow 列表的范围。


整体工作流程

flowchart TD
    A[PR 打开/更新] --> B[GitHub Actions 触发]
    B --> C[checkout + 收集 git diff]
    C --> D{选择方案}
    D -->|团队协作 @claude| E[官方 claude-code-action]
    D -->|确定性流水线| F[裸模式 claude --bare -p]
    F --> G["--permission-mode dontAsk<br/>--allowedTools Read,Grep"]
    G --> H[Claude 只读审查]
    E --> H
    H --> I["--output-format json/stream-json<br/>结构化输出 + 成本"]
    I --> J{有高危问题?}
    J -->|是| K[贴审查清单评论]
    J -->|否| L[回 LGTM]
    K --> M{配置允许自动修复?}
    M -->|否| N[人工 review 后合并]
    M -->|是| O["切换 acceptEdits + 受控 allow<br/>CI 跑测试 → 自动 commit"]
    O --> N

    style F fill:#e1f5ff,stroke:#0288d1
    style G fill:#fff4e1,stroke:#f57c00
    style H fill:#e8f5e9,stroke:#388e3c

常见陷阱清单

陷阱 现象 对策
没加 --bare CI 跑出和本地不同的结果 CI 一律带 --bare,显式注入所需上下文
用了 OAuth 登录态 裸模式下认证失败 改 ANTHROPIC_API_KEY 或 apiKeyHelper
权限模式选错 CI 卡在权限提示挂死 用 dontAsk(或 bypassPermissions 仅限隔离容器)
--allowedTools 缺空格 Bash(git diff*) 连 git diff-index 也放行 写成 Bash(git diff *),空格 + 星号
--resume 找不到会话 续接报错 两次调用须在同一目录 / worktree
后台进程不退出 claude -p 一直挂着(旧版) 升级到 v2.1.163+;5 秒优雅期会收尾
插件加载失败未察觉 CI 静默降级 检查 stream-json 的 system/init.plugin_errors,失败即 exit 非 0
审查机器人改了码 越权写入 dontAsk + 只允许 Read,Grep,系统提示二次声明只读

延伸阅读


训练营适用性评估

维度 评估
适合训练营类型 DevOps / SRE 进阶营、AI 工程化实战营、企业 AI 落地营;不适合零基础入门营(前置需理解 CI、权限、shell 管道)
建议教学时长 3–4 学时(1 学时讲 -p/--bare/权限模式,1 学时讲结构化输出与会话续接,1.5 学时做 GitHub Actions 实战,0.5 学时答疑联调)
学员产出 每人一个可运行的 PR 审查机器人 workflow + 一份 settings.json 权限基线
核心考核点 能正确解释为何 CI 要用 --bare + dontAsk,并能独立把只读审查升级为受控自动修复
风险提示 实战环节会真实消耗 API 额度,建议配 --max-turns 与额度告警;自动修复分支务必限制 allow 列表

参考来源

  1. Run Claude Code programmatically(Headless / -p / --bare 官方文档) — 裸模式、结构化输出、会话续接、权限模式与后台任务退出的权威说明
  2. Claude Code GitHub Actions(官方文档) — claude-code-action@v1 集成、@claude 触发、Bedrock/Vertex 认证与 claude_args 透传
  3. Claude Code permission modes: which one should your CI use? — Background Claude — 六种权限模式从严到松的横向对比与 CI 选型论证
  4. Configure permissions — Claude Code Docs — permissions.allow 规则语法、--allowedTools 前缀匹配与只读命令集
  5. Claude Code Headless Mode for Batch Tasks and CI/CD — Restato — 无头模式用于批量任务与流水线的实战案例补充

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入