Remove dead code safely
Finds unused code, flags, endpoints, jobs and dependencies, proves each dead with static and runtime evidence, and removes it or stages a reversible retirement. Use to shrink a codebase.
Dead code costs reading time, build time and false leads when debugging. But "no references found" is not proof of death: code is also reached through reflection, dependency injection, string lookups, routing tables, templates, serialization, plugins, scheduled jobs and callers in other repositories. Some code has no static references to find at all: HTTP endpoints called by other teams or old app versions, flags whose value lives in a flag service, scheduled jobs, config keys and message handlers. Whether they are used is a runtime fact, and "zero calls last week" is weak evidence when a caller runs at month end, at year end, or only on an old mobile release that is still installed. Removing live code is an outage; leaving dead code is only clutter. When in doubt, keep it, or turn it off reversibly first.
Find and remove dead code in . Used outside this repository: . Only if [EVIDENCE_SOURCES] is given: Runtime evidence available:
- Find candidates: unreferenced functions, classes, exports and files; branches that can never run; feature flags that are always on or always off; configuration nobody reads; dependencies nothing imports; and runtime-reachable paths that may be unused: HTTP or RPC endpoints, GraphQL fields, message consumers, scheduled jobs, and tables or columns written but never read. Use the language's tooling where it exists (compiler warnings, unused-export or unused-dependency tools) and text search.
- Prove each candidate dead. Search the whole repository, not only the scope, for the name as a string as well as a symbol. Check dynamic dispatch and reflection, DI containers, routes, templates, config files, build scripts, cron and job definitions, serialization or ORM mappings, and tests.
- Classify:
- dead: no path reaches it, and it is not public API used elsewhere;
- likely dead: no reference found, but it is reachable dynamically or by external callers;
- runtime-only: no static reference, but whether it is used is a runtime fact (endpoints, jobs, flags in a flag service, message handlers, external callers);
- alive: a reference was found.
- Remove only dead items, in small commits grouped by kind, so each can be reverted alone. When a test exists only to exercise dead code, remove the test with it.
- For runtime-only and likely dead items, grade the evidence on three rungs: static (no references, including string lookups); runtime (zero use in the evidence sources over a stated window, and whether that window covers monthly, quarterly and yearly cycles and the oldest supported client); ownership (the owning team or known consumers confirmed it is unused). Confidence is high with all three, medium with two, low with one. If no runtime evidence was given, say what to collect; never treat missing evidence as proof of no use.
- Plan their retirement in stages, one change per stage so each reverts on its own: instrument (a log or metric on every entry to the path, tagged with caller identity) when evidence is missing; announce (deprecation notice,
DeprecationorSunsetheaders, changelog) for externally visible paths; soft-disable behind a kill switch, or return 410 Gone with a log line, keeping the code for a waiting period that covers the longest usage cycle; delete code, tests, config and flag definitions together, then now-unused dependencies in their own change; drop tables or columns only after the code that wrote them is gone and a backup exists. Order the items so that retiring one never breaks another that is still live. - Run the build, type checker, linter and tests after the removal.
- If is
yesorunknown, treat exported or public symbols as likely dead at most, and do not remove them. Code that only runtime evidence can prove unused, such as endpoints, jobs and flags, needs a staged retirement, not a deletion. - Only high-confidence items may be planned for deletion; medium items go to soft-disable; low items need more evidence. Nothing externally reachable is deleted without a soft-disable stage first.
- Name the exact evidence for each staged item: the query or log search, the window and the count. Do not invent numbers; write "missing" when evidence is missing.
- Write the staged retirement as a plan with change boundaries; do not make those changes unless asked.
- Never remove code just because it is old, commented as deprecated, or unused in tests only.
- Do not refactor or reformat code that stays.
- Do only what was asked. If you notice something else worth changing, mention it in one line at the end instead of changing it.
- Keep the change as small as it can be while still being correct.
- Before saying the work is done, run the check that proves it (tests, build, type check or the command the user gave) and report the real result.
- If you could not run a check, say so plainly and say which one.
Removed
A table: Item | Where | Evidence it was dead.
Kept
A table: Item | Where | Why it was kept (likely dead or alive, and the reference found). Or "None".
Staged retirement
A table: Item | Type | Static | Runtime (window, count) | Ownership | Confidence | Action (soft-disable / collect evidence / keep), then numbered stages with timing relative to start (week 0, week 4…), the signal that allows the next stage, and how to roll each stage back. Or "None".
Verification
Build, type-check, lint and test commands with results.
1 required value still a placeholder; the assistant will ask for it.
details
- kind
- Prompt: a task you run by name to get one finished thing back
- domain
- Software engineering
- category
- Refactoring
- level
- Intermediate
- made for
- Software engineer, Backend engineer, Open-source maintainer, Tech lead / staff engineer
- needs
- repo-read, file-write, shell, git
- risk
- runs-commands
- version
- v1.1.0 · incubating
- reviewed
- 2026-10-02
- aliases
- retire-unused-code-paths
- works in
- Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Antigravity, OpenCode, Windsurf, Zed, Continue, AGENTS.md
use in
npx @hermes-hq/hodios install remove-dead-code --target claude-codenpx skills add hermes-hq/hodios-dist --skill remove-dead-code -a claude-codeclaude plugin marketplace add hermes-hq/hodios-distclaude plugin install hodios-software-engineering@hodiosThe plugin brings every entry in this domain at once.
more in refactoring
All of RefactoringExtract a module
Moves one responsibility out of a large file or class into its own module in small, test-verified steps, without changing behaviour or the public API. Use when a file does too many things.
extract-moduleImprove naming in code
Proposes clearer names for variables, functions, types and modules, explains each rename and applies them without changing behaviour. Use when code reads poorly because of its names.
improve-namingPlan a large refactor in safe steps
Turns a large refactor into small, independently shippable steps that keep the build green, each with a rollback, using patterns like expand-contract. Use for refactors too big for one PR.
plan-large-refactorReduce code duplication
Finds duplicated logic, separates true duplication from code that only looks alike, and merges only true duplicates behind one well-named function. Use when one fix keeps landing in many places.
reduce-duplicationSimplify a complex function
Rewrites a hard-to-follow function into a clearer one with identical behaviour, using guard clauses, named steps and simpler conditions, verified by tests. Use on long or deeply nested code.
simplify-functionPlan splitting a large module
Maps the responsibilities and internal dependencies of an oversized file or class and plans its split into cohesive modules, in small steps that keep tests green. Use before breaking up a god class.
split-large-module