Inspiration
Every developer has a graveyard of half-finished repos. They rarely die because the idea was bad — they die because nobody wrote down what the code was supposed to do. When Kiroween asked for a resurrection, this was the honest reading: you can't revive something without first recovering the intent behind it.
We picked a real corpse. aiorest is an
experimental JSON REST framework for aiohttp that its own maintainers declared dead. The
last commit is from April 2015. Its README says it plainly:
The development has stopped, the project is abandoned.
What it does
Resurrection runs an abandoned project through Kiro's spec-driven workflow in three stages:
- Diagnose — static triage of the repo (dependency declarations, import graph,
legacy API surface, async style) produces
diagnosis.md: what is broken, what is missing, and what can never come back. - Specify — from that diagnosis, Kiro writes a real spec:
requirements.md,design.md,tasks.md. - Revive — it works the task list one verified step at a time. Every task must carry an executable check; a change that fails its check is reverted, not kept.
The output is not just running code — it's the spec the project should have had on day one, so the next person (or the next agent) can pick it up.
How we built it
- Kiro for diagnosis, spec generation, and the task execution loop
- Python 3.12 for the scanning and orchestration layer
- pytest as the verification gate — a task only "passes" when its named test goes green
- Git as the safety net: every task runs on a branch, unverified changes are reverted
We deliberately chose a target far past the point of a simple dependency bump:
aiorest depends on APIs that no longer exist at all.
Challenges we ran into
The root cause was a version constraint, not a bug. setup.py declared
install_requires = ['aiohttp>=0.12'] — a lower bound with no ceiling. Eleven years later
pip happily installs aiohttp 3.14.5, and the package dies on import:
The tempting fix is to pin aiohttp<1.0 and call it resurrected. That's archaeology, not
revival — the project still wouldn't run on any modern Python. So our spec forbids
pinning backwards. The migration target is aiohttp 3.x.
One root cause, nine failed test files. pytest tests reports nine collection errors,
but they are all the same import chain exploding (__init__.py:37 → server.py:8 →
errors.py:14). That was a useful lesson for the diagnosis stage: counting errors lies —
you have to trace the chain.
Rewriting isn't renaming. handler.py:17 reads
class RESTRequestHandler(aiohttp.server.ServerHttpProtocol). The entire aiohttp.server
submodule was removed in 3.x. There is no equivalent class to rename to — the request
handling layer has to be rebuilt on aiohttp.web. That single line is where "resurrection"
stops being mechanical.
Async style outlived its idiom. The codebase has 20 @asyncio.coroutine decorators and
17 yield from expressions in the source (another 35 and 84 in the tests).
asyncio.coroutine was removed in Python 3.11. Every one of those is a hard failure on
Python 3.12 — and a task list that names them one by one is 37 tasks long. This is exactly
where coarse-grained, unverifiable tasks make things worse: the agent starts rewriting
whole modules and the diff becomes unreviewable.
Accomplishments that we're proud of
- Took a package that could not be imported at all and drove it to a state where its own test suite runs
- Every single edit in the final report is traceable to a task and to the check that verified it — no "trust me, it works" diffs
- Produced a spec that explains the migration in terms of intent, not in terms of diffs
What we learned
Spec-driven development isn't really about writing specs upfront. It's about making every step checkable. The moment a task has no verifiable outcome, the agent starts guessing, and guessing is what killed these projects in the first place.
The second thing: a dependency without an upper bound is a scheduled death. Every project
we looked at had the same signature — pkg>=x.y and no ceiling — and every one of them
died on schedule.
What's next for Resurrection
- Handle projects with no tests at all: have Kiro write the first smoke test before touching any source file
- A "resurrection score" that estimates salvageable surface from static analysis alone, so you know how much of a corpse is worth reviving
- Support multi-language repos where the death is a build-system problem, not an API one