Quality dead code analyzer
Analyze a codebase for dead code, duplicates, and circular dependencies using knip, jscpd, and madge, then validate findings to filter false positives. Use when user says "quality-dead-code-analyzer", "analyze code", "find dead code", "code cleanup", "find duplicates", "unused exports", or "static analysis".From its SKILL.md
npx -y skills add zcaceres/skills --skill quality-dead-code-analyzerAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 7 stars7 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
6.6 KB, as published. Nobody here has run it
Dead Code Analyzer
Runs three static analysis tools sequentially, then validates findings to filter out false positives.
Tools used:
- knip - Dead code, unused exports, unused dependencies
- jscpd - Duplicate code blocks
- madge - Circular dependencies
The tools are fetched on demand with a package runner — nothing is installed into the project or the skill.
Important: Run Tools Directly
DO NOT use Task agents for this skill. Run all tools directly in the main context using Bash. This prevents infinite retry loops and token waste.
Workflow
Step 1: Pick a Package Runner
The tools run via npx (npm). If npx is unavailable, fall back to bunx (Bun) — the arguments are identical. Set a RUN variable once and reuse it:
RUN="npx --yes"; command -v npx >/dev/null 2>&1 || RUN="bunx"
echo "Using: $RUN"
Major versions are pinned (knip@5, jscpd@4, madge@8) so results stay stable.
Step 2: Gather Project Context
Read the target project's package.json to understand it:
cat package.json
Note these details for validation:
- Framework:
next,react,vue,angularin dependencies - Runtime: Look for
bun.lockbor"bun"in scripts - Scripts that use tools indirectly:
"lint": "next lint"→ eslint is used"test": "bun test --preload ./preload.ts"→ preload.ts is used
- Config files:
ls *.config.* tsconfig.json 2>/dev/null
Step 3: Run Analysis Tools (Sequentially)
Run each tool ONE TIME with the exact commands below. If a tool fails, report the error and move on.
Tool 1: knip (Dead Code)
$RUN knip@5 --reporter json --no-progress 2>&1 | head -500
Flags explained:
--reporter json- Machine-readable output--no-progress- Disable dynamic terminal updates (required for non-TTY)
Parse the JSON output for:
filesarray - Unused filesissues[].dependencies- Unused dependenciesissues[].devDependencies- Unused devDependenciesissues[].exports- Unused exportsissues[].unlisted- Unlisted dependencies (false positives for framework-provided packages)
Tool 2: madge (Circular Dependencies)
$RUN madge@8 --circular --json --extensions ts,tsx --ts-config tsconfig.json --no-spinner src 2>&1
Flags explained:
--circular- Find circular dependencies--json- Machine-readable output--extensions ts,tsx- Only analyze TypeScript files--ts-config tsconfig.json- Use project's tsconfig for path resolution--no-spinner- Disable progress spinnersrc- Analyze the src directory
Output: Returns [] if no circular deps, or array of dependency chains.
Tool 3: jscpd (Duplicate Code)
$RUN jscpd@4 src --min-lines 10 --min-tokens 100 --reporters json --silent --gitignore --max-size 500kb -o /tmp/jscpd-report 2>&1
Then read the report:
cat /tmp/jscpd-report/jscpd-report.json | head -200
Flags explained:
--min-lines 10- Minimum 10 lines to count as duplicate (default 5 is too noisy)--min-tokens 100- Minimum 100 tokens (default 50 is too noisy)--reporters json- JSON output--silent- No progress output--gitignore- Respect .gitignore--max-size 500kb- Handle larger files (default 100kb skips many files)-o /tmp/jscpd-report- Write to temp dir, not project
Parse the report for:
statistics.total.clones- Number of duplicate blocksstatistics.total.duplicatedLines- Total duplicated linesduplicatesarray - Specific duplicate pairs with file paths and line ranges
Step 4: Validate Findings
After running all tools, validate each finding using Grep to filter false positives.
For Unused Dependencies:
# Check if package is imported anywhere
rg "from ['\"]package-name" src/
# Check if used in scripts
grep "package-name" package.json
Classify as:
- HIGH confidence: 0 imports in src/ AND not in scripts
- FALSE POSITIVE: Used in scripts (e.g., eslint via "next lint")
- FALSE POSITIVE: Framework-provided (e.g., "server-only" in Next.js)
For Unused Files:
# Check if file is imported anywhere
rg "from.*filename" src/
# Check if referenced in configs
grep -r "filename" *.config.* tsconfig.json package.json 2>/dev/null
Classify as:
- HIGH confidence: 0 imports AND not in config AND not in scripts
- FALSE POSITIVE: Used by scripts (e.g., preload.ts for bun test)
Step 5: Present Validated Results
## Code Cleanup Analysis (Validated)
### High Confidence - Safe to Remove
| Item | Type | Verification |
|------|------|--------------|
| react-icons | dependency | 0 imports in src/, not in scripts |
| src/components/OldComponent.tsx | file | 0 imports found |
### Circular Dependencies
[List any chains found by madge]
### Duplicate Code
[List significant duplicates from jscpd, skip test files and docs]
### Filtered Out (Not Issues)
- `eslint`: Used by `next lint` script
- `server-only`: Provided by Next.js
- `preload.ts`: Used by `bun test --preload` script
Step 6: Cleanup (If Requested)
If user wants to proceed:
- Use
AskUserQuestionto confirm which items to remove - Edit package.json to remove dependencies
- Use
trashcommand to delete unused files (notrm) - Run
bun installto update lockfile - Run
bun run typecheckto verify no breakage
Common False Positives
Next.js Projects
eslint,eslint-config-next→ used bynext lintscriptserver-only→ provided by Next.js, shows as "unlisted" but is validpostcss,autoprefixer→ used by Next.js CSS processing- Files in
app/with special names (layout, page, loading, error) → framework conventions
Bun Projects
preload.ts→ used bybun test --preload- Many
@types/*packages → Bun provides built-in types
Testing
@faker-js/faker,@testing-library/*→ only in test files is OK- Test file duplication → often intentional for test clarity
shadcn/ui Projects
- Unused
@radix-ui/*packages → installed by CLI but component not yet used - UI component files → installed but not yet used (suggest removal)
Documentation
CLAUDE.md<->GEMINI.mdduplication → intentional- README duplication in monorepos → intentional