Code Quality

Dead Code Finder

Find code nothing calls -- unused exports, unreachable branches, orphaned files -- and verify each one before recommending deletion.

When to use this

  • Periodic codebase hygiene pass, or before a major version cleanup.
  • When a file/function feels vestigial and you want confirmation before deleting it.
  • Not a substitute for a language-specific dead-code linter where one exists -- run that first, use this for what it misses (dynamic dispatch, reflection, string-based lookups).

The skill file

Copy this verbatim. It's written in the SKILL.md format (YAML frontmatter + markdown instructions) that Claude Code, and increasingly other agent tools, read directly.

SKILL.md
---
name: dead-code-finder
description: Locate exports, functions, files, and branches that nothing in the codebase actually calls or imports, and verify each candidate before recommending removal. Use for codebase cleanup passes, not for reviewing a specific diff.
---

# Dead Code Finder

False positives here are expensive -- deleting something a dynamic caller
still needs breaks production silently. Verify harder than you think you
need to.

## Search strategy

1. For each candidate symbol (function, class, export, route, config key),
   search the whole repo for its name as plain text, not just as an import
   statement -- dynamic dispatch, string-keyed lookups, and reflection won't
   show up as a normal reference.
2. Check non-code call sites too: templates, config files, CI scripts,
   database migration references, feature-flag definitions.
3. Check test files -- a symbol only referenced by its own test is still
   dead in production, but flag that distinction explicitly rather than
   silently excluding it.
4. For a whole file, check the build/bundle entry points and route tables,
   not just other source files -- an unreferenced page component can still
   be live if it's wired through a router config.

## What to report

For each candidate: the symbol/file, where you searched, and your
confidence (certain / likely / needs a human to confirm because it's
reachable only through configuration you can't fully trace here).

## Do not delete anything yourself

Report findings; let the reviewer (or a follow-up task) do the deletion,
especially for anything below "certain" confidence.

Installing it elsewhere

The frontmatter/body split above is Claude Code's convention. Here's how to carry the same instructions into other tools:

Claude Code
.claude/skills/dead-code-finder/SKILL.md

Save the file below verbatim (frontmatter included) at that path, project-local or in ~/.claude/skills/ for a user-level skill. Claude Code loads the name/description pair to decide when to pull it in, or you invoke it directly as /dead-code-finder.

Cursor
.cursor/rules/dead-code-finder.mdc

Convert the YAML frontmatter to Cursor's rule format (description, globs, alwaysApply: false) and keep the markdown body as the rule content. Cursor surfaces it by description match, same idea as Claude Code's auto-load.

Codex CLI / Copilot
AGENTS.md

Codex CLI (and increasingly other agentic CLIs) read AGENTS.md at the repo root as always-on instructions. Paste the markdown body under a heading like ## {title}; for GitHub Copilot's coding agent, the equivalent file is .github/copilot-instructions.md.

Windsurf
.windsurfrules

Append the markdown body to .windsurfrules at the repo root. Windsurf treats the whole file as always-on context, so keep only the instructions you want applied on every request.

Where this goes wrong
  • Grepping only for import statements and missing string-based or reflective references.
  • Flagging framework lifecycle methods (e.g. a hook a framework calls by convention) as dead because nothing in-repo "calls" them explicitly.
  • Reporting low-confidence guesses with the same certainty as verified-dead code -- confidence level is part of the finding.