Skip to content
Development
Skill

/find-dead-code

Find dead code using parallel subagent analysis and optional CLI tools, treating code only referenced from tests as dead. Use when the user asks to \"find dead code\", \"find unused code\", \"find unused exports\", \"find unreferenced functions\", \"clean up dead code\", or

From plugin
turbo
40279 skills
Install
$ npx -y skills add tobihagemann/turbo --skill find-dead-code --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/find-dead-code

Context preview

The summary Claude sees to decide when to auto-load this skill.

Find dead code using parallel subagent analysis and optional CLI tools, treating code only referenced from tests as dead. Use when the user asks to \"find dead code\", \"find unused code\", \"find unused exports\", \"find unreferenced functions\", \"clean up dead code\", or

SKILL.md

find-dead-code.SKILL.md
name: find-dead-code
description: "Find dead code using parallel subagent analysis and optional CLI tools, treating code only referenced from tests as dead. Use when the user asks to \"find dead code\", \"find unused code\", \"find unused exports\", \"find unreferenced functions\", \"clean up dead code\", or \"what code is unused\". Analysis-only — does not modify or delete code."

Find Dead Code

Identify dead code in a codebase. **Core rule: code only used in tests is still dead code.** Only production usage counts.

In an incomplete or abandoned implementation, a declared-but-unused symbol may be intended-but-not-yet-used. When git history shows it was added as a deliberate part of an unfinished stack, recommend **investigate** rather than **delete**.

Step 1: Detect Languages, Scope & Test Boundaries

Determine the project structure:

1. Check for config files: `package.json`, `tsconfig.json`, `pyproject.toml`, `setup.py`, `Package.swift`, `.xcodeproj`, `Cargo.toml`, `go.mod`, `pom.xml`, `build.gradle` 2. Glob for source files: `**/*.ts`, `**/*.py`, `**/*.swift`, `**/*.go`, `**/*.rs`, `**/*.java` 3. Identify source roots — where production code lives (e.g., `src/`, `lib/`, `Sources/`) 4. **Partition the codebase** into analysis units by top-level source directories (e.g., `src/auth/`, `src/api/`, `src/utils/`, `lib/models/`). Each directory becomes one subagent's scope in Step 3.

If the user specified a scope, restrict analysis to that scope.

Test File Patterns

Establish which files are test files. Code referenced ONLY from these locations is dead.

| Language | Test file patterns | |----------|-------------------| | TS/JS | `*.test.{ts,tsx,js,jsx}`, `*.spec.{ts,tsx,js,jsx}`, `__tests__/**`, `__mocks__/**`, `*.stories.{ts,tsx,js,jsx}` | | Python | `test_*.py`, `*_test.py`, `tests/**`, `test/**`, `conftest.py` | | Swift | `*Tests.swift`, `*Test.swift`, `Tests/**`, `*UITests.swift`, `XCTestCase` subclasses | | Go | `*_test.go`, `testdata/**` | | Rust | `tests/**`, `benches/**`, `#[cfg(test)]` modules (inline test modules within source files) | | Java/Kotlin | `src/test/**`, `*Test.java`, `*Tests.java`, `*Spec.java`, `*Test.kt` | | General | `fixtures/**`, `__fixtures__/**`, `mocks/**`, `testutils/**`, `testhelpers/**`, `spec/**` |

Also exclude: test runner configs (`jest.config.*`, `vitest.config.*`, `pytest.ini`), storybook files, benchmark files.

Step 2: Quick Wins — CLI Tools (Optional)

If a CLI tool is installed, run it as a fast first pass for **zero-reference** dead code.

| Language | Tool | Check | Run | |----------|------|-------|-----| | TS/JS | `knip` | `npx knip --version` | `npx knip --no-exit-code` | | Python | `vulture` | `vulture --version` | `vulture <src_dirs> --min-confidence 80` | | Swift | `periphery` | `which periphery` | `periphery scan --skip-build` | | Go | `deadcode` | `which deadcode` | `deadcode ./...` | | Rust | compiler warnings | — | `cargo build 2>&1 \| grep "dead_code"` |

**Important limitation:** CLI tools count test imports as real usage. They **cannot** detect code that is only used in tests. They only find symbols with literally zero references anywhere. Step 3 is required for test-only detection.

If no CLI tool is installed, or the tool errors out without producing a report, skip to Step 3. Do not ask the user to install anything.

Step 3: Test-Only Analysis — Parallel Subagents (Core)

Before dispatching, read the project's test configuration and CI workflow to identify any test tier that resets a shared external resource between tests, such as a database, a fixed port, or a cache. Such tiers have no cross-process interlock, so subagents running them concurrently wipe each other's state and return failures that look like real defects. Name any such tier to every subagent as off-limits.

This is the primary analysis. Emit one Agent tool call per top-level source directory from Step 1, all in one assistant message. Each Agent call uses `model: "opus"` and no `name`. Wait for every agent to report before continuing. Do not begin the next step on a partial set, and do not relaunch an agent that has not yet reported. Cap at 8 per the Rules section. State the count explicitly when emitting the calls. Each subagent's prompt directs it to treat the shared working tree and its git index as read-only — any empirical check runs in an isolated `git worktree` created under `$TMPDIR` and discarded afterward. HEAD stays where it is: read other refs with `git show <ref>:<path>` rather than `git checkout` or `git switch`. Refer to that worktree by absolute path in every command and join chained steps with `&&`, so a failed step cannot leave the rest running in the shared checkout. Run teardown and verification as their own commands. Give that worktree its own dependency install rather than reaching the shared tree's install by any route: removing a worktree deletes through symlinks, and a redirected suite writes into the shared install. When its own install is not possible, the check is left unrun and reported as such. Afterward the subagent verifies that `git worktree list` no longer shows the worktree, that `git status --short` is clean, that HEAD is still on the branch it started on, and that the shared tree's dependency directory still resolves (a destroyed install leaves `git status` clean, since it is gitignored). It also confirms that no process whose command line names the worktree path is still running, since stopping a runner can leave the processes it spawned alive. When it cannot list processes, it reports that check as unrun and names the worktree path. Damage the subagent cannot repair is reported with the exact repair command in place of findings.

Subagent Strategy

Each subagent receives:

1. **Its assigned directory** to scan for exported symbols 2. **The test file patterns** from Step 1 3. **The full project root path** so it can grep across the entire codebase

Subagent Task

Each subagent performs these s

Read more
Ships withturbo

A composable dev process for agentic coding harnesses, packaged as modular skills. Turbo has sibling editions for Claude Code and Codex. The Claude Code edition is production-tested.

Get the whole plugin
Stats
403
Stars
30
Forks
Active
Maintenance
Shell
Language
MIT
License
4h ago
Last commit
6mo ago
Created

Repo: tobihagemann/turbo

Other skills on turbo.

audit
Skill

audit

Project-wide health audit pipeline that fans out to all analysis skills in parallel, evaluates findings, and produces a unified report at .turbo/audit.md. Use…