DEV Community

Cover image for NecroKit: finding the dead code you depend on, built with Kiro for Kiroween 2026
Anish Kumar
Anish Kumar

Posted on AI-assisted

NecroKit: finding the dead code you depend on, built with Kiro for Kiroween 2026

This post is written as part of the Kiroween 2026 hackathon.

Most software does not die loudly. A package stops getting releases. Its repository gets archived. CI stays red for months. Nobody notices until a security alert shows up with "no fix available", and then you find out the thing you depend on has been dead for four years.

I wanted a tool that says plainly what is dying, shows the proof, and tells you what to do next. That became NecroKit, my entry for the Skeleton Crew category.

One skeleton, two apps

Skeleton Crew asks for a lean template that supports two different apps. NecroKit is a small TypeScript core that does four things:

app adapter (fixture or live)
  -> evidence + unavailable sources
  -> rules -> findings (each cites evidence ids)
  -> score (0-100, band) + revival plan
  -> report (JSON, Markdown)
Enter fullscreen mode Exit fullscreen mode

The core knows nothing about npm or GitHub. Each app adds only an adapter, a live collector, and its own rules.

Package Graveyard checks an npm package. It looks for deprecation (and quotes the notice), an archived source repo, no release in two years and no commit in one year, a single maintainer, and low downloads. Try left-pad: 6/100, critical, with "use String.prototype.padStart()" quoted straight from the registry.

Repo Reaper checks a public GitHub repository: archived, no license, failing CI, stale issues, forgotten pull requests, no push in over a year, no recent release, and no README.

On top of both sits Undertaker, a Kiro Crew app that runs the same scans on a schedule, keeps a score history, and turns new findings into revival plans that wait for a person to approve or dismiss them. It never changes code.

Three rules I would not break

1. Every finding cites evidence. Nothing is scored by a model. Each finding links to the exact facts behind it, and in the demo every evidence chip opens the registry page or GitHub page it came from. People trust a verdict when they can click through to the proof.

2. Missing is not guessed. If a call fails or GitHub's rate limit is hit, the report lists that source under "Could not check" with a plain reason, and the rules that need it do not fire.

3. No evidence, no score. Early on, a package that does not exist scored 100 and was called healthy, because no rule fired. Now a report with no evidence has score: null and band unknown. "We know nothing" should never look like "all good".

How Kiro shaped the build

This is the part I care most about, because Kiro changed the order I did things in.

Specs first, and the core spec before the apps

I wrote three specs in .kiro/specs/: core platform, Package Graveyard, and Repo Reaper. Each has requirements in EARS style, a design, and a task list. The core spec came first, on purpose. Once it said things like

WHEN no evidence at all could be collected THEN the report SHALL have score: null and band unknown rather than a perfect 100.

both apps had to fit that one contract. The spec turned "make it reusable" from a hope into a checklist.

Steering as a set of house rules

.kiro/steering/project.md is always included, so every change Kiro made had to respect lines like:

  • Every finding must include evidence, an unavailable reason, or a fixture citation.
  • Never call an external API without timeout, rate-limit handling, and fixture fallback.
  • Never require a secret or paid service for the judging path.
  • Do not delete or weaken tests to make a result green.

That last one matters. With an agent writing code, the easy way out of a red test is to change the test. Steering closed that door.

Hooks that guard the shared core

The whole point of a skeleton is that a change to the core cannot quietly break an app. So there is a hook on packages/necrokit-core/src/**/*.ts: when a core file changes, Kiro runs the core typecheck and tests, then typechecks both apps against the new contracts, and lists every adapter or rule that must change if a contract changed shape. A second hook does the same for each app's rules and asks Kiro to explain any snapshot change.

Property-based tests for the score

The score is the one number people look at, so it gets property tests with fast-check: it always stays between 0 and 100, adding a finding never raises it, and the order of findings does not change it. That last property caught a real bug where the score depended on finding order.

Kiro Crew for the part a web page cannot do

A dependency rarely dies in one day. It gets a failing CI, then a stale release, then an archived repo. A one-off scan misses that slope. Undertaker uses what only a long-running host gives you: a cron that scans while the browser is closed, a data folder that survives updates, a backend behind the gateway's signed proxy, and an agent with a necrokit-triage skill that can explain a report in plain language. Getting it running in a real Kiro Crew 0.11.0 gateway taught me a few things the docs did not, like the gateway still signing with the v1 proxy header.

A bug I found while writing this post

While re-testing the live demo, request/request scored 79, "healthy". That repo has not had a push in over two years and its oldest open pull request is almost ten years old. The collector already read pushed_at from GitHub, but no rule used it.

So I added no-recent-push: a warning when the last push to any branch is more than a year old. Using any branch keeps it conservative, so it only fires when the whole repo is quiet. The hook made Kiro run the tests, the neglected fixture's snapshot changed from 68 to 56 with the new finding, and request/request now reads 67, "at-risk". That is the loop I wanted: evidence already there, a small named rule, a test, done.

Try it

  1. Open https://necrokit-demo.vercel.app. It starts on a recorded scan of an abandoned package.
  2. Click left-pad or request, or type any npm package.
  3. Switch to Repo Reaper and paste any github.com URL.
  4. Click any evidence chip to see its source, then copy the report as Markdown.

Or run it locally:

corepack enable
pnpm install
pnpm test
pnpm dev
pnpm scan:package --live left-pad
Enter fullscreen mode Exit fullscreen mode

What's next

Scanning a whole package.json at once, so you get one graveyard map for your project instead of one package at a time.

If you have a package you suspect is quietly dead, run it through NecroKit and tell me what it finds.

Top comments (0)