Every team eventually says the same sentence about its own system: nobody knows why it does that any more.
The code is still there. It compiles, it ships, it serves traffic at three in the morning. What has gone is the knowledge that produced it. The rule someone agreed with a customer four years ago. The constraint that forced an architecture decision. The reason a strange workaround exists in the payment path. That knowledge lived in people, and it left when they did.
What remains is a fossil: evidence that a decision happened, without the decision itself.
We accepted this because, until recently, code was the only durable artifact that could actually run. Documentation was a courtesy. Specifications were scaffolding you threw away once the building stood. Anything that was not code decayed, because nothing depended on it being true.
I have spent the last while testing whether that is still the case. This post is what I found, including the parts that did not work.
The experiment
I built a small commerce system: customers, an address book with a default-address invariant, and orders that capture a copy of the shipping address rather than a reference to it. Nothing exotic. The kind of business logic that fills real systems.
Then I wrote down its knowledge. Not documentation, exactly. Business rules as individual files with IDs and relationships. Architecture decisions with the alternatives that lost and why. Assumptions nobody had verified. And contracts, in given/when/then form, stating behaviour at the HTTP boundary.
Then I generated two implementations from that knowledge. One in TypeScript, one in Python. Neither was written from the other.
Both pass the same seventeen contract scenarios, executed by the same runner:
============================================================
typescript http://127.0.0.1:54123
============================================================
PASS CT-001 Email uniqueness on registration (4/4)
PASS CT-002 Default address invariant (6/6)
PASS CT-003 Deleted customers cannot authenticate (3/3)
PASS CT-010 Orders capture the shipping address (4/4)
17/17 scenarios passed across 4 contracts
============================================================
python http://127.0.0.1:54126
============================================================
PASS CT-001 Email uniqueness on registration (4/4)
PASS CT-002 Default address invariant (6/6)
PASS CT-003 Deleted customers cannot authenticate (3/3)
PASS CT-010 Orders capture the shipping address (4/4)
17/17 scenarios passed across 4 contracts
Same knowledge. Same contracts. Different stacks. All green.
Enter fullscreen mode Exit fullscreen mode
You can clone it and run node verify.mjs yourself. It has no dependencies, on purpose, so there is nothing to install and nothing to trust.
Then delete impl/python, hand the knowledge to any capable coding agent, and watch it come back.
What this is actually claiming
Not that AI writes software. Everyone has heard that, and most people have been disappointed by it.
The claim is narrower and, I think, more useful. Code is becoming a build artifact of knowledge, in the same way binaries are a build artifact of code.
binaries are a build artifact of code verified by compiler + tests
code is a build artifact of knowledge verified by contracts + regeneration
Enter fullscreen mode Exit fullscreen mode
Almost nobody reviews compiler output. Nobody stores the binary and deletes the source. We review source, trust a toolchain, and verify with tests. The ladder has moved before.
The analogy is imperfect and it is worth saying so immediately: a compiler is deterministic and semantics-preserving, and a model is neither. That is exactly why the right-hand column matters more here than it does one rung down. The analogy sets the direction. Verification carries the weight.
The part everyone skips
If you take one thing from this post, take this.
Contracts have to be knowledge, not generated code.
If your tests are generated from the same prompt as your implementation, in the same breath, they cannot verify your intent. They confirm only that the model was consistent with itself. That is not nothing, but it is not verification of what you asked for.
So contracts get written and reviewed as knowledge, versioned as knowledge, and changed only when a human deliberately changes them. Regenerated code must satisfy the contract suite that existed before it was generated.
Two consequences follow, and both matter more than they look.
Contracts must sit at an interface boundary: HTTP calls, command-line behaviour, data formats, observable effects. Never internal classes or function names. A contract that reaches inside an implementation cannot survive that implementation being regenerated, let alone regenerated in another language. In my demo, the contract runner contains no mention of TypeScript or Python at all. That constraint is what makes stack independence a property rather than a slogan.
And a contract suite can only falsify, never prove. More on that below, because it is the most important limitation here.
How this differs from what already exists
2025 was the year the industry moved to specifications. GitHub Spec Kit brought structure to agent workflows. Amazon Kiro built an IDE around requirements, design, and tasks. Tessl made the strongest commercial case that specs are durable and code is disposable. Sean Grove of OpenAI put it memorably in The New Code: code is a lossy projection of the specification.
I agree with all of them. Two distinctions are worth drawing, and they are not the same distinction.
Against feature-scoped tools. Spec Kit and Kiro answer "how do I build the next thing with AI". A spec is written, drives an implementation, and after the merge nobody guarantees it is still true. That is not a flaw, it is what those tools are for.
The question I care about is different: how do you own a system for ten years once code is cheap? That forces everything the feature-scoped view can skip. The whole system rather than one feature. A lifecycle rather than a hand-off. Drift detection. A debt model. Provenance. A path in for brownfield code.
Against platforms. Tessl is not feature-scoped, and it would be unfair to pretend otherwise. The difference there is not scope but ownership. What I am describing is a methodology: an open schema, conventions anyone can implement, no registry to depend on. Knowledge that compiles only inside one company's platform is not the stack-independent knowledge I am arguing for.
Drift is the actual enemy
The thing that kills this approach is not bad generation. It is the Tuesday afternoon hotfix applied straight to the code and never reflected back into knowledge. Do that a dozen times and your knowledge base becomes exactly what documentation has always been: confidently wrong.
So drift gets a direction, and the two directions mean opposite things.
Knowledge ahead of code is normal. Someone decided something, the implementation has not caught up. That is a backlog.
Code ahead of knowledge is a defect, and detecting it turns out to be simpler than it sounds, because it needs no understanding of the code:
If a change touches a module's generated paths and contains no corresponding change to that module's knowledge, that is code-ahead drift.
Purely structural. A build artifact changed while its source did not. I have this running as a CI check that blocks merges.
Emergencies still happen, and a methodology that forbids them gets ignored during the first outage. So there is an escape hatch: ship the hotfix, record it as drift debt with a reason and an owner, carry a reconciliation task. The debt stays visible in the metrics, because an escape hatch that hides the debt is just rot with paperwork.
"We tried this. It was called MDA."
If you were building systems twenty years ago you are already typing this, and you are right to.
The honest version of my answer is not that MDA's generators were worse. Per run, those deterministic template engines were far more predictable than any language model. Anyone claiming otherwise is selling something.
MDA's actual failure was that it treated the transformation as correct by construction. There was nothing standing outside the generator to check its output against intent. When the model and the generated system drifted from reality, nothing caught it.
This approach assumes the generator is fallible precisely because it is stochastic. That assumption is why contracts are written before generation, why they are knowledge rather than generated artifacts, and why provenance is recorded. Determinism was never what made generation safe. Independent verification is.
The thing that has not changed: this works best where behaviour can be contracted. That was true of MDA and it is true here.
I ran this test on my own demo and it failed
Both implementations above were written by the same agent in the same session, which is not evidence of anything. It is the software equivalent of marking your own homework. So I ran the test properly.
I moved the Python implementation out of the repository and gave an independent agent access to the knowledge files only. No TypeScript, no contract runner, no README. One attempt, no chance to run the suite first.
It scored 14 out of 17.
Every failure came from one thing: the contract runner reads order.shippingAddress.line, and the regenerated implementation returned shippingAddress as a bare string instead of an object.
That was not an implementation mistake. My knowledge never said which shape it should be. Both choices are defensible, the agent picked one, and the contract silently assumed the other.
Before scoring, the agent had listed eighteen questions the knowledge did not answer. The worst was not the failure at all:
There is no edit-address endpoint anywhere in the knowledge. CT-010 has "When the customer edits address...", but the interface documentation lists only POST, GET, and DELETE. I invented one.
A contract was exercising a capability my interface documentation did not contain. That contradiction had been sitting in the repository since I wrote it, and no schema validator could have caught it, because it is a semantic gap rather than a structural one. Only regeneration found it.
It also caught my prose contradicting itself. One rule opened with "exactly one address is the default at all times" and closed by describing the case where there is none. Another referred to "the same generic message as a wrong password", in a system that has no passwords.
So I fixed the knowledge, not the code. Editing the implementation to match the contract would have left the next regeneration failing in exactly the same way. And I did not touch the contracts, because contracts are knowledge, and changing one to make a build go green is the most destructive move available here. The contracts were right. My documentation was wrong.
I am telling you this because a demo that only ever succeeds is worth very little, and because this is the methodology doing the one thing I claim for it: regeneration is not only how you produce software, it is how you find out what you failed to write down.
Then I sent the same agent back to the corrected knowledge. 17 out of 17.
The result is genuinely independent work, not a reconstruction: 481 lines against the original's 277, a different internal structure, a mutex the original did not have. It even removed an endpoint it had invented in the first round, once the corrected rule made clear that the default address changes only through the operations already listed.
That is the whole loop, on a system small enough to hold in your head: regenerate, fail, find the debt, fix the knowledge, regenerate, pass.
And the second round found one more thing, which is my favourite finding of the lot:
POST /resetandGET /healthare absent from the knowledge entirely. A third implementation regenerated from the knowledge alone would not have them and would be unscoreable.
I had documented the domain carefully. What I never wrote down was the scaffolding the tests need, because it lived in the head of whoever wrote the test harness, which was me. That is exactly the kind of knowledge regeneration loses, and exactly the kind nobody thinks to write down. It is now a file.
One technique worth stealing even if you take nothing else from this: ask the regenerating agent what it had to guess, before you score it. Those guesses are your knowledge debt whether or not your tests happen to catch them. Mine listed eighteen the first time. Three of them cost me contracts. The other fifteen were real gaps that simply had not been exercised yet.
The part I got wrong at first
I wrote the first version of this as a document practice. Write your knowledge down, structure it, generate from it. Counting words in that draft: "knowledge" ninety-one times, "agent" four, and two of those four were about other people's products.
That framing gives away the whole point, because it does not explain why now.
Structured documentation is not a new idea. Literate programming is from 1984. Model-driven architecture had metamodels and generators twenty years ago. People have been writing down business rules and hoping since before I could type. What changed is not that we discovered documentation is good.
Documentation has always failed for exactly one reason, and it has nothing to do with formats or discipline: keeping it true is work nobody is paid to do.
That is the constraint that has actually lifted. Not the typing of implementations, which is the least interesting thing an agent does here. The unglamorous maintenance nobody ever had budget for: checking that the description still matches, noticing when it stopped, drafting the correction.
Three things follow that were not available before:
Regenerate on a schedule, not just on demand. Continuous integration proves your code still works. Regenerating a module every week proves you still understand it. When that fails nothing is broken and no user notices; what decayed is your knowledge, and you found out before it mattered. A module nobody has regenerated in six months is not known to be regenerable, only believed to be.
Never let an agent verify its own work. I learned this by getting it wrong, as described above. An agent that wrote the code, or that can see it, will reproduce what it remembers and report that everything is fine.
Let the machine draft the correction. When drift is found, an agent writes the proposed knowledge change and a human reviews a draft instead of facing a blank page. The judgment stays human; the typing does not. That is the same inversion that makes mining old systems work.
One caution, because this is where the idea is easiest to oversell. Agents are how this runs in 2026, not what it is. Knowledge is supposed to outlive implementations, stacks, and tools, and that includes the tools doing the regenerating. Define the method by what today's agents happen to do and it dates the moment they change.
Automate the toil. Do not automate the judgment.
What I am not claiming
A methodology that works everywhere is selling something, so here is the honest flank.
Contracts under-specify, always. Seventeen scenarios do not prove my two implementations are equivalent. They prove nothing contradicts what I specified. Either could carry an injection flaw, a quadratic loop that only bites at scale, or a resource leak, and still be green. "Behavioural equivalence under contract" means equivalence with respect to what you wrote down, and nothing more. Static analysis, dependency scanning, and load testing do not become optional.
Security review does not go away. Generated code is untrusted code from an unfamiliar author. Authentication, authorisation, cryptography, input handling at trust boundaries, anything touching money or personal data still needs human eyes, at every level of this. A model choosing your dependencies is a model choosing your attack surface.
I picked a contract-friendly domain, and that was convenient. Business rules over an HTTP interface are the easy case. Interface feel, animation, performance tuning against a specific runtime, exploratory code whose purpose is to discover what you are building: these resist contracts, and where behaviour cannot be verified, regeneration is not safe.
Regeneration is not deterministic. Two runs produce different code. If you need byte-identical output, this is not for you.
The test conflates two things. A failed regeneration might mean your knowledge was incomplete. It might equally mean the model was not up to the task. Diagnose before booking it as knowledge debt.
What you can do this week, for free
You do not need my schema, my tooling, or anyone's permission. The useful part costs about an hour.
Run the Regeneration Test on one module. Not to regenerate it. Just to answer the question:
Could you delete this implementation today and regenerate a functionally equivalent one from your written knowledge alone, with the existing tests passing?
Then write down everything that makes the answer no. Rules that live in one person's head. Decisions nobody recorded. Behaviour that exists because of an incident three years ago.
That list is your knowledge debt, itemised. Most teams find it is shorter and more alarming than expected: not thousands of missing pages, but a dozen specific facts two people happen to know.
Whether or not you adopt any of this, that list is worth having.
Links
- Manifesto and getting started: regen.engineering
- The two-stack demo, clone and run it: regen-engineering-demo
- Schema and tooling: regen-engineering-schema
- Agent skills: regen-engineering-skills
It is version 0.1 and it is meant to be argued with. If you run the Regeneration Test on your own code, I would genuinely rather hear that it failed than that it worked. A methodology tested only by the person who wrote it, on examples they chose, is worth very little.
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.