# CLI 与启动 · grok 二进制怎么开机

> grok 一个二进制，既是 TUI，又是 headless，又是一堆子命令，还能当 agent 后端。这一章看组合根怎么开机、clap 怎么解析、以及 async_main 怎么把你敲的命令派往 TUI / headless / 子命令 / agent 模式。

- 作者：David（道雾轩）
- 专栏：Grok Build 源码解读（https://daiw.org/manual/grok-build.md）
- 最后更新：2026-09-15
- 原文：https://daiw.org/manual/grok-build/cli-surface
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# CLI 与启动 · grok 二进制怎么开机

Part 6 总览：`grok` 一个二进制承载了 TUI、headless、几十个子命令、还有 agent 后端模式。这一章看它怎么开机、怎么分流。

## 组合根开机

入口是 [Part 0 提过的组合根](https://daiw.org/manual/grok-build/install-and-run) `xai-grok-pager-bin`。`main()` 是**同步**的一串启动：mermaid 渲染 / 语音采集子进程**早退** → `PagerArgs::parse_cli()` 解析参数(`version`、`doctor` 当场处理完就返回)→ 装 minimal-mode 钩子 → jemalloc(可选)→ 整理进程环境 → 抬 fd 上限 → **校验运行环境**(`validate_requirements`，policy 不过 exit 2)→ sentry → 装 [crash handler](https://daiw.org/manual/grok-build/rust-engineering) → 收集上次崩溃的会话(`xai-grok-active-sessions` 找出 `~/.grok/active_sessions.json` 里 PID 已死的条目)→ 建多线程 tokio 运行时 → `run_and_shutdown(runtime, async_main(args), RUNTIME_SHUTDOWN_GRACE)`(2 秒优雅关闭)。和写作时相比，参数解析从 `async_main` 挪进了 `main()`，子进程早退也提到了最前面。

## clap 解析

`PagerArgs`(clap)分几组：全局(`--cwd`/`--yolo`/`--trust`)、headless(`-p`/`--output-format`/`--json-schema`)、会话(`--resume`/`-c`/`--fork-session`/`--worktree`)、模型行为(`-m`/`--effort`/`--permission-mode`/`--no-plan`)、屏幕(`--minimal`/`--fullscreen`)。还有一个位置参数(`grok "修 bug"`)和一个子命令枚举。

`Command` 枚举：`Agent`、`Login`/`Logout`、`Mcp`、`Plugin`、`Memory`、`Models`、`Sessions`、`Usage`、`Wrap`、`Update`、`Version`、`Completions`、`Worktree`、`DiskUsage`、`Doctor`、`Dashboard`……其中 `Doctor`、`Usage`、`DiskUsage`(即 `grok du`)是写作之后加的。user-guide 新增的 `grok clone`(把仓库拉进 Grove 内容仓并挂载成工作树)不在这个枚举里，遥测里把它标成独立的 utility process。

## async_main 分流

`async_main()` 是真正的分流器：

```mermaid
flowchart TB
  P["main(): PagerArgs::parse_cli"] --> V{version/doctor?}
  V -->|是| RUN0[当场处理并返回]
  V -->|否| EARLY{早退子命令?}
  EARLY -->|completions/wrap| RUN1[直接跑]
  EARLY -->|否| SUB{有子命令?}
  SUB -->|Agent| AG[run_agent_command:<br/>stdio/headless/serve/leader]
  SUB -->|login/update/models…| RUN2[各自 run]
  SUB -->|否| HL{headless prompt?}
  HL -->|-p| HR[headless::run_single_turn]
  HL -->|否| TUI["app::run(TUI)"]
```

- 最早：`version`、`doctor` 在 `main()` 里就处理掉了。
- 早退：`completions`(生成补全脚本)、`wrap`([grok wrap](https://daiw.org/manual/grok-build/pty-wrap-media))先处理。
- 有子命令：各自 `run`。`Agent` 子命令经 `run_agent_command` 按 `AgentCmd` 分派到 [stdio/headless/serve/leader](https://daiw.org/manual/grok-build/acp)。
- 没子命令但有 `-p`(或 `--prompt-json`/`--prompt-file`):[headless](https://daiw.org/manual/grok-build/headless)。
- 都不是：落到交互式 TUI(`app::run`)，启动前还后台起一个自更新检查。

agent、headless、TUI 三条路真正开跑前，都要先过一次 `enforce_version_policy_or_exit()`——组织配了必需版本区间时，版本不符就拒绝启动(见[工程底座](https://daiw.org/manual/grok-build/rust-engineering))。

<Callout type="info">
  一个二进制、一套 `PagerArgs`，靠 `async_main` 一次 `match` 把你分派到五种运行形态——这是「单入口、多形态」的清爽实现。你在前面几章看到的 TUI、headless、ACP、子命令，汇聚点就在这里。
</Callout>

## 和《从 LLM 到 Coding Agent》对照

教学最小实现通常就一个入口：读 prompt、跑循环。grok 的增量是一个**多形态二进制**的启动与分流：同步 boot 兜住崩溃/环境校验，`async_main` 把一条命令行分派到 TUI / headless / 子命令 / agent 后端。这是「一个可执行文件，同时是产品、脚本工具、和服务」的工程组织。下一章钻进它的鉴权。

---

上一篇：[后台任务、loop 与 monitor](https://daiw.org/manual/grok-build/background-tasks) · 下一篇：[认证与配置](https://daiw.org/manual/grok-build/auth-config)
