doctor · git:20260807.d13beb6 · 2026-08-07 · sha256 d961e773f24513d7

doctor git:20260807.d13beb6B

Immutable. This exact content is served forever at /api/v1/blob/d961e773f24513d7.

---
name: doctor
description: Audits the orchestration setup without changes for model drift, stale pins, and environment overrides. Use when routing behaves oddly, after a CLI upgrade, or when model drift is suspected.
allowed-tools: Read, Glob, Bash(rg:*), Bash(node:*), Bash(codex --version:*), Bash(grok --version:*), Bash(grok models:*), Bash(grok inspect:*), Bash(grok --help:*), Bash(grok agent --help:*)
---

Audit the orchestration setup and report findings as a short checklist with a clear verdict per item.

Environment overrides captured at invocation:

- CLAUDE_CODE_SUBAGENT_MODEL: !`sh -c 'printenv CLAUDE_CODE_SUBAGENT_MODEL || echo "(unset)"'`
- ANTHROPIC_MODEL: !`sh -c 'printenv ANTHROPIC_MODEL || echo "(unset)"'`
- ANTHROPIC_DEFAULT_HAIKU_MODEL: !`sh -c 'printenv ANTHROPIC_DEFAULT_HAIKU_MODEL || echo "(unset)"'`
- ANTHROPIC_DEFAULT_FABLE_MODEL: !`sh -c 'printenv ANTHROPIC_DEFAULT_FABLE_MODEL || echo "(unset)"'`

Checks to perform:

1. A set CLAUDE_CODE_SUBAGENT_MODEL can silently override every agent model pin (Claude Code behavior as observed on 2.1.x); flag it as a problem unless the user says it is deliberate.
2. Read ~/.claude/settings.json and report the `model` key. It should be an alias, preferably `best[1m]` (Fable when available, latest Opus otherwise, floats to future releases). Flag any dated full model ID as a rot risk. Also confirm codex@claude-code-fusion, grok@claude-code-fusion, and fusion@claude-code-fusion appear in enabledPlugins. Treat codex@openai-codex and codex@claude-code-fusion being enabled together as an error because both register the `codex` namespace. When Codex is missing, report that ordinary implementation has lost its primary lane. Bounded isolated work may use Grok under `burst`; work whose load bearing capability is Claude tools or privacy, or that is structurally stranded with a stated `claude-fallback: <reason>` header, uses fusion:claude-worker. Recommend installing codex@claude-code-fusion.
3. Read the frontmatter of every file in ${CLAUDE_PLUGIN_ROOT}/agents/ and report each `model`, `effort`, and `maxTurns` value. Alias pins (opus, sonnet, haiku) float to new releases automatically and are healthy. Full model ID pins are rot risks; fusion:trivial-worker's claude-haiku-4-5 pin is deliberate because the haiku alias can be remapped by ANTHROPIC_DEFAULT_HAIKU_MODEL, so a full ID pins the tier to the intended model regardless of that override, but it must be bumped by hand when a newer cheap tier ships.
4. List ~/.claude/agents/ if it exists. A file whose name matches a plugin agent (deep-reasoner, claude-worker, trivial-worker) registers as a duplicate agent alongside the fusion: namespaced one and confuses auto delegation; flag it as a stale leftover to delete unless the user says it is a deliberate local override.
5. Compare the template hash of ~/.claude/rules/orchestration.md against the template hash of ${CLAUDE_PLUGIN_ROOT}/rules/orchestration.md, using the same normalization as rules-sync: replace everything between the `<!-- fusion:model-table:start -->` and `<!-- fusion:model-table:end -->` sentinel lines with the fixed normalized marker before computing SHA-256. Prefer `node --input-type=module` with `hashRulesTemplate` exported by `${CLAUDE_PLUGIN_ROOT}/scripts/lib/rules-template.mjs`; a sed or similar comparison that strips only the sentinel region is also acceptable. Missing live rules or a mismatched template hash means the static routing policy is stale; point at /fusion:setup to install or update it. A user selected live model table may differ from the scored canonical table and is healthy when the template hashes match.
6. Remind the user of the role model: the main Claude session is the only control plane and final judge. Claude workers are native specialists rather than an independent model family, Codex owns ordinary implementation and default deep external review, and Grok keeps the protected `burst`, `independence`, `live-web`, and `large-context` roles. The orchestrator, deep reasoning, mechanical, and trivial Claude tiers are roles bound to alias tiers, not to specific models, so same tier releases (for example Sonnet 5 under the sonnet alias) adopt their role with no configuration change. Only a genuinely new tier above or between the existing rungs requires a decision.
7. Note the recovery moves: Fable is the intended orchestrator, and a main session found on Opus 5 or any lower tier is a fallback state to report (availability, safety classifier, or quota), not a peer configuration; /model best restores the strongest available orchestrator, and the session meanwhile keeps orchestrating under the full rules and narrows nothing. Peer engine models are owned by their own CLIs (~/.grok/config.toml, ~/.codex/config.toml); this setup never pins them.
8. Point at /codex:setup and /grok:setup for peer runtime health checks beyond config defaults; peer config defaults themselves are covered in the next step.
9. Peer engine defaults: extract the model related keys from ~/.grok/config.toml and the model and model_reasoning_effort keys from ~/.codex/config.toml (never read or print the full files; they sit next to credentials; use a scoped rg query rather than Read on those two files). Report each peer's configured default and flag grok drift when the grok CLI default is absent from the capability table or when that table's recorded lane or scores disagree with the default shown by the CLI. Run `node "${CLAUDE_PLUGIN_ROOT}/scripts/fusion-config.mjs" audit` and report its Codex listing section as one checklist item. It reads only ~/.codex/models_cache.json (or FUSION_CODEX_MODELS_CACHE) and never refreshes it or invokes the Codex binary. Flag the configured-but-absent IDs and unconfigured gpt-* newcomers it reports, including the listing mtime. Treat `listing unavailable` as a warning without aborting the doctor run. /fusion:config is the write path for changing these scores; this audit never changes model-routing.json. When the capability table has no scored models at all, recommend /fusion:config propose so routing stops relying on the qualitative lane descriptions alone.
10. Audit the installed Codex slash-command surface against the foreground invariant. Glob `~/.claude/plugins/cache/claude-code-fusion/codex/*/skills/*/SKILL.md` and `~/.claude/plugins/cache/claude-code-fusion/codex/*/agents/`, then inspect the task, rescue, review, adversarial-review, and codex-rescue instructions. Task and review calls must stay foreground regardless of complexity, expected duration, review size, or model unless the incoming user request explicitly supplied `--background`; the rescue agent's companion Bash call must use the 10 minute tool timeout. A package that cannot fit the cap must be split or routed elsewhere. Fusion orchestration gives every detached job it creates one same turn collection attempt capped at 540000ms; a timeout must remain explicitly uncollected with the job id and result command. Direct Codex slash command instructions inspect through status and collect through result; Fusion's monitor is notification only. Confirm that task and rescue expose opt in `--web`, require `--write --network` for sandbox network access, and leave both settings disabled when absent. Flag any instruction that can detach implicitly or accepts a foreground receipt as a result.
11. Check ~/.claude/plugins/data/codex-claude-code-fusion/state, the canonical root for new Codex jobs. If it does not exist, report no recorded Codex job history yet or an uninitialized Codex state path, not necessarily an error.
12. In the live ~/.claude/rules/orchestration.md, collect every concrete model ID named in routing prose outside the `<!-- fusion:model-table:start -->` and `<!-- fusion:model-table:end -->` sentinel region, then compare them with the model IDs in the live capability table. Flag every prose ID without a table row as an orphan.
13. Probe the installed Codex plugin cache's slash-command surface by globbing `~/.claude/plugins/cache/claude-code-fusion/codex/*/skills/*/SKILL.md` for the `/codex:task`, `/codex:rescue`, `/codex:review`, `/codex:adversarial-review`, `/codex:status`, `/codex:result`, `/codex:cancel`, and `/codex:setup` command files and `~/.claude/plugins/cache/claude-code-fusion/codex/*/agents/` for the codex-rescue agent. Report any absent surface as a degraded-capability warning, not an error.
14. Audit the installed Grok runtime and instructions against the actual headless surface, not version assumptions. Consult, write, and review must all use `--sandbox strict`; a workspace downgrade is an error. Every managed run requires `--prompt-file`, `--output-format`, `--sandbox`, `--tools`, `--disallowed-tools`, `--deny`, `--max-turns`, and `--no-auto-update`; consult also requires `--permission-mode` and `--allow`, no-web requires `--disable-web-search`, write requires `--always-approve`, review requires `--json-schema`, ordinary calls require `--no-wait-for-background`. Missing installation, version, or applicable capability readiness is failure kind `setup`; recommend upgrading or repairing the CLI and rerunning `/grok:setup`, never retrying the unchanged task. Consult tools are read, grep, and list plus optional direct web tools. Write tools are `read_file`, `grep`, `list_dir`, `search_replace`, and `run_terminal_cmd`, with Agent always denied; upstream 1.0.0's OpenCode-compatible `write` tool id stays outside the fixed allowlist, and `search_replace` creates files. Every mode denies `search_tool`, `use_tool`, `ask_user_question`, and MCP tools, while ordinary calls also deny Agent. Treat command-pattern denies for common direct grok, claude, and codex invocations as best effort because absolute paths, aliases or functions, and indirect scripts can bypass them. A hard nested-execution boundary requires removing `run_terminal_cmd` or an OS-level executable or network policy. Builder tracing starts only after stdin is consumed, so it cannot prove policy before prompt delivery or every side effect; fallback or unmatched warnings must terminate early, and a successful close without positive `tools allowlist applied` evidence is an error. Confirm the following behavior. The child sets all eighteen `GROK_CLAUDE_*_ENABLED`, `GROK_CURSOR_*_ENABLED`, and `GROK_CODEX_*_ENABLED` bridge variables to false; upstream currently consumes the six Claude and six Cursor cells plus the Codex sessions cell and reserves the other five Codex cells, and the child also pins `GROK_MANAGED_MCPS_ENABLED=false` because that variable has highest precedence over `[managed_mcps]` in `~/.grok/config.toml` and remote settings. Audit the companion's deterministic child environment for 1.0.0: `GROK_WEB_FETCH` is pinned by web mode, `GROK_AUTO_WAKE` and `GROK_MANAGED_MCP_GATEWAY_TOOLS_ENABLED` are pinned false, and `GROK_TEST_VERSION`, `GROK_SANDBOX`, `GROK_LEADER_SOCKET`, `GROK_SUBAGENTS_MAX_DEPTH`, `GROK_WEB_FETCH_PROXY`, and `GROK_WEB_FETCH_ALLOW_LOCAL` are removed. Confirm that it removes inherited `CLAUDE_CODE_*`, `CLAUDE_PLUGIN_*`, `GROK_COMPANION_*`, and `_GROK_CLAUDE_MARKER_OVERRIDE`, broadly scrubs unrelated secrets while preserving xAI authentication, and passes `--no-auto-update`. Confirm `GROK_MEMORY=0` is forced by default, only a direct ordinary task with explicit `--memory` receives `GROK_MEMORY=1`, and Fusion routed briefs, review, and stop gate cannot enable it. Report Grok hard version startup requirements (introduced in 0.2.112, verified through 1.0.0; exit 1 regardless of `--no-auto-update`, classified `setup`) as the residual execution and network boundary.
15. Audit native Grok configuration as a user-controlled trust boundary. The `search_tool`, `use_tool`, and MCP denies block model invocation but do not prove that native MCP servers, plugins, or hooks under `~/.grok` were not started during agent construction or had no side effects; those bridge variables disable Codex compatibility imports, not native Grok configuration. Run `grok inspect --json` and review the reported `permissions`, `hooks`, `plugins`, `agents`, `mcpServers`, and `externalCompat` surfaces as the native configuration exposure check that the SECURITY threat model otherwise cannot verify. Use scoped `rg` queries that report configured surface names without printing credentials or full configuration, and label any native startup surface as an explicit trust-boundary notice rather than claiming MCP side effects are disabled. The entire Grok home is read-write under strict, and the sandbox permits consult `read_file` to reach `~/.grok/auth.json`, config, and sessions while write terminal commands may receive preserved xAI authentication variables. Confirm the companion's best-effort Read denies cover `auth.json`, `mcp_credentials.json`, `config.toml`, `sessions`, `memory`, `logs`, and `debug` with both absolute paths and standard `**/.grok` patterns. Report that raw path variants, symbolic links, and shell or indirect scripts can bypass those tool-level rules, so environment scrubbing and pattern denies do not isolate filesystem credentials. When memory is explicitly enabled, upstream's internal first-turn memory injection is not a model `read_file` call and can place selected memory in the model context sent to xAI despite those Read denies. Narrower exposure requires a dedicated sandbox profile, an isolated Grok home, an authentication broker, or upstream path-level authorization.
16. Audit Grok sandbox, transport, output, metrics, session, worktree, collection, continuity, history, and ACP evidence. Strict's upstream `system_read` roots include `/var` and `/tmp` on Linux, and `/private` plus the entire `~/Library` on macOS, so shared temporary content and substantial user application configuration and caches may be readable. Its write roots include the workspace and entire Grok home, always include `/tmp` and `/var/tmp`, and on macOS also include `/private/tmp`, `/private/var/tmp`, and all of `/private/var/folders`; the unique private `TMPDIR` is preferred and handshake-verified, not the only writable temporary surface. Before prompt delivery, the adapter must validate a new `ProfileApplied` event from the incremental shared `sandbox-events.jsonl` delta that contains this run's private path and matches the canonical workspace, strict profile, enforced state, and requested `restrict_network: true` configuration. Upstream events have no run id or pid, so unrelated `ProfileApplied` and `ApplyFailed` records are not attributable to this run; failure events are auxiliary only. A matching owned-stderr warning, handshake timeout, missing or malformed matching evidence, shared-log rotation or disappearance, or matching field mismatch fails closed. The matching event proves configuration application, not actual network isolation: Linux uses seccomp, while macOS network blocking is a no-op and write shells may reach the network. Every prompt uses `--prompt-file /dev/stdin`. Stdout uses a 0600 file unlinked immediately after open and parsed through its descriptor under the total limit. An upstream `model_usage` row contains only input, output, cache-read, and model-call counts plus optional cost, never synthetic reasoning or total tokens. `usage_is_incomplete` makes reported values observed lower bounds and both job-total token and cost coverage incomplete. Exact cost otherwise requires a positive complete USD and tick pair, with ticks authoritative at 10000000000 per USD. Short-cwd metadata uses only the exact encoded path; long-cwd lookup requires an exact decoded or `.cwd` match and never selects a sole cross-cwd candidate. Review requires one `--json-schema` call; an error or explicit null structured result fails, and only a completely absent field permits local text parsing. Continuity must default to `manual`; optional `claude-session` affinity may select only a completed ordinary task from the same Claude session, exact resolved cwd, mode, strict profile, and memory boundary. Fusion routed briefs must not receive automatic affinity, while explicit resume remains limited to compatible terminal task records. `/grok:history` must expose only the safe companion metadata projection, default to the current workspace, and never read native session contents, briefs, results, or logs. Treat native sessions, companion history, and cross-session memory as three separate stores. Native session cleanup defaults to 30 days and accepts only a positive `[storage] cleanup_ttl_days`, with `0` falling back to 30; the companion ledger has no promised automatic garbage collection. Fusion creates real worktrees. Upstream ships ACP today, but the companion has not adopted it and continues per-call invocation; any future companion adoption must pool by canonical cwd plus sandbox profile with `grok --cwd <canonical> --sandbox <profile> agent --no-leader stdio`. A collector timeout, dead job, or status error reports the Fusion task id, peer job id, `uncollected`, and exact result command. Successful Grok collection remains unverified until `/fusion:stats --record <fusion-task-id>=<accepted|rejected>` records the main-loop judgment.
17. Run `codex --version` and `grok --version` and compare them against the verified contract versions in `${CLAUDE_PLUGIN_ROOT}/verified-versions.json`. An installed version older than the verified one is a compatibility warning. A newer one is an informational drift notice that the companion contracts were verified against the older release and behavior may have moved. Neither is an error by itself because a companion call failing with failure kind `setup` is the enforcement signal. Multiple Codex generations sharing one `CODEX_HOME` (for example an IDE or desktop app bundling a newer Codex) are worth flagging when the versions straddle the verified release.

Report the findings compactly. Do not change any file; this command is read only.