Harness-engineering cleanup-dead-code
<!-- Generated by harness generate-slash-commands. Do not edit. -->
git clone https://github.com/Intense-Visions/harness-engineering
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/commands/codex/harness/cleanup-dead-code" ~/.claude/skills/intense-visions-harness-engineering-cleanup-dead-code && rm -rf "$T"
agents/commands/codex/harness/cleanup-dead-code/SKILL.mdCleanup Dead Code
Entropy analysis and safe cleanup. Find unused exports, dead files, and pattern violations — then remove them without breaking anything.
When to Use
- After a major refactoring or feature removal
- When the codebase feels "heavy" — too many files, unclear what is used
- As a periodic hygiene task (monthly or per-quarter)
- When
triggers fireon_entropy_check - After deleting a feature flag and its associated code paths
- When
reports growing entropy in the project health dashboardharness cleanup - NOT during active feature development — dead code cleanup is a separate, focused task
- NOT when tests are failing — fix tests first, then clean up
- NOT under time pressure — dead code removal requires careful verification
Process
Phase 1: Analyze — Run Entropy Report
-
Run
to generate a full entropy report. This analyzes:harness cleanup- Dead exports — functions, classes, and constants that are exported but never imported anywhere
- Unused files — files that are not imported by any other file in the project
- Pattern violations — code that violates established project patterns (e.g., a service file without a corresponding test file)
- Orphaned dependencies — npm packages listed in package.json but never imported
-
Run
for machine-readable output focused specifically on unused code.harness cleanup --type dead-code --json -
Review the report summary. Note the total count and distribution. A few dead exports are normal; dozens suggest accumulated entropy from incomplete refactorings.
Graph-Enhanced Context (when available)
When a knowledge graph exists at
.harness/graph/, use graph queries for faster, more accurate dead code detection:
— perform graph reachability analysis from entry point nodes to identify truly unreachable codequery_graph
— distinguish dynamic imports from genuinely unused code by checking edge typesget_relationships
Graph reachability reduces false positives compared to static analysis alone, since it traces the full transitive import graph including re-exports. Fall back to file-based commands if no graph is available.
Phase 2: Categorize — Safe vs. Needs Review
Safe to auto-fix (remove without further analysis):
- Exports that are not imported anywhere AND not referenced in any config file
- Files that are not imported anywhere AND have no side effects (no top-level execution)
- Dead exports (non-public, zero importers) -- remove
keyword or delete entirely if zero internal callersexport - Commented-out code blocks -- delete commented block (dead by definition, code is in git history)
- Orphaned npm dependencies -- remove from package.json (probably safe; needs install+test verification)
- Unused local variables and imports within a file (linter can catch these)
Needs human review before removal:
- Exports that APPEAR unused but might be consumed dynamically (see "What NOT to Delete" below)
- Files that appear unused but are entry points (CLI scripts, test fixtures, config files)
- Code that is only used in specific build configurations or environments
- Exports from a public package — external consumers may depend on them
Phase 3: Apply Safe Fixes
For each item categorized as safe:
-
Remove the dead code. Delete the export, function, file, or import.
-
Run
to update any documentation references that pointed to the deleted code.harness fix-drift -
Run the full test suite. All tests must pass. If any test fails:
- STOP. The code was not actually dead — something depends on it.
- Undo the deletion immediately.
- Reclassify the item as "needs human review" and investigate the hidden dependency.
-
Run
andharness validate
. Both must pass.harness check-deps -
Commit the cleanup. Group related removals into logical commits (e.g., "remove unused shipping utilities" not "delete dead code").
New fix types:
- Dead exports (non-public): Use
withdetect_entropy
. The tool removes theautoFix: true, fixTypes: ['dead-exports']
keyword. If the function/class has zero internal callers too, delete the entire declaration.export - Commented-out code: Use
withdetect_entropy
. The tool deletes commented-out code blocks. This is cosmetic and only needs lint verification.autoFix: true, fixTypes: ['commented-code'] - Orphaned dependencies: Use
withdetect_entropy
. The tool removes the dep from package.json. Must runautoFix: true, fixTypes: ['orphaned-deps']
after to verify nothing breaks.pnpm install && pnpm test
Phase 3.5: Convergence Loop (Standalone)
When running standalone (not through the orchestrator), apply a single-concern convergence loop:
- Re-run detection. After applying all safe fixes, run
again.harness cleanup --type dead-code - Check if issue count decreased. Compare the new count to the previous count.
- If decreased: loop. New dead code may have been exposed by the fixes (e.g., removing a dead export made a file fully unused). Go back to Phase 2 (Categorize) with the new report.
- If unchanged: stop. No more cascading fixes are possible. Proceed to Phase 4 (Report).
- Maximum iterations: 5. To prevent infinite loops, stop after 5 convergence cycles regardless.
Why convergence matters: Removing dead code can create more dead code. For example:
- Removing a dead export may make all remaining exports in a file dead, making the file itself dead.
- Removing a dead file removes its imports, which may make other files' exports dead.
- Removing an orphaned dep may cause lint warnings that reveal unused imports.
Phase 4: Report Remaining Items
Graph Refresh
If a knowledge graph exists at
.harness/graph/, refresh it after code changes to keep graph queries accurate:
harness scan [path]
Dead code removal changes graph topology — skipping this step means subsequent graph queries (impact analysis, dependency health, test advisor) may return stale results.
For items that need human review, report:
- What it is — file path, export name, what it does
- Why it appears dead — no static imports found
- Why it might not be dead — dynamic import patterns, external consumers, test utilities
- Recommended action — delete with confidence, delete with caution, or keep
What NOT to Delete
These patterns make code APPEAR dead when it is actually in use:
Dynamically imported modules
// This import won't show up in static analysis const module = await import(`./plugins/${pluginName}`);
Files in a
plugins/ directory may appear unused but are loaded dynamically at runtime. Check for import() calls, require() with variables, and glob-based loading patterns.
Test utilities and fixtures
// test-helpers.ts — only imported by test files export function createMockUser() { ... }
Test utility files may appear unused if the analysis excludes test files. Verify that
harness cleanup includes test files in its import graph.
Type-only exports
// Only used as a type, never as a value export interface UserConfig { ... }
Some analysis tools miss type-only imports (
import type { UserConfig }). Verify before deleting any exported interface or type alias.
Package entry points
// index.ts — re-exports for external consumers export { createClient } from './client';
The entry point of a package re-exports things for external consumers. These exports may have zero internal imports but are the public API.
Side-effect files
// polyfills.ts — imported for side effects, not for exports import './polyfills';
Some files are imported for their side effects (polyfills, global registrations, CSS). They have no exports but are not dead.
Environment-specific code
// Only used when FEATURE_FLAG_X is enabled if (process.env.FEATURE_FLAG_X) { const handler = require('./experimental-handler'); }
Code behind feature flags or environment checks may appear dead in the default configuration.
Harness Integration
— Full entropy analysis. Reports dead exports, unused files, pattern violations, and orphaned dependencies.harness cleanup
— Focused analysis on unused code specifically.harness cleanup --type dead-code
— Machine-readable output for automation.harness cleanup --type dead-code --json
— Update documentation after removing dead code. Ensures deleted items are not still referenced in docs.harness fix-drift
— Run after cleanup to verify project structure remains valid.harness validate
— Run after cleanup to verify no dependency violations were introduced.harness check-deps
Success Criteria
reports zero dead exports and zero unused files (or all remaining items are documented as intentional)harness cleanup- All tests pass after every deletion
andharness validate
pass after cleanupharness check-deps- Documentation references to deleted code are updated or removed
- No dynamically-imported, type-only, or side-effect code was accidentally deleted
- Each cleanup commit is atomic and has a descriptive message explaining what was removed and why
Examples
Example: Removing unused utility functions
Entropy report:
DEAD EXPORT: src/utils/string-helpers.ts - capitalizeFirst() — 0 imports found - truncateWithEllipsis() — 0 imports found - slugify() — 3 imports found (ACTIVE, not dead)
Action: Remove
capitalizeFirst and truncateWithEllipsis from the file. Keep slugify. Run tests — all pass. Commit: "remove unused capitalizeFirst and truncateWithEllipsis from string-helpers"
Example: Detecting a false positive
Entropy report:
UNUSED FILE: src/plugins/markdown-renderer.ts - 0 static imports found - File contains: export default class MarkdownRenderer
Investigation: Check for dynamic imports:
// src/plugins/index.ts const renderer = await import(`./${format}-renderer`);
Result: False positive. The file is loaded dynamically based on the
format variable. Mark as intentional and add a comment in the file explaining the dynamic loading pattern.
Example: Orphaned npm dependency
Entropy report:
ORPHANED DEPENDENCY: moment (package.json) - 0 imports of 'moment' found in src/ - Last imported in commit abc123 (removed 3 months ago)
Action: Remove
moment from package.json dependencies. Run npm install to update lockfile. Run tests — all pass. Commit: "remove unused moment dependency"
Rationalizations to Reject
| Rationalization | Reality |
|---|---|
| "This export has zero static imports, so it is definitely dead and safe to remove" | Zero static imports does not mean zero consumers. Dynamic imports, type-only imports, side-effect imports, and package entry points all create false positives. |
| "I removed the dead code and the tests pass, so I do not need to run harness validate and check-deps" | Both harness validate and harness check-deps must pass after every cleanup. Dead code removal can introduce dependency violations. |
| "The convergence loop found new dead code after my fixes, but it is probably just noise from the tool" | Removing dead code creates more dead code. The convergence loop exists to catch these cascades. If the issue count decreased, loop back. |
| "The entropy report has 60 items but I can clean them all up in one pass to be thorough" | When the report is very large (>50 items), pick the highest-confidence dead code first. Attempting everything at once risks compound errors. |
Escalation
- When removing code causes unexpected test failures: The code has a hidden dependency. Undo the deletion, investigate the dependency chain, and document the finding. The code is not dead — it is just hard to trace.
- When the entropy report is very large (>50 items): Do not attempt to clean everything at once. Pick the highest-confidence dead code (files with zero imports, no dynamic patterns) and clean those first. Schedule the rest across multiple sessions.
- When you are unsure if an export is used externally: Check if the code is in a published package. If so, removing an export is a breaking change. Deprecate first, then remove in a major version.
- When dead code is tangled with live code in the same file: Extract the live code first (using harness-refactoring), then delete the remaining dead code. Do not try to surgically remove dead code from a complex file in one step.