把AI编程Agent塞进CI流水线,最怕的不是它报错,是它一声不吭地把活干砸了。五个主流Agent CLI的无头模式,权限模型各不相同,其中有的会在没人值守的时候直接拒绝工具调用,然后继续往下跑。
![]()
Claude Code的文档写得很直白:一次运行碰到需要审批的工具调用,现场没人批,调用被拒,运行照常继续。Agent最后还能交回一条消息说它修好了那个不稳定的测试,任务显示绿色,diff却是空的。Gemini CLI是故意这么设计的——在非交互模式下,一条本该弹出来问你的规则,"被视为拒绝"。
下面按各家当前文档拆一遍,五个Agent、五套权限模型,有的拒绝你还不告诉你。
Claude Code:模式要显式给,CI里加--bare
不指定权限模式,运行会落到内置的起始模式,文档说这个模式"可能自动"。acceptEdits允许它写文件,但只读集合之外的shell命令仍然需要一条--allowedTools条目。
CI里还要加--bare。不加的话,一个-p会话会跑仓库.claude/settings.json里的钩子、连.mcp.json里的服务器,全程没有信任弹窗。bare模式跳过这些,也不读订阅登录,所以得设ANTHROPIC_API_KEY。
示例命令里,--output-format json把结果写进文件,再用jq检查permission_denials数组长度是否为零,有任何拒绝就让任务失败。Bash(npm test *)这条规则同时匹配裸的npm test。
Codex:默认只读沙箱
codex exec默认"跑在只读沙箱里"。你不加--sandbox workspace-write就让它修bug,它能读你的仓库,改不了。旧的--full-auto标志"已不再支持"。要写文件用--sandbox workspace-write,或者用--approve-for-me把审批请求送进自动审查。danger-full-access留给受控环境。
Codex还要求当前目录是Git仓库,--skip-git-repo-check可以绕过。同一页文档警告:在会执行仓库控制代码的工作流里,别把OPENAI_API_KEY或CODEX_API_KEY设成任务级变量。
Gemini CLI:策略文件管住非交互
--approval-mode接受default、auto_edit、yolo、plan四个值。--yolo和--allowed-tools都已废弃,后者让位给策略引擎。用户策略放在~/.gemini/policies/下,可以只允许某一条命令,且只在没有终端附着时生效——规则里写interactive = false,这条策略就"只在非交互(无头)模式下"适用,你手动开的会话照样会问你。
Gemini CLI还有个前提:文档说它"已于2026年6月18日被Antigravity CLI取代",针对免费层和Google One用户。账号还跑Gemini CLI的,上面这行成立;已经迁走的,继任者的打印模式是agy -p,在Antigravity CLI 1.1.8里拿到了--output-format和--json-schema。打印模式的用法错误以状态码2退出,1.3.4修掉了最后一个仍然退出0的问题。
Copilot CLI:拒绝规则优先级最高
Copilot的编程参考文档没说-p碰到一个你从未允许的工具会怎样。那就把能跑的和不能跑的都列出来。拒绝规则"即使设置了--allow-all"也照样生效,而--allow-all(别名--yolo)等于同时打开工具、路径和URL三扇门。
示例里用--allow-tool放行写入和shell(npm:*),用--deny-tool挡掉shell(npm publish),再加--no-ask-user防止它停下来问澄清问题。另一个坑:如果既管道输入又传-p,管道输入会被忽略。--continue和--resume在命令参考里是通用标志,但没写清怎么和-p组合,流水线依赖它之前先手动试一次恢复。
OpenCode:反着来,默认放行
OpenCode是另外四个的反面。"大多数权限默认允许",只有doom_loop和external_directory默认询问,.env读取被拒。所以opencode run不加任何标志就能改文件、跑shell命令。你的防线是项目opencode.json里的拒绝规则。
加--auto会批准每一个"未被显式拒绝"的请求,每条ask变成yes,那两行deny就是全部的围栏。不加--auto时,无头模式下的ask行为没有文档,只能当未知处理。还有个容易踩的:opencode run上的-p意思是--password,服务器的basic-auth密码,不是提示词。提示词是位置参数。
输出和退出码:别把日志当答案
第二个坑是解析日志,而你要的是答案。Claude Code用--output-format json打一个JSON对象,文本在result里,附带session_id和total_cost_usd(客户端估算)。加--json-schema,解析后的答案落在structured_output。Codex默认很干净:进度走stderr,只有最终消息走stdout;--json把stdout变成JSONL,从thread.started到turn.completed或turn.failed;-o把最终消息写进文件。Gemini CLI在JSON模式返回response、stats和可选的error对象。Copilot CLI不加-s会带上统计和装饰,--output-format json输出JSONL。OpenCode用--format json输出"原始JSON事件",但CLI页面没描述结构,解析前先锁版本。
五个里只有两个为无头运行写了退出码。Claude Code成功为0,失败非零,运行内部的失败(比如缺认证)会作为结果打到stdout,SIGTERM给143,JSON里的is_error和subtype(如error_max_turns)说明原因。Gemini CLI是0成功、1一般或API错误、42输入错误、53超出轮次上限。Codex只点名了一种失败退出:required = true的MCP服务器启动失败。Copilot的参考给的是copilot workflow run的退出码,不是-p的。OpenCode的CLI页面关于run的退出码只字未提。
退出0只说明进程结束了。所以Agent步骤之后自己加两道检查:Codex失败轮次就失败;任何本该改文件的Agent步骤,什么都没改就失败。第二道检查能抓住空diff的绿色构建,不管跑的是哪个Agent。
无头模式是给没人看的运行用的。其余时候,你大概还是想让同样的Agent把提示词摆在屏幕上。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.