A few weekends ago I sat down to audit a few personal AI projects I’d been working on since the start of the year. As I mentioned in my previous article my coding skills are rusty, but I vibe coded my way through these projects. My project apps are working well and I’d been using them daily for months without much trouble.
I’ve also been adding features and enhancing constantly and I started noticing small things. A feature that worked yesterday would quietly behave differently today. A configuration file was twice the size it should have been. There were code paths I didn’t remember asking for. Nothing was broken, exactly. I just had a growing sense that the projects had gotten bigger than my understanding of them. The phrase that kept coming to mind was technical debt, which is the term software engineers use for the invisible cost of shortcuts taken earlier, the bill that comes due later.
So I decided to audit my apps. I wanted to know how much of that debt I’d actually accumulated. The audit itself was simple in concept. I wrote a detailed prompt asking an AI to act as a senior engineer and examine the code across three dimensions: security, redundancy, and efficiency. I told it to be specific, give file paths, and not soften the findings. Then I let it get to work.
The findings exposed a real gap between what I thought I’d built and what was actually running. These are just a few examples I encountered:
When people talk about vibe coding, the conversation usually splits into two camps. The enthusiasts will tell you it’s a superpower that lets you ship in days what used to take months. The skeptics will tell you the code is fragile, the security is poor, and the engineers will have to clean up eventually.
Both camps are right but there is another dimension to this. The real cost of vibe coding isn’t bad code. It’s invisible code.
When you describe a feature and an AI writes it, you get back something that runs. You test the happy path, it works, and you move on. What you don’t get is intuition, the kind that comes from having written the thing yourself, line by line, and knowing where it’s brittle, what it assumes, what happens if a config value is missing. You don’t have the muscle memory because you didn’t lift the weight.
Multiply that by every feature, every file, every dependency added over months, and what you end up with is a mess. Its as if you have a high level map but no firsthand knowledge of the terrain. The technical debt isn’t the kind a careful engineer logs in a ticket. It’s the kind you don’t even know you’re carrying.
My audit surfaced a long list of things in that territory I hadn’t known existed. Security vulnerabilities, both serious and trivial. Orphaned dependencies, which are software libraries the project required but never actually used. Dead code paths that ran on every request and produced nothing. Hardcoded values masquerading as defaults. Database queries that should have taken milliseconds but, written without indexes, were doing full-table scans every time. None of it was the AI’s fault, exactly. I told it what to build and it built it, and the features worked. But somewhere as the daily features grew, in the gap between what I asked for and what was actually shipped, a shadow codebase grew up, full of code I’d never read, decisions I hadn’t made, and behaviors I couldn’t have predicted because I didn’t know they existed.
I’ve been thinking about this at a larger scale, because the pattern doesn’t stop at personal projects. Enterprises are adopting AI coding tools at lightning speed right now, and the case for it is genuine, with measurable reductions in developer time, faster cycle times, and lower cost per feature. But here’s what I think is under appreciated. In traditional software development, technical debt accumulates slowly, building over years through team transitions, deferred refactors, and well-intentioned shortcuts, and there’s time to notice it. With AI-assisted development, the same kind of debt accumulates really fast. The same dynamic that produced my shadow codebases in four months is operating inside those companies too, just distributed across more engineers and more repositories. The features ship and the benchmarks improve, but the technical debt is being accumulated silently the in code nobody is reading carefully, because the AI wrote it and the humans approved it. That debt is invisible on the same dashboards that show the speed gains. The bill is real, it’s just deferred, and it will come due in audits, incidents, and migrations that happen long after the productivity numbers have been celebrated.
That’s the part I’d want every executive making AI coding decisions to sit with.
In case you are wondering, I’m not going to tell you to stop vibe coding. I haven’t stopped, and I’m not going to. The advantage is real. Four months ago I couldn’t have built these projects at all, and now I have them running and producing real value in my life.
Instead, what I am going to do is treat the output differently. I now assume, by default, that any project I’ve built this way contains things I don’t know about. I run audits not as a one-time cleanup but as a recurring practice, the way a careful homeowner reads their own utility bills, and I take the findings seriously even when the project appears to be working fine. That’s precisely the condition under which the worst problems hide.
There’s one more layer to this that I’m still working through. After I ran the first audit, on instinct, I ran the same audit again using a different AI, and the moment that unsettled me most wasn’t finding the problems. It was realizing the auditors disagreed. Some findings overlapped, but each tool also caught critical things the other missed entirely. Which raised an uncomfortable question I wasn’t quite ready for: if the code writing is AI-assisted and the auditing is AI-assisted, what exactly am I checking against?
For now, the lesson I’m sitting with is simpler. AI assistants don’t just write code faster than I can, they produce systems whose surface area outruns my attention. Every feature I didn’t write myself is a small loan against my future understanding. To be honest, I’m going to keep building this way, but I’m done assuming that working code means I understand it. For now, if I haven’t audited it, I treat it like I don’t know what it does. Because I probably don’t.
Originally published at https://www.linkedin.com.
Vibe Coding has an Invisible Bill was originally published in Stackademic on Medium, where people are continuing the conversation by highlighting and responding to this story.