Inspiration
In 2016, a developer deleted an 11-line package called left-pad and builds broke at Facebook, Netflix, and Spotify. That story always stuck with me. Ten years on, the problem is worse, not better — thousands of npm packages are abandoned or gone entirely, and production code still depends on them. I wanted to see if I could bring a dead package back without ever trusting its source code — and honestly, without trusting myself either. The tool had to prove its own claims.
What it does
You run necromancer resurrect left-pad and it goes through six phases:
- Exhume — grabs the tarball off npm and verifies registry integrity.
- Sandbox — locks the package in Docker. No network, lifecycle scripts stripped. If the package is malicious, it can't touch my machine.
- Probe — actually runs the thing and records what it does, with branch/line/function coverage so I know how much of it I exercised.
- Distill — turns those recordings into SOUL.md (a behavioral spec) and a vitest suite — one test per observed behavior.
- Resurrect — the model gets the soul and the tests, never the original source, and a judge loop feeds failures back for up to six rounds.
- Report — graveyard.html with the verdict, plus a provenance receipt (SHA-256 over every artifact).
The part I care most about: it doesn't overclaim. It never says "identical" — it says N of M observed behaviors passed, here's the coverage. Some tests (I call them Last Rites) are held out from the model entirely, so passing those actually means something — it's generalization, not memorization. And necromancer verify re-checks everything offline and prints what it could NOT re-verify.
How I built it
TypeScript on Node 20. Commander for the CLI, vitest for the generated suites, c8/V8 for coverage, Docker for the sandbox, and the OpenAI API / Codex CLI as the rebuild engine. The judge loop is deterministic — structured test failures go back to the model as feedback each round.
Challenges I ran into
- Running untrusted npm code safely. Read-only mounts, no network, stripped scripts — and then vitest wouldn't run in the read-only container because Vite wants to write its temp bundle into node_modules. Fixed it by bind-mounting a writable directory over just that path.
- Coverage across the container boundary. V8 records file URLs with container paths, so c8 couldn't match them to anything on the host. I rewrite the URLs before reporting.
- Honesty is a feature you have to build on purpose. FAILED RECONSTRUCTION is a real state the tool can end in, the held-out tests exist, and verify lists what it didn't check — none of that happens by accident.
Accomplishments that I'm proud of
- Seven real packages resurrected end to end — left-pad, is-odd, deep-extend, ms, object-assign, dedent, arr-diff — with the actual numbers (fidelity, coverage, dependency deltas) in the README, including the one run that didn't go perfectly.
- 72 tests, clean typecheck, and a no-credentials replay mode so anyone can poke at the report in seconds without an API key.
What I learned
Characterization tests are a shockingly good contract for LLM code generation — when the spec is behavioral instead of prose, the judge loop usually converges in a few rounds. Also: "N of M behaviors passed" turns out to be way more convincing than "it works". Bounded claims build more trust than big ones.
What's next for Necromancer
Bigger packages (multi-module, native deps), a public cemetery of verified resurrections, and CI integration that flags dead dependencies and proposes a verified rebuild automatically.
Built With
- codex
- docker
- node.js
- openai
- typescript
- vitest
Log in or sign up for Devpost to join the conversation.