react-doctor
Use when finishing a feature, fixing a bug, before committing React code, or when the user wants to improve code quality or clean up a codebase. Checks for score regression. Covers lint, accessibility
SKILL.md.claude/skills/react-doctor/SKILL.md
GitHubReact Doctor
Scans React codebases for security, performance, correctness, and architecture issues. Outputs a 0–100 health score.
Commands
bun run doctor # the enforced check; pinned, non-interactive
bunx react-doctor --verbose # per-file, per-rule detail
bunx react-doctor why <file>:<line> # why a rule fired, or why a suppression didn't apply
Always use the pinned copy (bun run doctor / bunx react-doctor), never
npx react-doctor@latest: the gate runs the pinned version, so a scan on
@latest can disagree with CI.
bun run doctor exits non-zero on any warning, so there is no score to
eyeball. It is part of bun run test and runs in CI, so a regression fails the
PR. For general cleanup, run the --verbose scan and fix errors before
warnings.
Dorkroom specifics
- It scans four projects and prints four scores:
@dorkroom/source(the app),@dorkroom/mobile,@dorkroom/logic,@dorkroom/ui. All four must be 100. - The app scan resolves
@dorkroom/*to package source, so the same physical file is reported under bothpackages/.../src/...and baresrc/...— fix it once; verify it's gone from both. - It respects inline disables. Prefer a real fix; only suppress a genuinely
subjective/false-positive finding, always with a justifying comment:
// eslint-disable-next-line react-doctor/<rule> -- whyfor native rules, orjsx-a11y/<rule>for a11y rules. Usewhy <file>:<line>to confirm a suppression applies, and check the rule name is current: upstream renames rules between versions. - React Doctor's checks are separate from the gate: a 100 score does not
mean
bun run testpasses (and the gate's typecheck is a no-op on the solution tsconfigs). Always run bothbun run testand React Doctor. - Config lives in
doctor.config.jsonat the repo root. It ignores generated/vendored/non-React trees (supabase/functions) and thedeslop/unused-*dead-code rules. Those dead-code rules are disabled because react-doctor's import analysis cannot resolve this repo's@/path alias, Vercelapi/serverless entrypoints, Vitest manual mocks (__mocks__),.mjsbuild scripts, or shell-script CLI usage (e.g.turbo-ignoreinscripts/should-deploy.sh,lucide-staticinapps/mobile/scripts/generate-tab-icons.mjs) — so it reports those as "unused" false-positives. Circular-import detection stays on. - Re-check every rule ignore in
doctor.config.jsonon each react-doctor upgrade. Ignores added for upstream false positives go stale once upstream fixes the rule.