Headless、CI/CD 与 Agent SDK
一句话定位:离开交互终端,Claude Code 变成一条命令行工具——
-p一发即走、退出码可判、输出可结构化,进脚本进 CI;要更深的程序控制就上 Agent SDK。前置:Claude Code 全景与日常使用——知道权限模式与工具体系。
先从「下班了它也得干活」说起
团队想要两个自动化:每晚十点,自动审查当天未处理的错误日志;每次提交 PR,自动检查有没有引入安全问题。这些都是「没人坐在终端前」的场景——交互界面里那套对话、弹窗、确认,全都不适用。
无人在场,交互式的整套协作方式就失效了,三个新问题随之而来。
权限怎么给——没人点「允许」了;结果怎么算成败——脚本要一个明确的出口信号;还有,你的自动化需要多深的控制力?
Claude Code 的答案是分两层:Headless 模式把整场会话压成一条命令——claude -p "任务",答案是输出,成败看退出码(进程结束时回传给系统的数值);需要更细的程序级控制(逐事件回调、会话内多轮干预),再上 Agent SDK。先把一次 Headless 运行解剖开:
图:一次 Headless 运行——①脚本发起 ②命令执行 ③上下文策略 ④权限策略 ⑤输出与退出码;CI 只认⑤的信号
渐进拆解:从对话者到流水线工人
类比:交互模式是把 Claude 请进办公室面谈,Headless 是给 Claude 发工单——工单上写清任务,做完交回结果,验收标准(退出码)白纸黑字。面谈适合探索,工单适合执行——同一批工人,两种协作方式。工单制度的关键不在工人,在单据:任务怎么写(prompt)、给工人带什么(上下文与权限)、交活验收看什么(退出码与输出格式)——Headless 的全部设计就是围绕这几栏展开的。
基本用法(②)
任何 claude 命令加 -p(—print)即进入非交互模式:执行、输出、退出。输入不止命令行参数——stdin(标准输入)可以管道喂进日志、diff 等任意文本,输出可以重定向进文件,所以它能像普通命令行工具一样接进任何管道。会话可延续:--continue 接着上一场聊,定时任务也能有记忆地连续工作。用户技能与自定义命令在 -p 下照常可用——把 /skill-name 写进 prompt 即自动展开。
上下文策略(③)
加载范围与安全面:默认的 -p 会像交互会话一样加载本地配置(hooks、技能、MCP、CLAUDE.md 全套);加 --bare 则全部跳过,只执行工单本身,启动更快。
安全面也随模式切换:bare 模式不读订阅登录与系统钥匙串,凭据走环境变量里的 API key(或 —settings 里的 apiKeyHelper),等于把「用谁的账号」显式写进了配置;而默认模式在不信任的目录里照样会执行该项目 settings 里声明的 hooks、连接 .mcp.json 里声明的服务器——CI 在陌生仓库上跑默认模式前,值得先想清楚这一层。
可复现性:bare 是「什么都不带」,默认是「什么都带」——带的东西多,可复现性就差;「每台机器结果一致」正是 CI 最需要的确定性。
权限三件套(④,无人在场的放行策略)
三件组合出无人值守的放行策略:
--allowedTools白名单:精确列出允许的工具,如提交场景只放行 git 相关命令;支持前缀匹配,粒度可细到「允许 git diff 但不许 git push」。--permission-mode档位:-p 模式在所有套餐上的起始档位都是 Manual,档位必须显式传;CI 常用dontAsk(没预批的一律拒绝,连向用户提问的工具都会被拒,适合严锁环境)或auto(分类器代审)。--permission-prompts none:声明「无人可批」——落到弹窗的请求直接拒绝并告知模型别重试,杜绝任务卡死在等批准上(交互模式「变更前确认」卡死问题的无人值守版)。
输出与成败(⑤,失败怎么算)
--output-format 三选:
text:默认纯文本。json:带会话 ID 与元数据,可配--json-schema强制结构化输出。stream-json:逐事件流式。
成败信号是退出码:0 成功、非零失败,脚本据此分支;用 SIGTERM(进程终止信号,kill 默认发的那种)强停则退出 143、当前轮不记结果——运行中的命令记为 killed、跑完 SessionEnd 钩子后退出,恢复会话可把没跑完的轮次续上,所以 CI 的超时强杀是安全的。
「失败怎么算」的设计答案就在这:让任务的验收条件落到退出码上,输出用 JSON 字段做二级判读。生命周期另有一个细节:运行中启动的后台任务(如 dev server)在结果返回后约五秒被收尾,不会吊住进程。
Rules 规则系统怎么配合
路径作用域规则属于 CLAUDE.md 加载体系——默认 -p 模式照常生效(改到哪类文件就带哪类规则),--bare 则连同 CLAUDE.md 一起跳过。CI 里的取舍:要「每台机器一致」用 bare 加显式 flag,要「带上项目约定」用默认加载——两边不可兼得,按任务选。还有一层安全账:默认模式会在陌生仓库里执行项目声明的 hooks——路径规则装载是收益,钩子执行是风险,CI 场景评估陌生仓库时这两样要分开算。
Agent SDK(程序级掌控)
Headless CLI 是「一发工单」,Agent SDK(Python/TypeScript)是把 Claude 嵌进你自己的程序:以库的形式起会话、逐事件收流式响应、用 canUseTool 回调在代码里裁决权限、用 interrupt() 优雅打断、用钩子与 MCP 定制行为。官方的 CI/CD 集成(GitHub Actions、GitLab)即基于 SDK。SDK 里同样可以配钩子、接 MCP 服务器、限定工具面——交互模式里的能力在库接口下都有对应物;差别在于它们从「配置文件」变成了「你代码里的参数与回调」。
SDK 的流式接口对应 CLI 的 stream-json(逐事件),多会话编排则可以同时驱动几场会话分工——这是 Headless CLI 覆盖不到的深度。再往前一步的玩法是把 SDK 嵌进自家产品——聊天界面里挂一个会读写代码库的助手、工单系统里挂一个自动分诊代理——Claude Code 从工具变成引擎。选型口径见下图:
图:CLI 与 SDK 选型——一发工单够用就 CLI,要程序内逐事件控制才上 SDK
动手:给 PR 检查写一条 CI 任务
一条可直接放进 CI 脚本的命令(# 后是注解):
git diff origin/main... | claude -p "检查以下 diff 是否引入硬编码密钥或不安全的输入拼接,输出发现清单;没有问题输出 PASS" \
--bare \
--allowedTools "Read,Grep" \
--permission-prompts none \
--output-format json
# 注:diff 经 stdin 管道喂入——白名单里没有 Bash 时模型拿不到 diff,凭空输出的 PASS 不可信;
# --bare 不载本机配置与登录态,凭据走 ANTHROPIC_API_KEY 环境变量,CI 结果与机器无关;
# --allowedTools 只读白名单,物理上改不了代码;--permission-prompts none 无人值守(需 Claude Code v2.1.259+);
# --output-format json 供脚本解析
脚本级判读:退出码为零再解析 JSON 字段做二级判断(清单是否为空、是否含 PASS);退出码非零直接标红。注意「红」的两种含义要分清——任务失败(退出码非零,比如网络错误)与检查不通过(退出码为零但清单非空)是两件事,CI 里应该给不同的标记:前者算基础设施故障可重跑,后者才是这次提交真的有问题。再进一步,把审查标准写进 --append-system-prompt(追加系统提示),或在仓库里放一份路径作用域规则让默认模式的运行自动带上检查清单——两条路都通向「检查标准版本化」。
三个高频场景的骨架:
- 日志分析:
cat build.log | claude -p "解释失败原因"。 - 自动提交:
--allowedTools "Bash(git diff *),Bash(git commit *)"把白名单收窄到 git 子命令。 - 定时摘要:cron 加
--continue,让每天的任务接着昨天的上下文。
git 通配符的坑单独记一句:白名单里通配符前有个空格,写成 git diff* 会连 git diff-index 一起放行。
边界与取舍:自动化的两个深渊
权限给宽了是安全洞,给窄了是假自动化
全放行类配置在 CI 里等于把仓库写权限交给概率系统;反过来,白名单太紧则任务永远「失败」,红灯常亮没人看。设计原则:按任务的最小工具面配 --allowedTools,写操作优先交给 acceptEdits 档而非全量放行,dontAsk 留给只读检查类任务;上线前先在本地用同一条命令跑三遍,确认退出码与输出稳定。
别把 SDK 当万能锤
SDK 的价值在「程序内逐事件控制」——权限回调、流式 UI、多会话编排;如果你的场景就是「定时跑一条命令、看退出码」,Headless CLI 更简单、更稳、维护成本低。判断顺序永远先 CLI 后 SDK:需要「把 Claude 作为组件嵌进产品」才写代码。
成本与超时是自动化任务的另外两条缰绳:长任务要设超时上限(Headless 的后台子进程默认五秒收尾、后台子代理最长等十分钟),SDK 场景用 maxTurns 限步数——无人值守的任务必须处处有闸,不然一次模型跑偏就是一次账单事故。
自测
合上文章先自己答,再展开对照:
CI 里跑 Claude Code,「权限怎么给」和「失败怎么算」怎么设计?
权限三件套按需组合:--allowedTools 白名单精确列出允许的工具(支持前缀匹配,如只放 git diff 与 git commit);--permission-mode 设档位(CI 常用 dontAsk 严锁或 auto 分类器代审);--permission-prompts none 声明无人可批,落到弹窗的请求直接拒绝并告知模型别重试,杜绝任务卡死在等批准。失败设计:退出码 0 成功、非零失败,脚本据此分支;输出用 --output-format json 做二级判读(校验 JSON 字段里的结论),SIGTERM 强停则退出 143 且当前轮不记结果,可恢复会话续跑。
SDK 方式与 Headless CLI 方式各适合什么自动化场景?
Headless CLI 适合「一发工单」型:单任务、文本进出、退出码即可判定成败——定时摘要、CI 检查、日志分析、管道处理,配 --bare 保证跨机器一致。Agent SDK 适合「程序内深度控制」型:要在自己的应用里起会话、逐事件收流式响应、用 canUseTool 回调在代码里裁决权限、interrupt() 打断、多会话编排——把 Claude 当作产品里的一个组件时才需要。选型顺序先 CLI 后 SDK:能用一条命令加退出码解决的,不要写程序。
参考与延伸
- Claude Code 官方文档《Headless mode》:-p/—bare/—output-format 与权限旗标语义的原始出处 — code.claude.com/docs/en/headless
- Agent SDK 快速开始(Python/TypeScript):程序内嵌入、权限回调与 CI/CD 集成 — code.claude.com/docs/en/agent-sdk/quickstart
下一站:Codex CLI 与 Agent CLI 对照——同赛道产品横向看:差异里藏着各自的设计哲学。