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
/doctorreport 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).
Detail
Section titled “Detail”| Component | Type | Scope | Uses (total since install) | Used in window? | Est. resident tokens | Verdict |
|---|---|---|---|---|---|---|
memtrace-skills@memtrace | plugin (27 skills) | user | 0 | no | 3,637 | remove |
understand-anything@understand-anything | plugin (9 skills + 12 agents) | user | 7 skill dispatches | no | ~950 | remove |
typescript-lsp@claude-plugins-official | plugin (LSP) | user | 0 | no signal (LSP) | ~0 | remove |
auggie | MCP server | user | n/a (no counter) | no (0 calls) | deferred | remove |
sync-intent-notes | skill | project | 0 | no | 208 | remove |
catalogue-form-requirements | skill | project | 0 | no | 164 | remove |
browser-testing-with-devtools | skill | project | 0 | no | 96 | remove |
security-guidance@claude-plugins-official | plugin (hooks) | user | 44,816 (hook fires) | yes | ~293 | keep |
caveman@caveman | plugin (hooks) | user | 4,073 | yes | 449 | keep |
mempalace@mempalace | plugin + MCP | user | 5,872 | yes (4 MCP calls) | 192 | keep |
pyright-lsp@claude-plugins-official | plugin (LSP) | user | 993 | yes | ~0 | keep |
commit-commands@claude-plugins-official | plugin | user | 472 (22 in window) | yes | ~150 | keep |
supabase / gitnexus / memtrace / coolify / context7 | MCP servers | user / project | n/a (no counter) | yes (322 / 142 / 15 / 21 / 2 calls) | deferred | keep |
agent-browser | skill | user | 82 | no (last 20 Jun) | 82 | keep — cheap, real use |
| 17 other project skills | skills | project | 2–511 each | mostly yes | ~2,835 | keep |
CLAUDE.md (root) | memory | project | — | always loaded | 2,654 | trim (checks 3+4) |
~/.claude/CLAUDE.md | memory | user | — | always loaded | ~100 | keep (memtrace-managed) |
7 nested CLAUDE.md | memory | project | — | on demand | 6,000 total | already 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.
Proposed actions
Section titled “Proposed actions”Check 0 — setup health: clean ✅
Section titled “Check 0 — setup health: clean ✅”Native install at ~/.local/bin/claude → 2.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.
Check 1 — unused extensions (7 items)
Section titled “Check 1 — unused extensions (7 items)”- Disable plugin
memtrace-skills@memtrace— 27 skills, ~3,637 est. tokens in every session’s skill listing, zero dispatches ever (checked bothmemtrace-skills:xand barexcounter keys) and zero in the window. Note this does not touch the Memtrace MCP server (15 calls in window) or thememtrace routehook — those stay.~/.claude/settings.json→"enabledPlugins": { "memtrace-skills@memtrace": false } - 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. ItspluginUsageof 23,126 comes from its SessionStart/PostToolUse hooks firing, not from you using it.~/.claude/settings.json→"understand-anything@understand-anything": false - Disable plugin
typescript-lsp@claude-plugins-official— 0 uses ever. LSP counters can lag a recent feature, but siblingpyright-lspshows 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. (/pluginwould show a load error if it’s broken.) - 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/handoffchains to it — buthandoffhas run 467 times and never once dispatched it. Veto this one if you want the chain kept alive.
Check 2 — local memory files: clean ✅
Section titled “Check 2 — local memory files: clean ✅”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)”CLAUDE.mdlines 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 needsNEXT_DIST_DIR=.next-1..4): see therun-canonicalskill.CLAUDE.mdlines 92, 96 — MemPalace mechanics (~380 est. tokens) →.claude/skills/recall-grounding/SKILL.md. The#1665wing-filter workaround, the archive palace CLI, and the cold-backup tarball path are lookup material, not per-turn context — andrecall-groundingalready 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.
Check 7 — version: current ✅
Section titled “Check 7 — version: current ✅”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:
| Pattern | Count | Kind | Why an allow rule won’t help |
|---|---|---|---|
Bash(grep) / Bash(rg) | 27 | all permission-rule | Blocked 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>) | ~50 | all permission-rule | Same hooks. Also cd is a prefix of arbitrary compound commands — never allowlistable. |
Edit / Write | 26 | mostly user-rejected | Write operations — never allowlistable, and both are already in your user allow list. |
Bash(diff supabase/types/database.types.ts) | 2 | permission-rule | Matches your deliberate project deny rule Read(supabase/types/database.types.ts). Respecting it. |
Bash(echo …), Bash(git …), Bash(sed …) | ~22 | mixed | Compound/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.
Warnings (no action taken)
Section titled “Warnings (no action taken)”Check 5 — slow hooks
Section titled “Check 5 — slow hooks”| Hook | Runs (10 d) | Median | Worst | Assessment |
|---|---|---|---|---|
Stop | 878 | 592 ms | 22 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:Bash | 4,171 | 971 ms | 6.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:startup | 985 | 945 ms | 34.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. |
UserPromptSubmit | 135 | 397 ms | 1.2 s | ✅ Fine. |
PostToolUse:Bash | 108 | 82 ms | 788 ms | ✅ Fine. |
Check 6 — context-heavy components
Section titled “Check 6 — context-heavy components”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)”Decisions
Section titled “Decisions”| Group | Decision |
|---|---|
| Check 1 — unused plugins (memtrace-skills, understand-anything, typescript-lsp) | Declined — about to start using these tools |
| Check 1 — auggie MCP + 3 unused skills | Declined — same reason |
| Check 3 — trim derivable CLAUDE.md content | Applied |
| Check 4 — migrate sections to skills | Applied |
| Check 8 — auto mode as default permission mode | Declined — keeping bypassPermissions at user scope |
| Check 9 — pre-approve denied read-only commands | Nothing 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.
Files changed
Section titled “Files changed”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-canonicalskill, keeping the load-bearingNEXT_DIST_DIR=.next-1..4constraint inline. - “Memory (MemPalace)” 3 paragraphs → 2, keeping the MUST-recall directive inline
and pointing at
recall-groundingfor mechanics. - Net: 10,615 → ~8,850 chars (≈ 440 est. tokens/session saved).
.claude/skills/run-canonical/SKILL.md— Step 4’s lock paragraph expanded into the full three-case rule set (different worktrees / same checkout / port collisionsportless), absorbing the migrated CLAUDE.md content.
.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:
| Script | Cost/call |
|---|---|
bash-heredoc-preflight.sh | 13.8 ms |
ip-leak-filename-guard.sh | 11.0 ms |
| Combined | 24.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.