$npx -y skills add tobihagemann/turbo --skill find-dead-codeFind 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 \"wha
| 1 | # Find Dead Code |
| 2 | |
| 3 | Identify dead code in a codebase. **Core rule: code only used in tests is still dead code.** Only production usage counts. |
| 4 | |
| 5 | ## Step 1: Detect Languages, Scope & Test Boundaries |
| 6 | |
| 7 | Determine the project structure: |
| 8 | |
| 9 | 1. Check for config files: `package.json`, `tsconfig.json`, `pyproject.toml`, `setup.py`, `Package.swift`, `.xcodeproj`, `Cargo.toml`, `go.mod`, `pom.xml`, `build.gradle` |
| 10 | 2. Glob for source files: `**/*.ts`, `**/*.py`, `**/*.swift`, `**/*.go`, `**/*.rs`, `**/*.java` |
| 11 | 3. Identify source roots — where production code lives (e.g., `src/`, `lib/`, `Sources/`) |
| 12 | 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. |
| 13 | |
| 14 | If the user specified a scope, restrict analysis to that scope. |
| 15 | |
| 16 | ### Test File Patterns |
| 17 | |
| 18 | Establish which files are test files. Code referenced ONLY from these locations is dead. |
| 19 | |
| 20 | | Language | Test file patterns | |
| 21 | |----------|-------------------| |
| 22 | | TS/JS | `*.test.{ts,tsx,js,jsx}`, `*.spec.{ts,tsx,js,jsx}`, `__tests__/**`, `__mocks__/**`, `*.stories.{ts,tsx,js,jsx}` | |
| 23 | | Python | `test_*.py`, `*_test.py`, `tests/**`, `test/**`, `conftest.py` | |
| 24 | | Swift | `*Tests.swift`, `*Test.swift`, `Tests/**`, `*UITests.swift`, `XCTestCase` subclasses | |
| 25 | | Go | `*_test.go`, `testdata/**` | |
| 26 | | Rust | `tests/**`, `benches/**`, `#[cfg(test)]` modules (inline test modules within source files) | |
| 27 | | Java/Kotlin | `src/test/**`, `*Test.java`, `*Tests.java`, `*Spec.java`, `*Test.kt` | |
| 28 | | General | `fixtures/**`, `__fixtures__/**`, `mocks/**`, `testutils/**`, `testhelpers/**`, `spec/**` | |
| 29 | |
| 30 | Also exclude: test runner configs (`jest.config.*`, `vitest.config.*`, `pytest.ini`), storybook files, benchmark files. |
| 31 | |
| 32 | ## Step 2: Quick Wins — CLI Tools (Optional) |
| 33 | |
| 34 | If a CLI tool is installed, run it as a fast first pass for **zero-reference** dead code. |
| 35 | |
| 36 | | Language | Tool | Check | Run | |
| 37 | |----------|------|-------|-----| |
| 38 | | TS/JS | `knip` | `npx knip --version` | `npx knip --no-exit-code` | |
| 39 | | Python | `vulture` | `vulture --version` | `vulture <src_dirs> --min-confidence 80` | |
| 40 | | Swift | `periphery` | `which periphery` | `periphery scan --skip-build` | |
| 41 | | Go | `deadcode` | `which deadcode` | `deadcode ./...` | |
| 42 | | Rust | compiler warnings | — | `cargo build 2>&1 \| grep "dead_code"` | |
| 43 | |
| 44 | **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. |
| 45 | |
| 46 | If no CLI tool is installed, skip to Step 3. Do not ask the user to install anything. |
| 47 | |
| 48 | ## Step 3: Test-Only Analysis — Parallel Subagents (Core) |
| 49 | |
| 50 | This is the primary analysis. Use the Agent tool to launch one subagent per top-level source directory from Step 1 in a single assistant message so they run concurrently. Run them in the foreground so all their results return in this turn. Each Agent call uses `model: "opus"`. Expect one Agent tool call per directory, capped at 8 by 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` the subagent discards afterward. |
| 51 | |
| 52 | ### Subagent Strategy |
| 53 | |
| 54 | Each subagent receives: |
| 55 | |
| 56 | 1. **Its assigned directory** to scan for exported symbols |
| 57 | 2. **The test file patterns** from Step 1 |
| 58 | 3. **The full project root path** so it can grep across the entire codebase |
| 59 | |
| 60 | ### Subagent Task |
| 61 | |
| 62 | Each subagent performs these steps on its assigned directory: |
| 63 | |
| 64 | **a) Find exported/public symbols:** |
| 65 | |
| 66 | | Language | Exported symbol patterns | |
| 67 | |----------|--------------------------| |
| 68 | | TS/JS | `export function`, `export const`, `export let`, `export var`, `export class`, `export interface`, `export type`, `export enum`, `export default`, `module.exports` | |
| 69 | | Python | Top-level `def` and `class` in non-`_`-prefixed modules, module-level constants (`FOO = ...`), symbols in `__all__`, public functions (no `_` prefix) | |
| 70 | | Swift | `public func`, `public var`, `public let`, `public class`, `public struct`, `public enum`, `public protocol`, `open class`, `open func`, `open var` | |
| 71 | | Go | Capitalized identifiers: `func FooBar`, `type FooBar struct`, `var FooBar`, `const FooBar` (Go uses capitalization for public visibility) | |
| 72 | | Rust | `pub fn`, `pub struct`, `pub enum`, `pub trait`, `pub const`, `pub static`, `pub type`, `pub mod` | |
| 73 | | Java/Kotlin | `public class`, `public static`, `public void`, `public` fields, `val`/`var` prop |