When my first dead-export script ran against a 3,300-file TypeScript/React/Python monorepo, it reported 2,266 dead exports. That number was completely wrong.

I had matched import { symbol } across files, which missed 1,722 symbols referenced via namespace imports (ns.helper()), JSX tags (<Widget />), or internal same-file calls, plus 648 framework entrypoint exports (index.ts, page.tsx, route.ts, sst.config.ts) and 270 barrel re-exports (export * from). And when I hashed every function body to find clones, 4,559 2-line getters and trivial wrappers collided across unrelated files.

After filtering out < 25 normalized-token functions (CLS008), framework entrypoints (CLS009), and separating same-file internal callers (CLS006) from zero-caller orphans (CLS005), I ran the corrected analyzer across all 3,300 files (4,544 non-trivial functions) and 153 local Claude Code (~/.claude/projects/**/*.jsonl) and Codex CLI (~/.codex/sessions/**/*.jsonl) transcripts.

clonesieve terminal output

What the 3,300-File + 153-Transcript Audit Found

  • 39.0% Blind Function Additions in Agent Sessions (CLS010 / CLS011): Across 153 Claude Code and Codex sessions (1,813 deduplicated tool calls), 23 of 59 new function definitions (39.0%) and 59 of 132 file write/patch calls (44.7%) were executed before the agent ran a single Grep, Glob, or rg search in that session.
  • 117 Exact Structural Function Clone Groups (CLS001 / CLS002): Using Type-2 token normalization (stripping comments, collapsing strings to "STR", numbers to NUM, and non-keyword identifiers to ID on functions >= 25 tokens), we found 19 multi-file exact clone clusters (>= 3 copies) and 98 pairwise structural clones (2 copies).
    • DataWordmark was copy-pasted 7 times across flash.tsx, june.tsx, minimax.tsx, novel.tsx, sheep.tsx, video.tsx, and stats-shell.tsx.
    • getReviewCommentContext, getUserPrompt, and subscribeSessionEvents were duplicated across index.ts and github.handler.ts.
  • 370 Cross-File Duplicate Helper Names (CLS004): 370 non-trivial function names (>= 25 tokens) were re-implemented in 2 or more separate files (summarize in 3 files, chat in 2 files).
  • 163 Truly Dead Zero-Caller Orphan Exports (CLS005) vs 381 Internal-Only Over-Exports (CLS006): 381 functions were exported with export even though they were only called inside their defining file (stripeWebhook, lakeVpc, isStableSessionSwitch), while 163 exported functions had 0 cross-file references and 0 internal calls (startVisualStabilityProbe, stopVisualStabilityProbe, runVisualStabilityScenario).

The Three False-Positive Traps We Fixed

  1. Whole-Repo Identifier Indexing (1,722 false positives eliminated): Instead of grepping import { foo }, clonesieve builds a per-file identifier token frequency map across the repository and compares external file hits against same-file occurrences.
  2. Entrypoint & Framework Convention Exclusions (648 entrypoints + 270 barrels skipped): CLS009 excludes index.*, main.*, cli.*, Next.js conventions (page.tsx, layout.tsx, route.ts, GET, POST, metadata, generateStaticParams), config files, and export * from barrels.
  3. 25-Token Structural Floor (4,559 trivial getters skipped): CLS008 requires at least 25 normalized tokens before running exact skeleton hashing or 4-gram Jaccard shingle comparison (CLS003).

Running clonesieve on Your Repo

I published clonesieve (v0.1.0, zero dependencies, MIT licensed) so you can run the 14-rule audit (CLS001 to CLS014) on your repository and generate a Canonical Helper Registry table for CLAUDE.md:

# Audit your repository for structural clones, duplicate helper names, and dead exports npx clonesieve . 

What rules or CLAUDE.md indexing tricks have worked best for you to keep agents from writing a 4th copy of existing helpers?