From vibesubin
Diagnoses repo rot prioritizing dead code (HIGH/MEDIUM/LOW confidence), god files, hotspots, hardcoded paths, stale TODOs, lopsided imports. Language-agnostic pure diagnosis.
npx claudepluginhub subinium/vibesubin --plugin vibesubinThis skill is limited to using the following tools:
Repos don't break in a day. They rot over months as dead code accumulates, god files grow, hardcoded paths get committed, and six-month-old `TODO`s turn into forever-`TODO`s. This skill surfaces what's rotting — it never edits code.
Identifies riskiest codebase files using git churn analysis, complexity metrics, coupling, and lenskit risk scores for technical debt hotspots.
Detects duplicated code, dead imports, security vulnerabilities, and complexity hotspots using parallel subagents. Run at session end, before commits, merges, or code reviews.
Detects dead code, unused exports, orphaned files, circular dependencies, unused packages, stale TODOs, and hygiene issues across 11 categories. Use scan, safe, aggressive modes on full codebase or paths.
Share bugs, ideas, or general feedback.
Repos don't break in a day. They rot over months as dead code accumulates, god files grow, hardcoded paths get committed, and six-month-old TODOs turn into forever-TODOs. This skill surfaces what's rotting — it never edits code.
What this skill is: a diagnosis, sorted by confidence and leverage, with a pointer to the skill that should handle each finding.
What this skill is not: an executor. It never deletes, refactors, rewrites, or runs tests. When the operator approves a finding, it hands off to another skill (refactor-verify for deletions and restructures, manage-config-env for config fixes, audit-security for CVE dependency rot). This boundary is load-bearing — the moment this skill starts editing, the evidence chain breaks.
Dead code is the core finding this skill produces. Non-obvious dead code is the highest-leverage cleanup target: it's the thing the operator can delete with calibrated confidence, reducing surface area without touching live behavior. Everything else in this skill is secondary.
Language-specific tools first (they're accurate), grep second (a lower bound).
# Python
pip install vulture && vulture src/
pyflakes src/
# JavaScript / TypeScript
npx ts-prune # TS unused exports
npx knip # TS/JS unreferenced files + exports + deps
npx unimported # unreferenced JS files
# Rust
cargo +nightly udeps # unused dependencies
cargo clippy -- -W dead_code # unreachable code
# Go
deadcode ./... # unreachable functions
go vet ./... # various unused warnings
# Universal fallback — LSP find-references
# (run in the operator's editor, or via the LSP CLI — accurate for cross-file symbols)
# Grep fallback — coarsest, lower bound only
git grep -w 'symbol_name' | wc -l
Static dead-code detection produces false positives. Dynamic imports, reflection, test-only usage, CLI entrypoints, and cross-language boundaries can all make a function look dead when it isn't. Every dead-code finding gets a confidence level so the operator doesn't delete something load-bearing.
| Confidence | What it means | Safe to delete? |
|---|---|---|
| HIGH | No textual reference anywhere in the repo (git grep -w, ts-prune, vulture, deadcode, etc.), not in tests, not in docs, not in entrypoints, not in config files, and the symbol is not exported for external use | Yes — hand off to refactor-verify for the actual delete + verification |
| MEDIUM | No reference in the main source tree, but appears in test files, or the language uses dynamic dispatch (Python, Ruby, JS without strict types), or the symbol name could be built dynamically | Ask the operator before deleting — the test may be load-bearing, or a dynamic caller may exist |
| LOW | Symbol is exported from a package, appears in generated code, is referenced via reflection / codegen / dependency injection (Go, Java annotations, .NET DI), or the language's find-references is unreliable | Do not delete without explicit human review and a second signal |
Never emit a dead-code finding without a confidence tag. Never emit "DELETE THIS" in any form.
## Dead code (diagnosis only — verify + delete via refactor-verify)
### HIGH confidence (safe to delete after verification)
- `utils/legacy_helpers.py::format_v1` — no grep hits, no test refs, not exported
- `src/api/users_v1.py` — entire file unreferenced since `v2` rename
- `pkg/cli/deprecated_commands/` — directory orphaned from the dependency graph
### MEDIUM confidence (ask before deleting)
- `src/api/users.py::get_user_v2` — referenced only in `tests/api/test_users_v2.py` (is the test obsolete too?)
- `lib/utils.js::formatLegacy` — JS, dynamic dispatch possible via `utils[fnName]`
### LOW confidence (do not delete without human review)
- `pkg/exported/Config.Validate` — exported symbol, downstream consumers unknown
- `src/plugins/payment_stripe.py::process` — loaded via plugin registry at runtime
- `internal/handlers/handler_admin.go::register` — registered via reflection-based router
### Deletion candidates summary
- HIGH: <N> items
- MEDIUM: <N> items (requires operator confirmation)
- LOW: <N> items (requires human review)
Hand off to `refactor-verify` with the HIGH list for safe deletion. Each item becomes a delete-dead node in its verification tree.
Everything below is additional rot worth knowing about, but the primary deliverable is the dead-code list.
These are candidates for splitting. Report them with the metric that triggered the flag. Hand off to refactor-verify for the safe split when the operator approves.
A file that changes often and is complicated is where bugs live. Either dimension alone is not enough:
How to compute (language-agnostic):
# Churn per file — commits touching it, last 6 months
git log --since='6 months ago' --name-only --pretty=format: \
| grep -v '^$' | sort | uniq -c | sort -rn
# Complexity per file — preferred: lizard (Python) or scc (Go)
lizard . --CCN 10 --length 50
scc . --no-cocomo
Multiply churn rank × complexity rank. Flag anything in the top 10 as a hotspot.
Fallback when lizard and scc aren't installed: use LOC as a weak proxy for complexity. Flag files in the intersection of top-20-churn and top-20-LOC. Tell the operator the fallback is in use and offer to install lizard (pip install lizard) or scc (brew install scc) for a sharper signal.
This is the "Code as a Crime Scene" methodology (Adam Tornhill) — churn × complexity identifies the files that carry the most risk. Nicolas Carlo's understandlegacycode.com has the best free write-up.
Grep patterns that almost always indicate a portability bug:
C:\\ / c:\\ / C:/ — Windows absolute path/Users/ / /home/ — Unix absolute home path~/ in string literals (not shell commands)\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b)\\ as a path separator in string literalsHand off to project-conventions — it owns the fix pattern (constant vs env var decision, platform-portable alternatives).
Any TODO / FIXME / XXX / HACK comment older than six months (via git blame). Either the author never came back, or the operator forgot the context. Both cases need a decision: fix it, delete it, or turn it into an issue.
Compute with a language-specific import parser (madge for JS/TS, pydeps for Python) or approximate with grep -rn "import <module>" counts.
pip-audit, npm audit, cargo audit, govulncheck)refactor-verify's job to fix)Tests don't show up in standard dead-code scans because they're usually not imported by production code — they're invoked by a runner. That makes them a blind spot for rot. Things to flag:
tests/fixtures/ / __fixtures__/ / testdata/ that no test currently references. Apply the same grep check used for dead code.__snapshots__/, .snap, .png golden files) orphaned from any test case..skip, xit, @pytest.mark.skip, #[ignore], t.Skip(). Find via git blame on the skip directive.time.sleep(5), await new Promise(r => setTimeout(r, 5000)) inside test bodies. Usually a flaky-test band-aid that should be replaced with a proper wait condition.Test rot is still just rot — diagnosis only. Dead-test deletions go to refactor-verify with the same HIGH/MEDIUM/LOW confidence framing (a test importing a symbol via string name is MEDIUM, same as prod code).
# Repo rot report — <date>
## Stats
- Files: <N>
- Total LOC: <N>
- Dead-code candidates: <N HIGH> / <N MEDIUM> / <N LOW>
- God files (>500 LOC): <N>
- Hotspots (churn × complexity): <N>
## Dead code
<HIGH / MEDIUM / LOW sections as shown above>
## God files / functions
- `src/api/user.py` — 1203 LOC, 24 top-level functions
- `src/auth/session.ts::handleLogin` — 87-line function body
- ...
## Hotspots (churn × complexity, top 10)
| # | File | LOC | CCN avg | Commits (6mo) | Notes |
|---|------|-----|---------|---------------|-------|
| 1 | src/auth/session.ts | 870 | 18 | 47 | also flagged as god file |
| 2 | ... | | | | |
## Hardcoded paths and platform assumptions
- `src/config.ts:42` — `/Users/alice/Projects/foo`
- `scripts/deploy.sh:15` — literal IP `192.168.1.10`
- ...
## Stale TODOs (>6 months)
- `src/db.py:87` — `TODO: handle connection timeout` (authored 2024-11, 17 months old)
- ...
## Dependency rot
- `requirements.txt` — 3 unpinned, 1 with CVE
- `package.json` — `left-pad` last updated 2018
- ...
## Hand-off summary
- **Dead-code HIGH** (<N> items) → `refactor-verify` for safe deletion
- **God files** (<N> items) → `refactor-verify` for safe splits
- **Hotspots** (<N> items) → `refactor-verify` when the operator picks one
- **Hardcoded paths** (<N> items) → `project-conventions`
- **Dependency CVEs** (<N> items) → `audit-security`
- **Stale TODOs becoming real work** → `write-for-ai` to file issues
## What this report did NOT do
Pure diagnosis. No files edited, no commits made. Approve any item and it gets handed to the specialist that owns the fix.
The bias is high-leverage + low-risk first. Dead code HIGH is usually the cleanest starting point — every deletion shrinks surface area with zero behavioral risk. Hotspot refactors are higher leverage but higher risk.
refactor-verify's job.When the task context contains the tone=harsh marker (usually set by the /vibesubin harsh umbrella invocation, but can also be set by direct requests like "don't sugarcoat" / "brutal review" / "매운 맛" / "厳しめ"), switch output rules:
refactor-verify", "HIGH — safe", "MEDIUM — confirm once, then delete".Harsh mode does not invent findings, exaggerate confidence, or become rude. Every harsh statement must still cite the same metric or signal the balanced version would cite. The change is framing, not substance.
refactor-verify with the list, each item becoming a delete-dead noderefactor-verifyrefactor-verify for the safe split (operator picks one target)project-conventions for the fix patternaudit-security for severity and incident responsewrite-for-ai to file the issuerefactor-verify for safe deletion, same HIGH/MEDIUM/LOW framingmanage-assets for the bloat audit (separate from code-rot — this skill only mentions the finding in passing)The full methodology is inlined in this SKILL.md rather than split into references. Tools worth knowing (install-on-demand):
scc — fast LOC + complexity, works on any languagelizard — cyclomatic complexity per function, most mainstream languagestokei — fast LOC (no complexity, faster than scc on huge repos)madge — JS/TS import graph visualizerradon — Python cyclomatic complexityvulture / pyflakes — Python dead-code detectionts-prune / knip / unimported — TypeScript / JavaScript dead-code detectiondeadcode — Go dead-code detectioncargo +nightly udeps — Rust unused-dependency detectiongit log --numstat — the universal churn primitive, always availableScripts and references in this skill directory are intentionally minimal — the primary deliverable is the diagnostic report, and the analysis lives in the single SKILL.md so nothing drifts out of sync.