Research notes

Why Deadpath is built this way.

Use cases and pain points behind every feature, collected from the issue trackers and post-mortems of existing dead-code tools (knip, ts-prune, Vulture, deptry, unimport, unused-code linters in Go, Rust, Java, C#) and from agent-driven refactor failures. Each row maps a real complaint to the mechanism that answers it.

Who needs this

Developer in an editor agent

Asks Claude, Cursor or Codex "is this still used?" and needs a deterministic answer with evidence, not a guess from grep.

Agent doing a refactor

Keeps adding compatibility shims around code nobody calls. Needs a pre-flight dead-code audit and a verify-before-delete checklist.

Tech lead adopting a tool

Legacy repository with hundreds of findings. Needs a ratchet that blocks only new dead code, not a big-bang cleanup.

Platform / enterprise team

Polyglot monorepo, many frameworks, security review. Needs SARIF, no network, no vendor SDK, secrets redacted, an audit trail of decisions, and predictable model spend.

Pain points and the mechanism that answers them

Pain pointDeadpath mechanism
False positives from dynamic loading. getattr, importlib, reflection, DI containers, plugin registries and string-named modules. Engineers stop trusting the tool and disable it. Confidence signals — *_named_in_string_literal, *_named_in_config, repo_uses_dynamic_import, module_getattr_lazy_export, name_token_seen_elsewhere — lower the score so the finding drops from block to warn/note. Name-precision languages are capped at warn outright.
Framework code looks dead. FastAPI routes, Django models and admin, Celery tasks, pytest fixtures, Spring beans, Rails models, Laravel controllers, Flutter widgets, SwiftUI views are invoked by the framework and never imported. A registry of 45 frameworks: entry-file roles, registration decorators/annotations, and framework base classes, detected from imports and manifests. A decorated route gets framework_registration_decorator −0.60.
Misconfigured entry points make used code look unused (knip's most common issue class). Entry points are inferred from package.json main/exports/bin, pyproject.toml scripts, __main__ guards, Go package main, Rust main.rs/lib.rs/bin/, C translation units, Ruby root scripts, and framework conventions. Explicit config is optional.
Auto-delete is dangerous. AST-based removal breaks contracts; agents confidently introduce bugs from a tool's false positive. Design law: never delete. deadpath.plan and deadpath.workflow return ordered steps and require validation (compiler, type checker, tests) before a human-approved patch.
Legacy debt blocks adoption. Teams need a CI ratchet, not a red build on day one. Memory tracks first/last seen. deadpath scan --only-new exits 1 only for new block findings.
Enterprise wants code-scanning integration and an audit trail. --format sarif with confidence and signals in properties; decisions (keep / false_positive / resolved) with notes and timestamps in .deadpath/memory.json.
Agents spend most tokens reading, not writing. Each session re-reads files, re-derives the same graph, and re-triages the same findings. Compact MCP packets (measured −58% on a repeat visit); content-hash parse cache in every language; workflows that name exact files and grep targets; triage verdicts cached by evidence digest so the model is asked once.
"AI-powered" tools spend model tokens on things a graph already knows, and hallucinate on things it does not. The model never sees block (certain) or note (too weak) findings. It sees warn findings only, once, batched, as evidence packets without file bodies. Its job is ranking and second opinion, never detection. See Workflow.
Hidden live paths look unused. Cron jobs, Dockerfile CMD, Lambda handler strings, Makefile targets, feature flags, platform-gated files, generated code, applied migrations. Agents that delete these are fast and wrong. The judge / devil's advocate checks 30+ named counter-hypotheses against real artifacts with file:line evidence, plus an identification check. Verdict remove / verify / keep. Never auto-delete.
Dead code is also attack surface. Leftover eval, pickle.loads, verify=False, unused endpoints, secret-like literals sit outside the live path and the on-call dashboard. Security lens reports marker + line number only (values redacted). remove_first findings go to the top of the workflow.
Agent output is a wall of prose the developer cannot scan during a review. Plugins render GitHub-flavoured markdown tables (deadpath.judge / format: "table"): severity, judged confidence, devil's advocate, next check, security, effort.
Polyglot estates, single-language tools. Each service team runs a different scanner with a different output. One Finding shape across 16 languages, with declared graph precision so a Java finding is never dressed up as a Python one.
Tools need network, SDKs, or a model to work at all. Detection is offline and deterministic. The LLM is optional veto-only counsel on remove then verify packets (never file bodies), over plain OpenAI-compatible HTTP, and only if a key is set. Every workflow has an identical offline path.

What Deadpath deliberately does not do (v0)