← all writing
03 · 15 Jul 2026 · 5 MIN READ

Delete the Dependency: Regenerating the Slice You Actually Use

Skimming this morning's cs.SE list, one title stopped me cold: "Software Supply Chains are Dead." I braced for a hot take with no data behind it. Instead it's a measurement paper out of James Davis's group at Purdue — a lab that actually studies supply-chain security — arguing that when a repo touches only a thin slice of a dependency, you should hand an agent that slice, regenerate it locally, and delete the package. My thesis for this post: this is the first credible attack on "npm install" as a reflex, and the numbers are better than a title that flip has any right to be.

What it does

“Software Supply Chains are Dead: Use-Case-Oriented Regeneration” starts from a build-vs-reuse calculation that's been quietly inverting. Historically you import a dependency because writing it yourself costs more than trusting someone else's code. Two things broke that math: supply-chain attacks (xz, the endless npm and PyPI typosquats) raised the cost of external trust, while generative models dropped the cost of local implementation toward zero. Singla and Davis follow that to its conclusion — treat the repository–dependency pair, not the package, as the unit of replacement, and synthesize only the functionality a given repo actually exercises.

The mechanism is a three-step agentic loop driven by Claude Opus. Establish a baseline: clone the repo, install deps, run its existing tests, builds, and linters. Regenerate: the agent finds every first-party call site into the target dependency, writes replacement code covering just those usages, rewrites the call sites, deletes the dependency declaration, and iterates whenever validation fails. Re-validate: rerun the same baseline artifacts. The key formal move is that they don't chase full semantic equivalence with the library — they only require the regenerated code match the library's behavior on the slice the repo observes. That projection is the whole trick: you're not reimplementing lodash, you're reimplementing the 4% of lodash this repo touches.

The key result

Across 180 repository–dependency pairs spanning 9 npm packages (nanoid, change-case, chalk, express, semver, postcss, lodash, axios, zod), the regenerated slices passed 64,477 of 64,634 baseline checks — 99.8% behavioral preservation, with 166 of the 180 pairs perfect. And the surface collapse is the part I keep re-reading: exported API surface fell 93.1% on average. Lodash went from 306 exports to ~19; zod from 236 to ~4; nanoid from 5 to ~1. The framing lands hard — repos “rely on a highly bounded slice of a dependency's potential behavior.” You ship an entire library to call a fistful of functions, and now there's a workflow that measures exactly how little you actually needed.

Why it matters

The practitioner reframe is that a dependency isn't a unit of code — it's a unit of trust and attack surface, and both scale with the API you import, not the API you call. If you use zod for four things, you're carrying 232 exports of blast radius for a supply-chain compromise you'll never review. Regeneration flips “external trust” into “local verification”: the replacement is code you can read, diff, and test, sitting in your repo under your CI. For anyone building agentic coding tools, this is a new job to hand an agent — not “fix this bug” but “shrink this dependency to its used slice and prove behavior held.” That's a beautifully shaped agent task: bounded, verifiable against the existing suite, with a clean success signal.

It also clarifies what context such an agent needs. Its north star is the repo's own call sites and tests — the same artifacts a good migration or refactor agent already reads. I've been treating dependency hygiene as a scanning problem: audit the tree, pin versions, watch for typosquats. This paper adds a second lever — for narrow, stable, well-tested dependencies, don't secure the import, remove it. That's a genuinely different disposition, and it composes with the “emit a reusable codemod” pattern from recent breaking-update repair work: the output isn't a throwaway patch, it's a self-contained local module you own outright.

The caveats

I want to be honest about how far this generalizes, because the authors are:

The takeaway

What I'm filing away: “should this be a dependency?” is now a live question per repo, not a settled reflex. For a utility package you use three functions of, behind a decent test suite, regeneration is plausibly the more secure and more maintainable choice — and there's finally a pair of numbers (99.8% behavior held, 93% surface cut) to argue with. I'm not going to nuke node_modules and regenerate everything tomorrow. But the next time an agent proposes adding a dependency to pull in one helper, I'm going to ask it to just write the helper — and prove the tests still pass. That inversion, one dependency at a time, is the genuinely usable idea hiding under a deliberately over-the-top title.


Working on something similar?

Say hello — I read every email.