Headless 模式 · 同一个 agent,脱掉 TUI
grok -p 让同一个 agent 内核脱掉终端界面,在脚本和 CI 里跑。这一章看 headless 怎么复用 TUI 那套会话启动与 SessionActor(「TUI 减去渲染」)、四种输出格式,以及给 CI 的退出码与鉴权。
Headless 模式 · 同一个 agent,脱掉 TUI
grok -p "修一下这个 bug" 让同一个 agent 在没有界面的情况下跑一轮——脚本、CI、管道。核心在 headless.rs。
「TUI 减去渲染」
最值得记的一点:headless 不是另一条 agent 路径。它复用和 TUI 完全相同的会话启动 SSOT(session_startup.rs)和同一个 SessionActor,只是不套 ratatui。run_single_turn 用 spawn_grok_shell 在进程内拉起 agent、开一条 ACP 通道,走一遍 initialize(由 build_headless_init_request 构造:clientType 取 HEADLESS_CLIENT_TYPE,值是 "grok-shell";startupHints{nonInteractive, skipGitStatus, skipProjectLayout}——省掉界面才需要的东西)→ 开/恢复会话 → prompt → 流式收尾。同一个大脑,脱掉一层皮。
四种输出格式
--output-format(headless/cli.rs 里的 OutputFormat):
- plain(默认):文本到 stdout,错误和进度到 stderr——保证 stdout 干净,好被管道消费。
- json:跑完输出一个对象,含
text、stopReason(snake_case,如end_turn)、sessionId、usage(各类 token)、total_cost_usd(不完整时连同各模型的 cost 一起省略,不给你半个数)。 - streaming-json:NDJSON 事件流,按
type分派:除了text/thought/end/error,现在还有tool_call、tool_call_update、每次模型响应一行的usage、plan等,end总在最后。 - streaming-messages-json(写作之后新增):按 Messages API 的
stream-json线格式输出(system/init→assistant/user→result),加--include-partial-messages还能拿到原始流事件;缺数据的用量字段回落为 0,宁少报、不多报。
给 CI 的细节
- 退出码:
0成功 /1出错 /130SIGINT /143SIGTERM。收到信号时状态存到最后一次完成的工具调用,但文件改动不回滚——resume 可续。 - 鉴权:
XAI_API_KEY、grok login --device-auth(见认证章)、或缓存凭据。GROK_HOME可换配置目录;~/.grok只读时持久化静默变临时。 - stdin 不进 prompt:必须用
$(...)或--prompt-file——一个容易踩的点。 - 还有
--max-turns、--json-schema(结构化输出)、--tools/--disallowed-tools(内置工具白/黑名单)这些 headless 专用 flag。写作时还在的--self-verify、--best-of-n已从 CLI 删掉。
headless 和 TUI 共用会话启动与内核,意味着行为一致:你在 CI 里 grok -p 跑出来的东西,和你在终端里手跑是同一套逻辑,连 resume、fork、compaction 都通用。「一套内核,多种前端(TUI/headless/ACP)」是这一部分反复出现的主题。
和《从 LLM 到 Coding Agent》对照
对照 Claude Code 的 headless(-p):两者思路一致——把交互式 agent 变成可脚本化的一次性调用。grok 的实现干净在「TUI 减去渲染」:不复制逻辑,只抽掉渲染层。下一章看它怎么当编辑器后端(ACP)。
上一篇:Plan mode · 下一篇:ACP · 编辑器后端