Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Thoroughly find dead, unused, and unreachable code in a repository and produce a confidence-ranked report. Use this skill whenever the user asks to find dead code, unused variables, unused functions or classes, unreachable code, orphaned files, unused exports, unused dependencies, stale CI files, orphaned config files, or temp/junk files, or wants to "clean up" or "slim down" a codebase. Also trigger on phrases like "what can I safely delete", "audit this repo", "find code nobody calls", or "our
.claude/skills/adityaarakeri-dead-code-audit/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 23% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 75% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 56% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 114% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 60% | 0% |
Find code that nothing actually uses, without lying about certainty. The output is always a report with confidence tiers, never silent deletion.
Static analysis cannot prove code is dead. It can only prove nothing statically references it. Reflection, dependency injection, string-based imports, plugin registries, ORM magic, and template engines all call code that looks unreferenced. So every finding gets a confidence tier, and deletion only happens if the user asks for it after seeing the report.
Run the sizing script first. It counts files and lines per language, flags vendored and generated directories, and recommends a strategy.
bashpython scripts/size_repo.py /path/to/repo
Strategy thresholds (the script applies these for you):
| Tier | Repo size | Strategy | |------|-----------|----------| | SMALL | under 50k source lines | Full scan: run every relevant tool across the whole repo in one pass, then manually verify each finding | | MEDIUM | 50k to 500k lines | Tool scan: run language tools repo-wide, but only do deep cross-reference verification on the highest-value candidates (largest files, whole modules, exported symbols) | | LARGE | over 500k lines or over 5,000 source files | Chunked scan: see "Large repo protocol" below. Do not attempt a single-pass grep-everything approach, it will blow the time budget and the context window |
Always exclude before scanning, regardless of tier: node_modules, vendor, dist, build, .git, target, venv/.venv, __pycache__, generated code (protobuf _pb2 files, *.generated.*, migration folders unless asked), and test fixtures. The sizing script prints an exclusion list; confirm it looks right before proceeding.
Read the reference file for each language the sizing script found. Each one lists the tools, install commands, invocation, and known false-positive patterns:
references/python.md - vulture, pyflakes, coverage-assisted checksreferences/javascript.md - knip, ts-prune, depcheck, ESLint (covers TS too)references/go-rust-java.md - staticcheck/deadcode, cargo machinery, compiler flagsreferences/configs-ci-hygiene.md - temp/junk files, stale CI, orphaned configs.ALWAYS read this one regardless of language; run python scripts/hygiene_scan.py <repo> alongside the source-level tools, since source tools cannot see this category at all.
references/safe-removal.md - test-only-alive detection, tombstone runtimeverification for Tier 2, the deletion workflow, and prevention (CI ratchets). Read before reporting and always before deleting anything.
If a tool is unavailable and cannot be installed (no network, unsupported), fall back to the manual method in references/manual-analysis.md: build a symbol definition list with grep/AST parsing, then search for references to each symbol.
For each candidate the tools flag, check the dynamic-usage traps before assigning a tier:
"symbol_name", 'symbol_name') -catches reflection, getattr, dynamic imports, config-driven dispatch.
event listeners, pytest fixtures, DI containers, serializers).
package __init__.py or index.ts, listed in __all__, mentioned in docs or README, or the package is published. Public API that is internally unused is "unused internally", not dead.
name.
git log --oneline -3 -- <file>. Code touched in the last30 days deserves extra suspicion of the tools, not of the code.
test/, tests/, spec/, __tests__/, _test., .test., .spec.). Production code kept alive solely by its own tests is dead; label it "test-only" in Tier 1 and remove code and tests together. See references/safe-removal.md. Exception: published-library code may legitimately have only test references internally; that stays Tier 3.
ALWAYS use this exact structure:
# Dead Code Audit: <repo name>
Scanned: <N files, N lines> | Strategy: <SMALL/MEDIUM/LARGE> | Coverage: <full or which modules>
## Tier 1 - Safe to remove (high confidence)
Nothing references these statically OR dynamically. Private symbols, unreferenced
files, unreachable branches after return/raise, unused imports.
<table: location | symbol | why it is dead | evidence>
## Tier 2 - Probably dead (verify with owner)
Statically unreferenced but matches a dynamic-usage risk pattern, or is old code
in a rarely-touched module. For each item, offer the tombstone technique from
`references/safe-removal.md` (a logged marker shipped for 30-90 days) as the way
to settle it with runtime evidence instead of leaving it in limbo.
<table: location | symbol | risk that it is actually used | suggested verification>
## Tier 3 - Unused but intentional (do not remove without discussion)
Public API surface, feature-flagged code, platform-specific branches.
## Unused dependencies
Packages in the manifest that no source file imports.
## Stale CI, configs, and junk files
Temp/backup files, CI files for retired systems or nonexistent branches, and
configs for tools no longer in the dependency set.
## Not scanned
Anything excluded or skipped due to size limits, so the user knows the blind spots.Estimate deletable line counts per tier. Note the standing blind spots when relevant: dead API endpoints need traffic logs and dead database objects need query logs, both outside a source-only audit; name them as follow-ups rather than staying silent.
If the user then asks to delete, follow the workflow in references/safe-removal.md: Tier 1 only, one branch per audit and one commit per module, tests deleted with the code they tested, a post-delete grep per symbol, full test suite and build, and a diff summary. After a cleanup, offer the prevention step from the same file (compiler/linter flags plus a baselined ratchet job) so dead code stops accumulating between audits.
For LARGE repos, work like a search party sweeping a forest grid by grid rather than one person wandering everywhere:
scoping options: whole repo chunked, top N largest modules, or a specific directory they care about. Default to whole-repo chunked if they do not choose.
python scripts/symbol_index.py /path/to/repo --out index.json This is a flat map of defined symbols to files, built with lightweight parsing, cheap enough to run on millions of lines.
relationships mostly stay inside a chunk.
candidate against the global index, not just the chunk. This is what prevents the classic false positive where module A's helper is only called from module B.
If the audit gets interrupted, resume from the last chunk instead of restarting.
scan its largest files only, and mark the rest under "Not scanned". Partial honest coverage beats fake complete coverage.
prioritize finding whole dead files and dead modules (biggest wins), then only descend to function-level analysis in modules the user cares about.
*.log, *.bak, .DS_Store, editor swaps)deleted branches, and CI helper scripts nothing references
Makefile (see references/configs-ci-hygiene.md)
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-17 | pass→pass | 12,663 | 10,318 | -19% | 1 | 1 | 0% | 2,101 | 3,900 | +86% | 0 | 0 | — |
case-01 | fail→fail | 42,092 | 15,073 | -64% | 1 | 1 | 0% | 6,280 | 2,375 | -62% | 0 | 0 | — |
case-02 | fail→fail | 32,540 | 15,037 | -54% | 1 | 1 | 0% | 4,532 | 2,379 | -48% | 0 | 0 | — |
case-03 | fail→fail | 21,062 | 15,721 | -25% | 1 | 1 | 0% | 3,531 | 2,411 | -32% | 0 | 0 | — |
case-04 | fail→pass | 20,296 | 10,442 | -49% | 1 | 1 | 0% | 3,218 | 3,959 | +23% | 0 | 0 | — |
case-05 | fail→pass | 20,015 | 27,266 | +36% | 1 | 1 | 0% | 3,454 | 6,034 | +75% | 0 | 0 | — |
case-06 | fail→pass | 21,957 | 21,190 | -3% | 1 | 1 | 0% | 2,840 | 4,440 | +56% | 0 | 0 | — |
case-07 | fail→pass | 12,414 | 10,652 | -14% | 1 | 1 | 0% | 1,816 | 3,890 | +114% | 0 | 0 | — |
case-16 | fail→pass | 16,120 | 5,468 | -66% | 1 | 1 | 0% | 1,939 | 3,106 | +60% | 0 | 0 | — |
case-08 | fail→pass | 10,841 | 5,167 | -52% | 1 | 1 | 0% | 1,800 | 3,076 | +71% | 0 | 0 | — |
case-09 | pass→pass | 12,814 | 11,506 | -10% | 1 | 1 | 0% | 1,333 | 3,282 | +146% | 0 | 0 | — |
case-10 | fail→pass | 18,328 | 9,786 | -47% | 1 | 1 | 0% | 2,497 | 3,962 | +59% | 0 | 0 | — |
case-11 | fail→pass | 15,943 | 20,167 | +26% | 1 | 1 | 0% | 2,657 | 4,718 | +78% | 0 | 0 | — |
case-12 | pass→pass | 17,846 | 12,732 | -29% | 1 | 1 | 0% | 1,937 | 3,457 | +78% | 0 | 0 | — |
case-13 | pass→pass | 19,522 | 16,814 | -14% | 1 | 1 | 0% | 2,469 | 4,296 | +74% | 0 | 0 | — |
case-14 | pass→pass | 13,415 | 9,656 | -28% | 1 | 1 | 0% | 1,350 | 2,900 | +115% | 0 | 0 | — |
case-15 | fail→pass | 10,335 | 11,150 | +8% | 1 | 1 | 0% | 1,645 | 3,122 | +90% | 0 | 0 | — |
case-18 | pass→pass | 16,823 | 5,206 | -69% | 1 | 1 | 0% | 1,916 | 3,070 | +60% | 0 | 0 | — |
case-19 | pass→pass | 9,981 | 8,621 | -14% | 1 | 1 | 0% | 1,641 | 2,787 | +70% | 0 | 0 | — |
case-20 | fail→fail | 13,903 | 16,770 | +21% | 1 | 1 | 0% | 2,747 | 5,334 | +94% | 0 | 0 | — |
case-21 | pass→pass | 7,702 | 13,241 | +72% | 1 | 1 | 0% | 914 | 3,131 | +243% | 0 | 0 | — |
case-22 | fail→fail | 26,640 | 30,916 | +16% | 1 | 1 | 0% | 6,018 | 7,148 | +19% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 19 counted toward the lift figure. The other 3 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +41 percentage points is the difference between those two pass rates over the 19 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 9/4/2026 | +41% |
Other measured skills in the registry, with their headline benchmark lift.