Skip to content

D143 — doctor: a separate command that diagnoses and never repairs

cartographer doctor is a new read-only command that runs eight checks over this machine's client configuration and reports what is left over or missing, each finding naming a real path and the command that fixes it.

Why not status --strict. These checks read every provider's native config file, enumerate its MCP entries, count marker pairs in instruction files and scan Codex's config.toml for orphaned tables. That is an order of magnitude more work than status' revision comparison — and status is on the path the bootstrap hook's success message prints. Conflating them would slow down the fast command to serve the rare one. Two commands, two costs.

Diagnosis only. No --fix flag, and no writing of any kind: not even the lockfile migration ReadLockFile performs in memory anyway, not a created directory, not a refreshed cache. The repair paths already exist — sync restores managed files and removes Codex's double registrations, reconnect (D142) rebuilds, service sync-timer install adds the trigger — and each is individually reviewable. A doctor that silently fixes things is a doctor nobody can predict, and the operator would lose the one thing this command is for: knowing what was wrong.

Severity model. error means something is broken now (a managed file missing, a hook firing twice, an MCP entry pointing at a KB that is gone); warning means stale or suboptimal (a v1 lockfile, no trigger for a hook-less provider, a version difference). Both exit 1 — the operator should look at either — but the severity orders the output so the actionable one is read first. A third, info, carries what cannot be acted on by itself and never changes the exit code: managed entries recorded before materialized hashes existed cannot be verified at all, and reporting that per artifact would bury the real findings. Exit codes stay status' convention (0 clean, 1 findings, 2 command error) so scripts treat them identically.

Every finding names a path. "Something is wrong with claude" is not a diagnosis. The path is absolute and may legitimately be gone — that is exactly what a missing finding says — but it is always a place the operator can go and look.

Useful offline. The only network access is the /health probe sync already makes, and failing it produces one warning finding rather than aborting: a client whose server is down is precisely when someone runs doctor.

Never on the session path. Neither the bootstrap hook nor the scheduled timer invokes it. Eight checks on every session start is the background cost D60 avoided by keeping bootstrap.sh silent, deterministic and always exit 0.

One byproduct. The bootstrap hook's lockfile entries carried no materialized hash, so D139's verification could not check them and doctor would have reported "unverifiable" on every healthy machine forever. EnsureBootstrapHook now records the hash of the two files it writes — computed from the same constants, never read back — which makes the client-generated hook verifiable like any other managed artifact.