配置自诊断
CC /doctor 是 Ink 界面化体检(安装/更新/设置/上下文),Codex doctor 是带 JSON 输出与退出码的 18 项 CI 友好诊断;harness 预检 = 二进制 + 认证 + 版本兼容三件套
配置自诊断
结论
两家都有 doctor,但面向的消费者不同。CC 的 /doctor(也可 shell 直跑 claude doctor)是给人看的 Ink 界面:核心是安装健康(安装方式六分类、多重安装冲突检测、ripgrep 可用性)、更新健康(自更新状态/权限/渠道/远端版本)、设置合法性(zod 校验)、再加 CC 特色的上下文体检(CLAUDE.md/agents/MCP 的 token 占用警告、不可达权限规则),但没有机器可读输出。Codex 的 codex doctor 是给人也给脚本的诊断器:18 项检查(system/installation/runtime/search/config/auth/updates/network/websocket/MCP/sandbox/terminal/git/terminal title/state/thread inventory/app-server/provider reachability)并发执行,--json 输出脱敏的扁平 schema(每项带 category/status/issues/remediation/duration_ms),整体 fail 时退出码 1——明确设计为「只报告不修复」,CI 可直接消费。harness 的预检不应照抄任何一家,而是三件套:二进制存在与版本(which + --version)、认证有效(官方 API probe 或 login status)、版本兼容(与已验证 flag 语义比对);对 Codex 还可以直接吃 codex doctor --json。
研究问题
- CC 的
/doctor覆盖哪些检查项?如何检测多重安装? - Codex 有无对等机制?输出能否被程序消费?
- harness 应该预检什么?Yoda 现状与机会点?
各 Agent 设计与实现
Claude Code
入口:斜杠命令 /doctor(commands/doctor/index.ts:4-10,描述 "Diagnose and verify your Claude Code installation and settings",可被 DISABLE_DOCTOR_COMMAND 环境变量禁用)[一手源码];CLI 起不来时从 shell 跑 claude doctor(docs troubleshooting.md:22)[一手文档]。
诊断数据层(utils/doctorDiagnostic.ts)[一手源码]:
DiagnosticInfo字段:installationType、version、installationPath、invokedBinary、configInstallMethod、autoUpdates、hasUpdatePermissions、multipleInstallations[]、warnings[](issue+fix 成对)、recommendation、packageManager、ripgrepStatus(working / system|builtin|embedded)(doctorDiagnostic.ts:54-71);- 安装方式六分类:
npm-global | npm-local | native | package-manager | development | unknown。检测顺序:NODE_ENV=development → bundled 模式下探测 8 种包管理器(homebrew/winget/mise/asdf/pacman/deb/rpm/apk)→ npm-local → npm 全局路径启发式(含 nvm 路径与npm config get prefix前缀比对)(doctorDiagnostic.ts:86-148); - 多重安装检测是亮点:同时检查
~/.claude/local(npm-local)、npm 全局前缀的bin/claude(并 realpath 解析 symlink——若指向 Homebrew/Caskroom/且当前就是 brew 安装则不算重复)、无 bin 入口的「孤儿」全局包、原生安装~/.local/bin/claude与~/.local/share/claude(doctorDiagnostic.ts:205-315)[一手源码]。claude update复用同一诊断,更新前先警告多重安装与 PATH 指向问题(cli/update.ts:40-75)[一手源码]。
渲染层(screens/Doctor.tsx)的区块结构 [一手源码]:
| 区块 | 内容 | 位置 |
|---|---|---|
| Diagnostics | 当前运行的安装类型+版本、包管理器、路径、invoked binary、config install method、Search(ripgrep 状态与来源) | Doctor.tsx:268-318 |
| 多重安装/警告 | multipleInstallations 列表(标注 currently running)、warnings 的 issue+fix | Doctor.tsx:334-343 |
| Invalid Settings | settings zod 校验错误(MCP 除外单列) | Doctor.tsx:351 |
| Updates | 自更新开关(含禁用原因)、更新权限(No 时提示 sudo)、渠道、npm/GCS dist-tags(stable+latest 远端版本) | Doctor.tsx:66-83, 376-400 |
| Environment Variables | env 校验错误(capped/error 状态) | Doctor.tsx:429, 525 |
| Version Locks | 版本锁列表(PID 是否存活、清理 stale 锁数量) | Doctor.tsx:442, 522 |
| Agent/Plugin Errors | agent 文件解析失败、插件错误 | Doctor.tsx:450-458 |
| Unreachable Permission Rules | 永远不会命中的权限规则 | Doctor.tsx:466 |
| Context Usage Warnings | CLAUDE.md / agents / MCP servers 的上下文占用警告(CC 独有) | Doctor.tsx:474 |
| Sandbox | SandboxDoctorSection 组件 | Doctor.tsx:14, 426 |
macOS 上 claude doctor 还检查 Keychain 可访问性(登录失败排查路径,docs troubleshooting.md:779)[一手文档]。没有 --json 之类的机器可读输出——doctor 是 Ink 组件,结论只进终端 [一手源码+推断:未发现任何结构化输出路径]。
Codex CLI
入口:一等子命令 codex doctor,帮助文案 "Diagnose local Codex installation, config, auth, and runtime health"(cli/src/main.rs:159-160)[一手源码]。
输出契约(这是与 CC 最大的差异)[一手源码]:
- flag:
--json(脱敏机器可读报告)、--summary(紧凑行)、--all、--no-color、--ascii(cli/src/doctor.rs:149-170); - 报告 schema 刻意扁平:
DoctorReport { schema_version, generated_at, overall_status, codex_version, checks[] },每个DoctorCheck带id/category/status/summary/details/issues/remediation/duration_ms,DoctorIssue再细分severity/cause/measured/expected/remedy——注释明说是为了支持工具能逐行过滤/脱敏(doctor.rs:180-226); - 「不修复,只报告」:整体 fail 时退出码 1,让脚本能区分干净环境(
doctor.rs:301-331)。
检查项(build_report,doctor.rs:333-429):先同步跑 system、installation、runtime、search 四项,然后加载 config,成功则 tokio::join! 并发跑 14 项:config、auth、updates、network、websocket、MCP、sandbox、terminal、git、terminal title、state、thread inventory、app-server、provider reachability;config 加载失败也有降级路径继续跑子集(doctor.rs:431-439)[一手源码]。几个值得抄的细节:
updates检查会验证「npm install -g 将更新的包根 = 当前运行进程的包根」,提前抓出 PATH/prefix 错位导致的「更新了却没生效」(doctor/updates.rs:1-7模块注释、50-86);terminal检查覆盖 dumb terminal、窄于 80x24、非 UTF-8 locale、terminfo 不可读、SSH/WSL/VSCode 等远程指示变量、tmux 关键选项(doctor.rs:107-143常量表 +terminal_check)——这正是 harness 嵌入 PTY 时最常踩的雷区清单;- 网络探测统一走
curl -fsSL --max-time 5,失败只降级为 warning 不掩盖本地问题(doctor/updates.rs:28-32, 174-180)。
差异矩阵
| 维度 | Claude Code | Codex CLI |
|---|---|---|
| 入口 | /doctor(会话内)+ claude doctor(shell) | codex doctor(shell 子命令) |
| 机器可读 | 无 | --json(脱敏、schema_version 化) |
| 退出码语义 | 无明确契约 | overall fail → exit 1 |
| 检查并发 | React effect 逐块异步渲染 | tokio::join! 并发 + 每项 duration_ms |
| 安装健康 | 六分类 + 多重安装冲突检测(强项) | InstallContext 五分类 + npm 包根错位检测(强项) |
| 更新健康 | 自更新状态/权限/渠道/远端双渠道版本 | 缓存版本 + 远端 latest + npm root match |
| 配置校验 | settings zod 错误、env 校验 | config 加载 + strict 检查 |
| 认证检查 | Keychain(macOS)、/status 配合 | auth + provider 专项 + provider reachability + websocket |
| 上下文体检 | CLAUDE.md/agents/MCP token 占用警告(独有) | 无 |
| 终端体检 | 无 | dumb/窄屏/locale/terminfo/远程/tmux(独有) |
| MCP 体检 | 配置校验 + 上下文占用 | server 可达性(disabled 跳过、optional 降 warning) |
| 修复行为 | claude update/claude install 附带清理动作 | doctor 纯只读,remediation 给命令建议 |
最小复现
# CC:会话内 /doctor;或 shell:
claude doctor # Ink 界面,人读
# Codex:CI 友好
codex doctor --json | jq '.overallStatus, [.checks[] | {id, status}]'
codex doctor --summary; echo "exit=$?" # fail 时 exit=1
# harness 最小预检(不依赖任一家 doctor)
which claude && claude --version && claude auth status >/dev/null; echo "cc-auth=$?"
which codex && codex --version && codex login status; echo "codex-auth=$?"Harness 接入建议(Yoda 实践)
Yoda 当前没有「doctor」命名的功能,但已分层实现了预检三件套的前两件 [一手源码]:
- 二进制 + 版本:
DependencyManager两阶段探测(见版本章),结果含status/version/path/checkedAt/error,启动即后台跑全量并流式推给 UI(core/dependencies/dependency-manager.ts:104-169); - 认证有效性:注册表为每个 runtime 声明
OfficialApiProbeSpec——用对应 env key 对官方 API 发一个最便宜的认证请求(如 AnthropicGET /v1/models带x-api-key+anthropic-version头,OpenAIGET /models带 bearer;src/shared/runtime-registry.ts:99-110, 682-711),产出AgentApiProbeResult{ok,status,endpoint,error};订阅态登录则读 CLI 本地登录状态(AgentSubscriptionAccount,runtime-registry.ts:176-187); - 本地用量侧写:直接读各 CLI 的本地会话日志聚合 token/成本(
AgentLocalUsage,runtime-registry.ts:156-174)——这其实是 doctor 没有的「健康 + 消耗」视角。
机会点(按性价比排序):
- 直接消费
codex doctor --json:Yoda 对 Codex 的深度体检不必自建,spawn 一次解析overallStatus与逐项remediation即可;注意它有网络探测,应放后台并设超时 [推断]; - CC 侧补齐多重安装检测:CC doctor 不可机读,但其检查逻辑(
~/.claude/local、npm prefixbin/claude、~/.local/bin/claude三处 stat + realpath)足够简单,Yoda 可复刻——Yoda 现在which只取第一个命中,正是 CC doctor 要抓的「PATH 指向另一个安装」盲区 [推断]; - 版本兼容预检:在 probe 之后比对「Yoda 已验证的 flag 语义版本区间」(如 CC
--session-id、Codexresume子命令),不符则降级相应功能并提示升级——这是两家 doctor 都不会替 harness 做的事 [推断]; - 终端预检清单照抄 Codex:Yoda 的 PTY 尺寸(≥80x24)、TERM、locale 设置可对照
doctor.rs的 terminal 检查项做自检,提前规避 TUI 渲染劣化。
失效条件
- CC
/doctor增加机器可读输出(届时 Yoda 应改为直接消费;源为 v2.1.88 重构源,滞后线上约 2 个月) - CC 安装六分类或多重安装检测路径变化(
doctorDiagnostic.ts重构) - Codex doctor 检查项集合或
--jsonschema_version 升版(cli/src/doctor.rs) - Codex doctor 退出码契约变化(当前 fail=1)
- Yoda 接入
codex doctor --json后,Codex 把网络探测改为默认跳过/必选(影响超时策略)
参考资料
- CC docs:
claude-code-docs/docs/troubleshooting.md(/doctor 用法、Keychain)、setup.md(claude doctor 验证安装)、troubleshoot-install.md - CC 重构源:
src_2026-03-31/commands/doctor/index.ts、utils/doctorDiagnostic.ts、screens/Doctor.tsx、cli/update.ts - Codex 源(b89ce9a):
codex-rs/cli/src/doctor.rs、cli/src/doctor/{updates,runtime,system,thread_inventory,background}.rs、cli/src/main.rs:159-160, 1319 - Yoda 源:
src/main/core/dependencies/dependency-manager.ts、src/shared/runtime-registry.ts(OfficialApiProbeSpec / AgentApiProbeResult / AgentLocalUsage / AgentSubscriptionAccount)