What technical debt is, when you didn't write the code
The trouble with quick and dirty is that dirty remains long after quick has been forgotten.
AI didn't eliminate technical debt. It made it invisible. You can ship 500,000 lines of working code in a weekend. The demo runs. The PR looks clean. What you can't see is the surface area you just took ownership of. The debt is there. It always was. It just lives somewhere you can't point to.
McConnell wrote that in 1993, and it applies more now than it did then. For most of software history, technical debt was a deliberate choice. A team took a shortcut, knew the cost, and shipped anyway. The trade-off was visible. AI changed the visibility, not the trade-off.
What technical debt actually is
Ward Cunningham coined the term in 1992 as a financial analogy: borrow speed today, pay it back tomorrow. The metaphor stuck because engineers had always felt this and had no clean word for it.
Debt isn't "code that needs to be fixed later." It's the interest you pay on every future change in that area. The extra hour spent figuring out what the code does. The extra meeting to confirm an undocumented edge case. The extra risk that your change breaks something you didn't realize you were touching. The principal is the original shortcut. The interest is what every future engineer pays, including future-you.
Two flavors. Deliberate debt: you saw the shortcut, weighed it, took it. You know where it is. Manageable. Accidental debt: you didn't see the shortcut. You wrote the code the only way you knew how, or in the way the model produced it. By the time you notice, it's woven through everything built on top.
Most AI-generated debt is the second kind. The model doesn't carry the context to choose a better shape, and you don't catch the choice it made because you weren't watching at that altitude.
The 1-degree-off error compounds at AI speed
We've written before about how AI changes the physics of development. A flight from New York to San Francisco that's one degree off course lands in the ocean. The pilot has hours to notice and correct. A rocket aimed one degree off doesn't get that window. Traditional development was the airplane. Slow enough that bad direction was costly but survivable. You'd notice midway through a project, rewrite the spec, burn a few sprints, land close enough.
AI-accelerated development is the rocket. You don't drift off course over months. You launch off course in a weekend.
The thing that's compounding isn't just lines of code. It's committed direction. Every architectural choice the model makes, every name it picks for a function, every abstraction it implies through the shape of its first three files, becomes the substrate that the next thousand decisions get built on top of. By the time you notice that one of those early decisions was the wrong direction, the next thousand decisions have all assumed it was the right one. Unwinding the original choice means unwinding everything that grew on top of it.
This is the part where the analogy with financial debt holds up best. Interest doesn't compound on the principal alone. It compounds on the unpaid interest from every prior period. A small shortcut taken in week one shows up in the work of week thirty as a cost much larger than the shortcut itself. Not because the shortcut got worse. Because everything you built on top of it shares its assumptions.
The 500,000-line example
Imagine a fresh codebase generated quickly through a vibe-coding session. 500,000 lines. It works. It looks clean to a reader because the model is reasonably good at making code that looks clean. There are no obviously wrong patterns at the surface level. By every measure that lives on the surface of the code, the system is fine.
Now ask yourself the questions a real maintenance situation forces you to answer. Where does this data model break down? What happens when a user does X under condition Y? Which of these modules can I delete without something quietly breaking? Why is the auth flow structured the way it is, and what was the intent? If I need to swap this dependency, where are the assumptions about it leaking?
In a codebase you wrote by hand, you have at least partial answers. Even bad answers, the kind that begin with "I think," are answers that route you toward a starting point. The mental model came with the keystrokes.
In a codebase the model wrote, the answers are missing. Not because the answers don't exist. They live in the implicit choices the model made while it was generating, and those choices are encoded in the code without being documented anywhere. The model isn't around to ask. The transcript of the prompts is somewhere in your chat history, maybe. The reasoning behind why this function gets a callback and that one gets a promise wrapper isn't anywhere. You own the 500,000 lines now. You own the surface area. You don't own the understanding.
That gap is the debt. It was there the whole time. You just couldn't see it because the surface looked clean.
Aim is the new ceiling
The reframe worth carrying out of this post is structural, not moral.
The hardest part of building software was never writing the code. The model moved that. What's left, after generation gets cheap, is the part that always mattered most: knowing what to build and what success looks like. We argued this in detail in another post, but it applies most sharply to the technical-debt question. The debt that compounds in AI-generated code isn't a function of how the code was written. It's a function of how unclear the intent behind the code was when it got generated.
A clear brief about what you're building and why isn't process ceremony. It's the thing that determines whether the next thousand decisions the model makes share the right assumptions or the wrong ones. The person closest to the problem is the one most equipped to set that direction. When the model is doing the writing, the human's job moves up an altitude. The competitive advantage isn't typing speed anymore. It's whether the human can hold the right direction long enough for the model to build along it.
We see this in real client work all the time. Two teams use the same tools. One produces code that compounds value. The other produces code that compounds debt. The difference isn't the tools. It's the clarity the human brought to what they were asking for. Product thinking is what separates the two outcomes, and it's where most of the durable work has migrated to.
What to do, practically
A few moves that don't require building any new methodology, just taking the existing posture toward code seriously when the code was generated for you.
Treat AI-generated code like inherited code. A codebase you didn't write yourself is a codebase you have to read before you trust. The same is true of code your AI wrote yesterday, even if your prompts are what asked for it. Read the data model carefully. Identify the assumptions the model made about edge cases. Add the tests that those assumptions imply.
Aim before you generate. A short brief about what you're building, who it's for, and what success looks like prevents most of the debt that accumulates from the model making decisions you didn't notice you were delegating. Five minutes of clarity at the front of a session saves hours of unwinding later. The discipline is closer to product thinking than to engineering, and that's the point.
Review at the right altitude. When the model generates a thousand lines, the value isn't in reading them character by character. The value is in asking three questions: Does this solve the problem I actually had? Does the data model match where I'm going next? Will the next change I want to make be easier or harder because of how this is shaped? Those are intent questions, not syntax questions. They're what an engineer reviewing a junior's code would ask. Apply them.
Notice and decide. Most accumulated debt is not noticed until it has to be dealt with. The teams that stay healthy notice it earlier, on purpose, and decide whether to pay it down or live with it. That decision is sometimes "live with it." That's fine. The problem isn't taking on debt. The problem is taking on debt you didn't know you took on.
Vibe coding is a stage. Product thinking is what carries you through it.
There is nothing wrong with shipping something quickly through an AI tool. Many of the best products in the next five years will start that way. The mistake is mistaking the speed of generation for the durability of what got generated. They're different things. They've always been different things. AI just changed how visible the difference is.
The trouble with quick and dirty is still that dirty remains long after quick has been forgotten. McConnell's line outlived the era it was written for because the underlying dynamic doesn't care what technology is at the keyboard. It only cares whether someone was thinking clearly about the direction of the work while it was happening. That's the part of the job that didn't move when AI did.
If you're shipping with AI, you're not the problem. You're the audience. The thing worth getting right is the thinking that goes in before the code comes out. That's where the compounding lives now.
Frequently asked
What is technical debt, in plain language?›Technical debt is the cost you pay every time you touch a piece of software where shortcuts were taken.
How is AI-generated technical debt different?›The debt isn't different. The visibility is.
So is vibe coding bad?›No. Vibe coding is a stage of maturity, not a destination.
What should I do if I've already shipped a lot of AI-generated code?›Treat it the way you'd treat a codebase you inherited from a contractor.
How do I avoid accumulating it in the first place?›Aim before you generate. A clear brief about what you're building and why prevents most of the debt that accumulates from the model making decisions you didn't notice you delegated.
Considered takes, in your inbox.
We write when we learn something worth sharing. No schedule, no marketing digests. Built for engineers and product owners shipping with agents.