Greenfield mode. This is a personal project with no external consumers and no backward-compatibility burden. Every change is an opportunity to refine the codebase — code should get smaller and clearer with each edit, not larger.
Step 0: Discover & Run Dead-Code Tools
Before manual review, let tools do the heavy lifting. Execute this sequence:
Detect stack — Read project root for go.mod, package.json, Cargo.toml, pyproject.toml, etc. to identify languages in use.
Search for best tools — For each detected language, web-search:
"best dead code / unused export / unreachable function detection CLI tool for {language} {year}"
Look for tools that do whole-program reachability analysis, not just single-file linting. Examples of what you might find (do NOT hardcode — always search for current best):
- Go →
deadcode, staticcheck
- JS/TS →
knip, ts-prune
- Rust →
cargo-udeps, compiler warnings
- Python →
vulture, ruff
Install & run — Install any missing tools, run them, capture output.
Act on findings — Delete every confirmed-dead item. If a tool reports a false positive (e.g. reflection-based usage), skip it silently — do not suppress the warning.
This step replaces manual grep for unused symbols. Only fall back to grep if no suitable tool exists for the stack.
Rules
Delete over keep — Dead code gets deleted outright. No commenting out, no _unused prefix, no re-export, no deprecation marker. Git remembers everything so you don't have to.
Replace over accommodate — When changing an interface, update all call sites directly. No wrappers / adapters / shims / legacy aliases. Only one version of the code exists.
Inline over abstract — If a function/type/interface is used exactly once, inline it at the call site. Don't pre-abstract for "future reuse." Extract only after three repetitions.
Ripple cleanup — When changing one spot, proactively check: did this make anything redundant (unused imports, orphaned helpers, empty modules)? If so, clean them up in the same change.
Direct over configurable — No feature flags, no toggle parameters, no "strategy pattern" unless there are already two or more variants that need to coexist right now.
Forbidden Patterns
The following patterns are strictly prohibited in this project:
// TODO: remove later / // deprecated — There is no "later." Delete now.
- Suppressing dead code warnings via annotations or config — Delete the dead code instead of silencing the compiler/linter.
- Renaming old functions to
_old_xxx, xxx_v1, xxx_legacy — Delete them.
- Switching between old and new logic via flag/config — Use the new logic, delete the old.
- Empty compatibility re-exports — Update the call sites.
- Commenting out old code "just in case" — Delete it. It's in git history.
- Adding comments/docs/type annotations to code you didn't change — Only touch what you're changing.
Decision Rule
When in doubt about whether to keep something, ask:
Is any code calling it right now?
There is no third option. "Might need it later" does not exist.
1---2name: greenfield3description: Activate code hygiene mode — eliminate dead code and keep the codebase lean with every change4---56Greenfield mode. This is a personal project with no external consumers and no backward-compatibility burden. Every change is an opportunity to refine the codebase — code should get smaller and clearer with each edit, not larger.78## Step 0: Discover & Run Dead-Code Tools910Before manual review, let tools do the heavy lifting. Execute this sequence:11121. **Detect stack** — Read project root for `go.mod`, `package.json`, `Cargo.toml`, `pyproject.toml`, etc. to identify languages in use.13142. **Search for best tools** — For each detected language, web-search:15 > "best dead code / unused export / unreachable function detection CLI tool for {language} {year}"1617 Look for tools that do **whole-program reachability analysis**, not just single-file linting. Examples of what you might find (do NOT hardcode — always search for current best):18 - Go → `deadcode`, `staticcheck`19 - JS/TS → `knip`, `ts-prune`20 - Rust → `cargo-udeps`, compiler warnings21 - Python → `vulture`, `ruff`22233. **Install & run** — Install any missing tools, run them, capture output.24254. **Act on findings** — Delete every confirmed-dead item. If a tool reports a false positive (e.g. reflection-based usage), skip it silently — do not suppress the warning.2627This step replaces manual `grep` for unused symbols. Only fall back to grep if no suitable tool exists for the stack.2829## Rules30311. **Delete over keep** — Dead code gets deleted outright. No commenting out, no `_unused` prefix, no re-export, no deprecation marker. Git remembers everything so you don't have to.32332. **Replace over accommodate** — When changing an interface, update all call sites directly. No wrappers / adapters / shims / legacy aliases. Only one version of the code exists.34353. **Inline over abstract** — If a function/type/interface is used exactly once, inline it at the call site. Don't pre-abstract for "future reuse." Extract only after three repetitions.36374. **Ripple cleanup** — When changing one spot, proactively check: did this make anything redundant (unused imports, orphaned helpers, empty modules)? If so, clean them up in the same change.38395. **Direct over configurable** — No feature flags, no toggle parameters, no "strategy pattern" unless there are already two or more variants that need to coexist right now.4041## Forbidden Patterns4243The following patterns are **strictly prohibited** in this project:4445- `// TODO: remove later` / `// deprecated` — There is no "later." Delete now.46- Suppressing dead code warnings via annotations or config — Delete the dead code instead of silencing the compiler/linter.47- Renaming old functions to `_old_xxx`, `xxx_v1`, `xxx_legacy` — Delete them.48- Switching between old and new logic via flag/config — Use the new logic, delete the old.49- Empty compatibility re-exports — Update the call sites.50- Commenting out old code "just in case" — Delete it. It's in git history.51- Adding comments/docs/type annotations to code you didn't change — Only touch what you're changing.5253## Decision Rule5455When in doubt about whether to keep something, ask:5657> **Is any code calling it right now?**58> - Yes → Keep59> - No → Delete60>61> There is no third option. "Might need it later" does not exist.