AI Tools

I Vibe Coded a Production App. The Fun Part Ended When It Had to Work.

I used AI agents to build a real app. Vibe coding worked, but production exposed a problem: the code could grow faster than I understood it.

A magnifying lens trails far behind a glowing blue trail of code on a dark surface.

I vibe coded a large part of a real mobile app, and I would do it again. What I would not do again is confuse fast progress with a healthy codebase.

That difference barely mattered while I was only trying to make a feature work. It mattered a lot more once RYZA had alarms, voice recognition, subscriptions, widgets, two operating systems, store review, and code I was afraid to break. That was the point where vibe coding changed for me.

I was already doing it before I cared what it was called

The term vibe coding came from Andrej Karpathy in February 2025, and Merriam-Webster’s own account of it is looser than the way the term gets used now: talk to an AI, let it write the code, keep steering it, and sometimes stop paying much attention to the code itself. That last part is the one that matters here.

I use Codex most often and started using Claude Code seriously more recently. A lot of my development happens by describing what I want, letting an agent inspect the project, reviewing what happened, testing it, then going back with another instruction. So yes, a lot of what I did looked like vibe coding.

But RYZA eventually became a bad place to forget that the code even exists. It is an alarm app. If a decorative animation breaks, that is annoying. If an alarm behaves incorrectly, that is a different category of problem.

The first version of a feature can feel almost too easy

AI changed the beginning of development more than anything else for me. I could explain a feature and get something working surprisingly quickly, and when it was wrong, I described what was wrong instead of spending the next hour searching through files myself.

That feedback loop was addictive: I wanted something, I described it, the app changed, I tested it, and I described the next thing. There were days when I moved through work that would previously have taken me much longer, and I remember thinking this was simply a better way to build software.

I still think that, mostly. The problem showed up later.

My code started getting ahead of me

An AI agent can change a lot of code before I have finished understanding the first change. That sounds obvious, and I did not treat it as a serious problem at first.

Imagine an agent edits a service, changes some state logic, adds a helper, updates a platform-specific path, and fixes two errors that appear afterward. The feature works, so I move on. A week later something related breaks, and now I am looking at code that technically belongs to my project, but part of my understanding of it came from reading an AI summary rather than building the logic myself.

Do that enough times and something strange happens. I still own the codebase. I just do not know all of it anymore.

I started thinking of this as understanding debtcode that works faster than I can build a clear mental model of why it works. Technical debt is familiar. Understanding debt felt different, because the code did not necessarily look bad — sometimes it looked cleaner than code I would have written myself, which made it easier to ignore.

time on RYZA code shipped my understanding of it understanding debt
Code shipped and my understanding of it both went up. They stopped going up at the same rate, and the gap is the part that eventually breaks.

Then I made the predictable mistake

When something broke, I sometimes asked AI to fix the visible problem too quickly. The error appeared here, so I pointed the agent here. It found a solution. The error disappeared. Done.

Except sometimes the error was only a symptom. A patch could make the immediate problem go away while adding another condition to code that was already becoming harder to reason about. After enough fixes, I would look at a section and wonder why there were so many exceptions in it.

The answer was uncomfortable: I had approved them. Not because I had carefully decided each one belonged there, but because each one had solved the problem in front of me at the time. AI did not create that bad habit. It made the bad habit much faster.

Production changed what I asked the AI to do

I eventually started giving coding agents less permission at the beginning of a task. That sounds backwards, since these tools were getting more capable while I was asking them to do less. What I actually wanted was a pause between understanding and changing.

For a larger bug or feature, I started with something close to this instruction: investigate the current implementation first, do not change anything yet, find the relevant code, explain how it works, and say what needs to change. That is substance I actually use, not a magic prompt, and the useful part is the “do not change anything yet.”

I can read the explanation and see whether the agent understood the same problem I thought I had. If it misunderstood the requirement, no code has been touched. If it finds that my assumption was wrong, even better. Only then do I move to implementation. It added a step, and it often saved time.

Codex and Claude Code made me notice autonomy

This became more obvious once I was using both side by side, and I went into the working-style differences in more detail in Claude Code vs Codex. Codex is still the one I use more. I have used it longer, and in my experience it usually stays fairly close to the job I give it. It occasionally misunderstands me or does something I did not expect, but I generally find it easy to keep focused.

Claude Code feels more proactive to me. I can ask about one problem and find it looking around the surrounding implementation. Sometimes that is exactly what I needed, and it notices something I had not thought to ask about. Other times I wanted one change and got an engineering opinion along with it.

Neither behavior is automatically better. It made me realize that using an AI coding agent is partly a question of how much judgment I want to hand over for this particular task, and that was not something I thought about much when I started.

Vibe coding gets weird when iOS and Android disagree

RYZA is built for iOS and Android in Flutter, which gave me a quick lesson in the difference between code that looks correct and software that actually works. An AI agent can inspect the code and give me a convincing explanation. The project can compile. The logic can make sense. Then I put it on a real phone.

An operating-system rule, permission, notification behavior, background restriction, or native implementation can change the result. This is especially noticeable in an alarm app, because so much of the product touches the operating system rather than living inside a normal screen.

I stopped treating a successful build as proof that a task was finished. The phone gets the last vote.

There is now research behind one of my worries

One thing I did not want to do in this post was turn my experience into a universal claim. My project is one project. But a June 2026 paper on arXiv examining real-world vibe-coded applications found recurring security problems including exposed secrets, insufficient input filtering, and placeholder logic, and found that better models and prompting reduced those problems without removing the underlying security risk.

That does not mean vibe-coded apps are automatically insecure. It does mean “the AI made it and it works” is not much of a security review. I think the same idea applies outside security too. Working is a starting condition.

I don’t want to stop vibe coding

This is the part where I disagree with the easy conclusion. I do not think the answer is to go back to writing everything manually, and I do not want to. AI lets me move faster, investigate unfamiliar code faster, and attempt things that would have taken much more time before. For an independent builder, that difference is hard to give up.

The market seems to agree that this way of building software is not disappearing: Lovable, one of the best-known products associated with vibe coding, was valued at $13.3 billion after a $400 million funding round reported by The Times in August 2026. That number is interesting, but I do not think the money is the important part for someone building an app. The important part is that the behavior is becoming normal — people describe software and software appears. The question after that is who understands what appeared.

The part I care about now

Early in RYZA, progress was easy to see: a new screen existed, a feature started working, a bug disappeared. Those were satisfying milestones.

Now some of the most valuable work produces almost nothing visible. I trace an alarm flow before changing it. I review what an agent touched. I test the same behavior on another platform. Sometimes I decide not to make the change at all. It feels slower than the first rush of AI coding. It isn’t. I had just been measuring speed at the wrong point.

Getting code onto the screen is fast now. Keeping a product understandable while that code keeps arriving is the harder job.

I would still vibe code my next app. I would just pay attention much earlier to the moment when the app stopped being disposable, because that was the line I missed with RYZA. Once I cared about protecting what already worked, I was not really asking AI to make software anymore. I was asking it to help me change software without losing control of it.