Vibe-coding is not chaos. It just needs a system.

Vibe-coding is interesting because it quickly creates the feeling that there is almost nothing left between an idea and a finished application. You write a prompt, something appears, you adjust the brief, another piece gets created, and things move. That is great. But it is also very easy to end up in a state where every new change breaks the previous one, the app starts to bloat, and you lose orientation.

Illustration for an article about vibe-coding and system-based software development

This is nothing new. Every new programmer has gone through something similar. At the start, you are excited that something is being created, you try many ways of building it, and eventually you reach a point where you can no longer continue. Complexity starts to push back and every new feature breaks the previous one. Some people give up and conclude that programming is not for them. Others start exploring how software is actually developed.

And that is exactly where many people are today when they start building applications with AI tools.

That is why I think it makes sense to return to a simple foundation:

Idea → Specification → Plan → Coding → Testing → Security → Deployment

Not to make development more complicated, but to handle what AI tools now make possible much faster. In my view, vibe-coding is not chaos. Chaos appears only when the system is missing.

Start with the idea, not the code

Right from the beginning, there is no need to find the perfect tool. It is more important to try what fits you best and build confidence in it. Over time, that pays off many times over. Today, the main tools usually cover everything you need. From there, the choice is mostly about preference and budget.

When you have a strong idea, great. Just do not jump straight into code. Write down, at least in a few bullet points, what it should do. How the data enters the system. How you will get data back out. Sketch the basic screens on paper or on your computer and you will notice how many more things come to mind. That is the first step.

It is tempting to skip it and start coding right away because you feel like you already know exactly what you want. But this is precisely where the foundation of the whole solution is created. If you skip it, you are only moving the problems into the next phase.

Specification saves time, energy, and tokens

The next part is creating the specification.

That means writing down how it will be built and in which technologies. The more work you put into it, the better the result. You will save yourself from a lot of dead ends and also from burning through tokens.

You do not need to invent everything yourself. In your tool, you can ask something like:

"I want to build app XY that does this and that. Suggest the most suitable technology, data storage, and proven best-practice approach."

If you want to be more systematic, it helps to use a library or framework that supports the process. For example, I use OpenSpec. I gradually use it to create the individual parts of the application through specifications.

The result is an application description in markdown files that you can review and also edit with AI. For example, by asking:

"You designed it in Python, but I want it in JavaScript. Can you explain the pros and cons?"

or

"You are suggesting MSSQL for storage, but this is a small project. Would SQLite or MySQL be better? Why?"

Anything you do not understand is worth asking about and having explained. Do not design systems for thousands of people right away. You do not need top-tier technology. And if you have programmed before, choose a language where you can at least visually recognize what it is doing.

Why create specifications instead of just saying "implement saving to the database"? Because when you come back later, the chat history is gone. In the specifications, the decisions and the reasons remain recorded.

You can then request new functionality like this:

"Look at the specifications for how we store data in the database and propose a new feature XY."

You can refer to a specific specification or to the whole design history.

I also find Context7 very useful in this phase. When you do not know how to build something in Next.js, for example, you can ask:

"Design an app in Next.js according to best practices, use Context7."

That pulls in documentation and recommendations and helps with the specification. You can ask about many technologies, and later it also helps with the implementation itself. During coding, for example, you can add:

"… and if you do not know, check the docs, use Context7."

And there is a good chance you will get a better result.

Without a plan, the project starts to fall apart

The next part is the implementation plan.

One advantage of OpenSpec is that it also prepares a plan for how the specifications will be implemented, or at least in what order. That matters. Because you do not want to code a website that needs data before the database it reads from even exists.

Again, you do not need to invent everything yourself. It is enough to ask something like:

"Go through the created specifications and suggest the order in which the prepared tasks should be implemented."

At the end, it is worth reviewing the plan at least a little so you understand what you are actually building.

At the end of this first larger phase, it pays to ask a lot of questions:

  • Review all the specifications again and check whether we missed anything.
  • Is everything clear? Can we move to implementation?
  • Are any of the proposed technologies in conflict with each other?
  • Do you see any parts that would be better solved differently than we proposed?

I really think it is worth spending a lot of time here.

Coding comes only as the next step

Then comes the actual coding, meaning the application itself.

At that point it makes sense to tell the tool something like:

"Take the plan and go through the specifications one by one. Implement them. After each smaller part, run a test to check that it works, then commit it with git. Keep going until you finish all the specifications, and if you hit an error, continue with the next part and we will solve the problems at the end."

And then you can go to sleep.

In the morning, you have a lot of new code to test and refine. But expectations need to be set correctly. It simply will not be perfect, and most of it will not work on the first try.

Then the process starts where you take the individual parts, meaning the specifications, and check that they work. You directly ask for changes. For example, change text sizes, add a column to the table, and so on. But if you discover that the application should behave completely differently, it is better to create a new specification from scratch. That prepares another batch of inputs, perhaps again for the next night. You gradually refine, fix bugs, write new specs, and shape the system.

Tokens and models also need a strategy

Token cost is becoming a topic too, so here are a few practical tips.

I switch models in the tool. I do planning in a larger model, for example GPT-5.4 with higher reasoning, but I put this into the prompt:

"Prepare the entire specification so that it will be implemented in GPT-5.4-mini, which is more economical."

Then I switch the model again for implementation and let the actual work run more cheaply.

After each task, I create a new chat or at least compress the context history.

My favorite trick is that I have Qwen Code installed and it is free if you sign in through Qwen OAuth. Then in Codex I ask:

"Take the tasks one by one and have them implemented using qwen code. After completion, do a code review and test that the task works, and at the end commit it."

The higher model handles orchestration and the remaining development runs on a cheaper but still usable model. You do need to think a bit about which data you send, but in development there usually is nothing highly critical or sensitive leaving the system. You can also use a local model here.

At the end, it is worth calling:

"Do a code review of the individual changes and suggest how the implemented tasks could be improved."

You get recommendations, and then you either implement them directly or plan them again with OpenSpec.

If you do not test, you do not have a product

The next step is testing.

When you have more than 50 percent of the application finished, it makes sense to start testing. At this stage, it really pays to do it manually and go through all the variants that a user might enter. Try entering text into the phone field. Put something into email that does not look like email. That is the basic validation on which many other things depend.

It is useful to invent different scenarios where the app might fail and go through them. If it is not just a tool for you, it is even better to sit someone down in front of the screen and let them go through the whole process you intended, while you quietly watch how they use the app.

Comments like "can't you see that?" or "are you blind?" help neither testing nor home life.

It is also useful to use prepared skills for testing. For example, Playwright. It helps with many things that are hard to look up without a development background. If you do not know how to use it, just ask:

"Explain to me how to use the Playwright skill."

And the tool will guide you.

If you do not test, you do not get a product. You just generate more code.

Security does not belong at the end

Even if you are using the app only on your own computer, at some point you may decide it would be useful to put it on the internet. And at that moment, a lot of issues can appear. That is why it is worth doing at least a basic security check.

You can use prepared marketplace skills. The prompt could be something like:

"Use skill ... and identify the security issues in the application. Rank them by severity and explain the risks if I do not fix them."

The result you get is then worth planning with specifications. For example, by asking:

"Use OpenSpec propose and suggest how to remove the individual security issues."

And then have those changes implemented.

Why handle security changes through specifications instead of just saying "fix the bug"? Because when you come back later, all the chat history is gone, but the specifications still contain what was done and why.

Important changes belong in the system, not in one forgotten chat.

Deployment is the moment of truth

The final part is deployment.

That is the moment when "it works on my machine" is no longer enough. The app is almost done and it is time to put it live and make it available to users.

If it is something simple, like a website, the easiest route is often uploading it through FTP and the hosting control panel, including the database. If those are unfamiliar words, just ask:

"What is FTP?"

"How do I upload data to hosting?"

The agent will guide you through it.

It can often do it by itself too. A prompt like:

"Here are the access credentials. Upload the project there and test that everything works."

is already quite realistic for simpler tasks.

Still, it makes sense to understand at least the basics. For example, how to use .env to hide passwords and keys. It sounds like a detail, but later it saves a lot of trouble.

If you are serious about it, sooner or later it pays to look at Docker.

Very simply put, a container is a small computer that already has everything installed that your application needs to run. You can run that container on your own machine or straight on hosting. You can also move it to larger cloud platforms and hosts such as AWS, Azure, Hetzner, and others.

The advantage is that you separate the app from your own computer and its environment. That gives you better control over which data it can access and what it can affect. That is also a basic security benefit.

AI changes speed. The principles of good development stay the same.

This is a short description of an application development workflow that works well if you are serious about vibe-coding. It will save you at least the basic trouble with avoidable problems.

It is not enough to have a good idea. It is not enough to have a good prompt. It is not even enough that AI can write code. The difference appears when you start managing the whole process from idea to operations.

Send me your question

Have a question about the article or want to discuss a related topic? Send me your email and write your question.