Skip to content

Claude Code health check — /doctor, 2026-07-26

Claude Code health check — /doctor, 2026-07-26

Section titled “Claude Code health check — /doctor, 2026-07-26”

Verbatim capture of the /doctor report as emitted in session. Decisions taken and changes applied are recorded in the appendix at the bottom (added after the report was presented).


Plain summary. Your install is healthy and up to date, and your memory files are clean. The real cost is in extensions: one plugin (memtrace-skills) puts ~3.6k tokens of skill descriptions into every session and has never once been used in 1,774 sessions, and three more items are similarly idle — about 5k tokens per session of dead weight. Everything I propose is reversible (disables are one command to undo; deleted CLAUDE.md text is quoted below so it can be restored).

ComponentTypeScopeUses (total since install)Used in window?Est. resident tokensVerdict
memtrace-skills@memtraceplugin (27 skills)user0no3,637remove
understand-anything@understand-anythingplugin (9 skills + 12 agents)user7 skill dispatchesno~950remove
typescript-lsp@claude-plugins-officialplugin (LSP)user0no signal (LSP)~0remove
auggieMCP serverusern/a (no counter)no (0 calls)deferredremove
sync-intent-notesskillproject0no208remove
catalogue-form-requirementsskillproject0no164remove
browser-testing-with-devtoolsskillproject0no96remove
security-guidance@claude-plugins-officialplugin (hooks)user44,816 (hook fires)yes~293keep
caveman@cavemanplugin (hooks)user4,073yes449keep
mempalace@mempalaceplugin + MCPuser5,872yes (4 MCP calls)192keep
pyright-lsp@claude-plugins-officialplugin (LSP)user993yes~0keep
commit-commands@claude-plugins-officialpluginuser472 (22 in window)yes~150keep
supabase / gitnexus / memtrace / coolify / context7MCP serversuser / projectn/a (no counter)yes (322 / 142 / 15 / 21 / 2 calls)deferredkeep
agent-browserskilluser82no (last 20 Jun)82keep — cheap, real use
17 other project skillsskillsproject2–511 eachmostly yes~2,835keep
CLAUDE.md (root)memoryprojectalways loaded2,654trim (checks 3+4)
~/.claude/CLAUDE.mdmemoryuseralways loaded~100keep (memtrace-managed)
7 nested CLAUDE.mdmemoryprojecton demand6,000 totalalready lean

Scan window: the 300 most-recently-modified transcripts (167 MB), 2026-07-17 → 2026-07-26 — 10 days across 14 project directories. I widened past the usual 50 files because 50 only covered 2 days. numStartups = 1,774, so lifetime counters are well-populated: a lifetime zero here is real evidence, not thin data.


Native install at ~/.local/bin/claude2.1.220, installMethod: "native" agrees, ~/.local/bin is on PATH, no npm-global or ~/.claude/local leftovers. All settings files parse (~/.claude/settings.json, both project files, ~/.claude.json; no .mcp.json). No agent definition files exist in either location — nothing to collide or break. Nothing to fix.

  1. Disable plugin memtrace-skills@memtrace — 27 skills, ~3,637 est. tokens in every session’s skill listing, zero dispatches ever (checked both memtrace-skills:x and bare x counter keys) and zero in the window. Note this does not touch the Memtrace MCP server (15 calls in window) or the memtrace route hook — those stay. ~/.claude/settings.json"enabledPlugins": { "memtrace-skills@memtrace": false }
  2. Disable plugin understand-anything@understand-anything — 9 skills + 12 agent types in the always-resident agent listing, ~950 est. tokens. 7 skill dispatches ever, none in the window, no agent dispatches in the window. Its pluginUsage of 23,126 comes from its SessionStart/PostToolUse hooks firing, not from you using it. ~/.claude/settings.json"understand-anything@understand-anything": false
  3. Disable plugin typescript-lsp@claude-plugins-official — 0 uses ever. LSP counters can lag a recent feature, but sibling pyright-lsp shows 993 in the same tracking era, so tracking works here — this is real disuse or a server that isn’t starting. Costs ~0 tokens; removing is decluttering, not savings. (/plugin would show a load error if it’s broken.)
  4. Disable MCP server auggie — 0 calls in 10 days. Its tools are deferred, so no token savings — this is one less connection to authenticate and keep updated. /mcp disable auggie — note this toggle is per-project; repeat it in other projects where you want it off. 5–7. Turn off 3 never-used project skills — 468 est. tokens combined. .claude/settings.local.json"skillOverrides": { "sync-intent-notes": "off", "catalogue-form-requirements": "off", "browser-testing-with-devtools": "off" } (joins the existing "proposal-writer": "off") ⚠️ sync-intent-notes’s own description says /handoff chains to it — but handoff has run 467 times and never once dispatched it. Veto this one if you want the chain kept alive.

No CLAUDE.local.md anywhere (project root or ancestors). ~/.claude/CLAUDE.md is a 4-line block managed by memtrace install — no overlap with your checked-in files, no contradictions. Nothing to dedup. (Editing it wouldn’t stick anyway — memtrace install rewrites it.)

Check 3 — trim derivable content from CLAUDE.md

Section titled “Check 3 — trim derivable content from CLAUDE.md”

Root CLAUDE.md is 10,615 chars — well under the ~40,000-char warning threshold, before and after. It’s genuinely well-curated (mostly gotchas and failure contracts, which are keeps). One clear cut:

CLAUDE.md lines 36–48 — directory layout table (13 lines, ~150 est. tokens). ls shows all of this. Two rows carry real conventions, so they survive as a bullet.

Verbatim block removed:

| Directory | Contents |
| --- | --- |
| app/ | Next.js 16 App Router — API + page routes |
| mcp-apps/ | MCP App UIs (Vite single-file builds) |
| components/ | Domain subdirs — never add components at root |
| contexts/ | React contexts |
| hooks/ | Custom hooks — domain sub dirs + general at root |
| lib/ | Core modules (ai/, mcp/, procurement/, validation/, …) |
| types/ | TypeScript types |
| scripts/ | Python pipeline (cocoindex_pipeline/), ingestion/search CLIs |
| supabase/ | Migrations + generated types |
| tests/ | Vitest tests — mirrors source structure |
| e2e/ | Playwright specs |

Replaced by: - **Layout conventions:** never add components at components/root (domain subdirs only);hooks/ takes domain subdirs plus general hooks at root.

CLAUDE.md lines 18, 20 — two standard command rows (~45 est. tokens): | bun lint / bun run format | ESLint / Prettier | and | bun run test:e2e | Playwright E2E | — both are in package.json scripts with no gotcha attached. The other rows stay: they carry warnings you can’t derive (bun build errors, integration tests hitting live Anthropic + Supabase, the NEXT_DIST_DIR slot).

Nested files (supabase/, lib/mcp/, components/, __tests__/, scripts/): already lean — nothing to cut. These are dense failure contracts (migration-stamp collisions, born-locked functions, fresh-server-per-request) that no amount of code reading would reconstruct.

Check 4 — migrate always-loaded content to lazy loading (~610 est. tokens/session)

Section titled “Check 4 — migrate always-loaded content to lazy loading (~610 est. tokens/session)”
  1. CLAUDE.md lines 26–30, “Parallel dev servers” (~288 est. tokens) → .claude/skills/run-canonical/SKILL.md. That skill is already “Launch recipe for the Canonical Next.js app locally” — exactly where a second-dev-server recipe belongs. Root keeps one pointer line: **Parallel dev servers** (same checkout needs NEXT_DIST_DIR=.next-1..4): see the run-canonical skill.
  2. CLAUDE.md lines 92, 96 — MemPalace mechanics (~380 est. tokens) → .claude/skills/recall-grounding/SKILL.md. The #1665 wing-filter workaround, the archive palace CLI, and the cold-backup tarball path are lookup material, not per-turn context — and recall-grounding already owns this discipline. The line-94 “MUST run a recall pass” directive stays in the root file — a must-do rule never moves into a lazily-loaded skill.

Not migrating: the GitNexus section (lines 98–109) sits inside <!-- gitnexus:start --> / <!-- gitnexus:keep --> markers — it’s tool-regenerated, so edits there get overwritten.

⚠️ Applying check 4 writes to .claude/skills/**, which your sentinel-gated-agents-skills-edit-guard.sh hook blocks — I’ll create the sentinel first (touch ~/.claude/.sentinels/..., already in your allow list) as part of applying.

All CLAUDE.md edits (checks 3 and 4) land as ordinary working-tree changes for you to review in git diff. I won’t commit them.

Installed 2.1.220; latest on the latest channel (native install, no autoUpdatesChannel set) is 2.1.220. Note autoUpdates: false in ~/.claude.json — background updates are off, presumably deliberately. You’re current anyway today; the tradeoff is you’ll need claude update manually to stay that way. No action proposed.

Check 9 — pre-approve denied read-only commands: nothing to propose

Section titled “Check 9 — pre-approve denied read-only commands: nothing to propose”

197 denials in the window (124 permission-rule, 73 user-rejected), and an allow rule would fix none of them:

PatternCountKindWhy an allow rule won’t help
Bash(grep) / Bash(rg)27all permission-ruleBlocked by your own PreToolUse: Grep|Glob|Bash hooks (memtrace route --hook, gitnexus-hook.cjs) steering search to Memtrace/GitNexus. Hook denials override allow rules.
Bash(cd <path>)~50all permission-ruleSame hooks. Also cd is a prefix of arbitrary compound commands — never allowlistable.
Edit / Write26mostly user-rejectedWrite operations — never allowlistable, and both are already in your user allow list.
Bash(diff supabase/types/database.types.ts)2permission-ruleMatches your deliberate project deny rule Read(supabase/types/database.types.ts). Respecting it.
Bash(echo …), Bash(git …), Bash(sed …)~22mixedCompound/model-authored command strings that wouldn’t pass read-only validation.

Your permissions.deny and ask lists are otherwise empty, and your default mode is bypassPermissions — so nothing is prompting you that a rule could pre-approve. No rules proposed.


HookRuns (10 d)MedianWorstAssessment
Stop878592 ms22 runs hit a 30 s timeout🔴 Worst case. Two Stop hooks are configured: tail-claude-hud hook cleanup (user scope) and security-guidance’s Python security_reminder_hook. 22 turns ended with a 30-second stall. The transcript records only the event name, so I can’t attribute which one — try disabling tail-claude-hud’s Stop entry first, since HUD cleanup is the likelier hang.
PreToolUse:Bash4,171971 ms6.4 s🟡 Under the 2 s rule of thumb but by volume the biggest tax: ~68 minutes of blocking latency over 10 days. Five hooks chain on every Bash call — bash-heredoc-preflight.sh, ip-leak-filename-guard.sh, intent-acp-autoallow.sh, gitnexus-hook.cjs, memtrace route --hook. The two Node/CLI ones pay a cold interpreter start each time. Narrowing matchers or merging the two guard scripts would cut this materially.
SessionStart:startup985945 ms34.3 s🟡 Median fine (10 s threshold); the 34 s outlier is one of mempal-recall.sh, lavish-axi, gh-axi, chrome-devtools-axi, or security-guidance’s ensure_agent_sdk.py — the last does a Python dependency check at startup.
UserPromptSubmit135397 ms1.2 s✅ Fine.
PostToolUse:Bash10882 ms788 ms✅ Fine.

Est. always-resident, largest first: project skill listing 3,303 (27 skills) · memtrace-skills listing 3,637 · root CLAUDE.md 2,654 · understand-anything ~950 (9 skills + 12 agents) · caveman 449 · security-guidance 293 · mempalace 192 · agent-browser 82 · ~/.claude/CLAUDE.md ~100. All MCP servers are deferred → ~0 tokens (names only; schemas fetch on demand).

Total skill/agent listing ≈ 8.6k est. tokens against a ~10k budget (1% of your 1M window) — 86% consumed. That matters beyond raw cost: once the listing overflows, descriptions get truncated and skill routing degrades. The proposed removals drop it to ~3.6k. Run /context for the exact live measurement — mine are disk-based estimates.


Appendix — decisions and changes applied (2026-07-26)

Section titled “Appendix — decisions and changes applied (2026-07-26)”
GroupDecision
Check 1 — unused plugins (memtrace-skills, understand-anything, typescript-lsp)Declined — about to start using these tools
Check 1 — auggie MCP + 3 unused skillsDeclined — same reason
Check 3 — trim derivable CLAUDE.md contentApplied
Check 4 — migrate sections to skillsApplied
Check 8 — auto mode as default permission modeDeclined — keeping bypassPermissions at user scope
Check 9 — pre-approve denied read-only commandsNothing proposed — all 197 denials come from the user’s own routing hooks, which allow rules cannot override

The declined items remain valid findings — the numbers in the table above are the re-review baseline if usage does not materialise.

  1. CLAUDE.md (root) — 4 edits:
    • Removed the 13-line directory-layout table; replaced with a one-line “Placement conventions” bullet keeping the two real conventions.
    • Removed 2 derivable command rows (bun lint / bun run format, bun run test:e2e).
    • “Parallel dev servers” 5-line block → 1-line pointer at the run-canonical skill, keeping the load-bearing NEXT_DIST_DIR=.next-1..4 constraint inline.
    • “Memory (MemPalace)” 3 paragraphs → 2, keeping the MUST-recall directive inline and pointing at recall-grounding for mechanics.
    • Net: 10,615 → ~8,850 chars (≈ 440 est. tokens/session saved).
  2. .claude/skills/run-canonical/SKILL.md — Step 4’s lock paragraph expanded into the full three-case rule set (different worktrees / same checkout / port collisions
    • portless), absorbing the migrated CLAUDE.md content.
  3. .claude/skills/recall-grounding/SKILL.md — new “§3 On-demand historic stores” (archive palace CLI + cold transcript backup); old §3 renumbered to §4.

To undo: git checkout -- CLAUDE.md .claude/skills/run-canonical/SKILL.md .claude/skills/recall-grounding/SKILL.md (the removed CLAUDE.md text is quoted verbatim in check 3 above).

Guard-script merge — scoping result: NOT worth implementing

Section titled “Guard-script merge — scoping result: NOT worth implementing”

Measured on this machine, 20 iterations each, synthetic PreToolUse payload:

ScriptCost/call
bash-heredoc-preflight.sh13.8 ms
ip-leak-filename-guard.sh11.0 ms
Combined24.8 ms — 2.5% of the 971 ms PreToolUse:Bash median

Merging them into one script saves one bash spawn + one jq spawn ≈ 11 ms, or ~1% of the chain. The remaining ~946 ms sits in the three user-scope hooks — intent-acp-autoallow.sh (bash, exits early outside ~/intent/workspaces/), gitnexus-hook.cjs (Node cold start per call), and memtrace route --hook. The last two were not timed: unlike the project guards they are not plainly read-only, so executing them to measure was out of scope.

Merging is technically straightforward (both read stdin, jq one field, exit 0/2), but it has a real cost: ip-leak-filename-guard.sh is registered on two matchers (Bash and Write|Edit|MultiEdit) while the heredoc guard is Bash-only, so a merge means either duplicating the denylist logic across two files or making one script serve both matchers with an internal branch. Paying that for 1% is not a good trade.

Where the latency actually is: the two Node/CLI routing hooks on PreToolUse: Grep|Glob|Bash, and the Stop hook that timed out 22 times at 30 s.

⚠️ Separate finding — the IP-leak guard is currently toothless

Section titled “⚠️ Separate finding — the IP-leak guard is currently toothless”

While scoping the merge: ip-leak-filename-guard.sh resolves its denylist to $KH_PRIVATE_DOCS_DIR/.config/ip-denylist.txt. That file is present (381 bytes, 6 lines) but contains 5 comment lines and 1 blank line — zero active terms.

The hook runs on every Bash/Write/Edit call, loops over zero terms, and exits 0. It blocks nothing today. Both CLAUDE.md (“Guard hooks enforce: … no client names in filenames/commands (private denylist)”) and supabase/CLAUDE.md (“enforced by the ip-leak-filename-guard hook against the private denylist”) cite it as the live enforcement mechanism for the F8 near-miss class.

Either the denylist was never populated, or its terms were removed. Worth checking against the private docs-site history.