How I keep a vibe-coded build readable months later

I opened a project this week that I shipped four months ago and had not touched since. A client wanted one change. I expected the usual tax: an hour of reading my own code back to myself, trying to remember why a function did what it did, reverse-engineering logic that an agent wrote and I approved and neither of us had looked at since. That tax is the thing every vibe coder eventually pays. You build fast, the app works, and then a season later you open it and it reads like a stranger's code, because in a real sense it is.

Except this time the tax did not come due. I read the change in, made it, verified it, and shipped it inside twenty minutes. Not because I have a better memory than anyone else. Because the thing I re-read was not the code.

the three-month wall

The pain has a shape, and a lot of people are hitting it at once right now. You vibe code something real, it ships, and three to six months later you cannot explain your own build. The chat session that produced it is gone. The code is the only artifact you kept, and generated code is the worst possible record of intent, because it captures what the machine did, not why you asked for it. Every change becomes archaeology.

The conversation cresting right now calls the answer spec-driven development, and frames it as the thing that comes after vibe coding, the grown-up phase you graduate into once the toy stops scaling. I think that framing is backwards, and I think it is worth saying why, because the fix is real but the story told about it is wrong.

six delegations, zero rollbacks

Here is the build I opened this week, the way it was actually made. Thirty hours of work, broken into six delegations. Each delegation was one concern, written as a spec before any code existed: what it does, why, the inputs, the outputs, the invariants it must not break, the edge cases. Each one named exact file paths, so the builder was never guessing where a thing lived. Each one ended with a verification step the work had to pass before it counted as done. And the rule under all of it: the architect reads the existing source before writing the next piece, so nothing gets regenerated blind on top of something it does not understand.

Six delegations, zero rollbacks. Nothing had to be torn out and redone, because the spec caught the disagreement before the code existed, where disagreement is cheap. The boring foundation made the payoff cheap. That is spec-first discipline, and it is not glamorous. It feels slow on day one. It feels like doing homework before you get to build.

What it buys you is the part nobody puts on a feature list, because it shows up four months later. When I opened that project this week, I did not re-read the code to remember the build. I re-read the spec. The spec says what each piece is for, what it must not break, and how it was verified. The code is downstream of that. When I needed to change behavior, I changed the spec first and regenerated against it, the same way the build was made in the first place. The artifact that survives the closed session is the spec, not the code, and the spec is written for a human to re-read. That is the whole trick. You vibe code the implementation. You do not vibe code the contract.

This is also the difference between a spec that holds and a spec that rots. The failure mode I watch for is treating the spec as upfront-docs theater: you write it once, the agent regenerates past it, the code quietly starts to lead, the document goes stale, and six months later the spec lies to you worse than the code does. A spec is only the durable artifact if it stays the source of truth. The discipline is updating the spec first when something breaks, then regenerating, every single time. The moment the code leads the spec in silence, you are back to archaeology, just with extra steps.

it is not a step beyond vibe coding

So when the spec-driven development crowd says this is what comes after vibe coding, I push back. Reading the source before you write, specifying the invariant before you generate, verifying against a contract: these are not a different activity from vibe coding. They are vibe coding with a metal layer underneath. Same speed, same agent-orchestrated build, same practitioner who never hand-writes the syntax. The only thing added is that the orchestration itself has a specification, so the build stays explainable when the chat window closes.

I have written before about why you spec the invariants and vibe the rest, and about what your agent actually inherits between sessions. This is the same idea pointed at maintainability. The spec is the persistent memory the chat session does not have. AI orchestration without that layer produces software you cannot reason about the moment the context is gone. With it, a vibe coder ships production software that a human can still read a season later, which is the only definition of maintainable that has ever counted.

If you are formalizing your own methodology after the messy phase and want to compare notes on what actually holds at production scale, work with VibeKoded. Send me how you are building now and where the maintainability wall is starting to show, and I can scope a spec-first orchestration pass on it.

The reason I could read my own build four months later is not talent and not memory. It is that the thing worth re-reading got written for re-reading, on purpose, before the code existed. Generated code is a snapshot of an answer. The spec is the question, kept legible. Keep the question, and the build stays yours.