| name | prune |
| description | Use when asked to clean up, remove unused, or delete dead code. Finds unreferenced symbols, dedupes constants, and removes drift. Requires user approval before editing. Do not use for comments. |
| license | MIT |
| metadata | {"version":"1.0.0"} |
Prune
Rule zero: treat every declaration as live until you have proven it safe
to remove.
Find candidates in four categories. Verify each candidate across the whole
repository, code and tests alike. Report all findings for approval before
editing.
Categories
- Confirmed dead: symbols, constants, tokens, or barrel re-exports with
zero references.
- Dedupe: the same constant, string, or type literal declared verbatim in
two or more places.
- Drift: a magic literal that duplicates an existing named constant.
- Arbitrary limits: caps, thresholds, or timeouts guarding against
situations users cannot reach. Quantify the real limit before recommending
removal.
Workflow checklist
Copy this checklist and track your progress:
Prune Progress:
- [ ] 1. Build the candidate list (tooling + search)
- [ ] 2. Verify every candidate repo-wide
- [ ] 3. Classify: safe to remove / arbitrary but intentional
- [ ] 4. Present the findings table
- [ ] 5. Ask which findings to apply
- [ ] 6. Apply approved changes and update tests
- [ ] 7. Run typecheck, lint, and tests
1. Build the candidate list
Use existing tooling. Do not install new tools without asking the user.
For JavaScript and TypeScript projects:
- If the project already uses knip, ts-prune, or depcheck, use
their output as the candidate list. For example:
npx knip.
- Otherwise, check whether TypeScript flags unused locals
(
noUnusedLocals, noUnusedParameters) or ESLint's no-unused-vars are
enabled. Use their warnings as candidates.
Tool output is a candidate list only. Every candidate must still pass the
verification step.
2. Verify every candidate
- Search each category across the whole repository: code, tests, and config.
- Verify every candidate's usage before judging it. One missed reference
makes the verdict wrong.
- For symbols re-exported by barrel files: a symbol is not dead while its
barrel has importers. Search for the symbol name, then follow each
importing file through the barrel chain. A naive search that does not
resolve re-exports will report a false "live" status.
- Classify each candidate as safe to remove or arbitrary but
intentional.
3. Present findings
Use exactly these columns:
| Item | Location | Notes |
|------|----------|-------|
| `<symbol>` | `path:line` | Zero references repo-wide (verified). Confirmed dead. |
| `<constant>` | `pathA:line`, `pathB:line` | Identical declaration in 2 files. Dedupe into one shared constant. |
| literal `<value>` | `path:line` | Duplicates `<NAMED_CONSTANT>`; reference the constant to avoid drift. |
| `<CAP>` | `path:line` | Threshold unreachable in practice (state the real limit). Safe to remove. |
- Item: exact declaration in backticks, or a short phrase for inline
literals.
- Location:
path:line. Include every dedupe and drift location.
- Notes: one sentence. Identify the item, confirm usage, and give the
verdict.
Output the table. Stop. Do not edit until the user replies with approved row numbers.
4. Apply and verify
- Apply approved changes and update affected tests.
- Run typecheck, lint, and tests. Fix anything the changes broke.
Treat as live
These are never dead without extra proof:
- Entry points:
package.json main and bin fields, framework pages and
routes, serverless handlers.
- Public API packages: exports consumed by other packages or users.
- Dynamic access:
eval, new Function, reflection, dynamic import(),
glob require, and property access by string.
- Framework entry files and convention-based registrations.
- Code used only by tests, if removing it breaks the tests.
Edge cases
- Monorepos: verify references across every package, not only the package
that declares the symbol. Workspace hoisting can move consumers.
- Generated code: skip generated output (lockfiles, compiled output,
vendored dependencies) when searching, but flag generated files that
re-export dead code if the generator is yours to change.
- Environment-conditional code: a branch gated by
process.env or a build
flag is not dead because your current environment never runs it. Report it
as arbitrary but intentional.
- Commented-out code: that is dead code, not a comment. Report it as a
separate finding and let the user decide.
Rules
When in doubt, it stays live. Remove only what you have proven dead.
- A symbol used only in its own file may be unexported, not deleted.
Cross-file consumers require it to stay exported.
- Check tests before removing exports. Keep exports that cover non-trivial
logic, or flag the trade-off.
- Keep intentional tuning values: animation timings, debounce intervals,
sizes, minimums. Report them as arbitrary but intentional.
- Keep validation and guards that prevent crashes on corrupt or missing data.
- Treat uncertain dynamic access, reflection, constructed imports, public
APIs, and framework entry points as live.
See examples/findings-report.md for a worked report.