Vibe coding has become one of the most visible concepts in AI-assisted software development. It is a very good method for testing things quickly. When a new model is released, when a new GenAI product appears, or when we want to turn a product or feature idea into something tangible fast, vibe coding works really well. But inside a real product development environment, it can easily become a way of breaking things, slowing things down, or creating confusion.
So first, what is vibe coding?
Vibe Coding The term vibe coding entered our lives through a tweet by Andrej Karpathy, Tesla’s former Director of AI and Autopilot, on February 3, 2025.
He starts with the line: “There’s a new kind of coding I call vibe coding where you fully give in to the vibes…” and describes a workflow where development happens less by writing code directly and more by talking to the model. In the rest of the tweet, he explains that he often accepts changes or diffs without reviewing them carefully, pastes error messages directly into the model and expects it to fix them, and allows the codebase to grow to a point where even the developer may no longer fully understand it. He also points out that this approach can work surprisingly well for small and fast-moving projects.
Vibe Coding Process Karpathy is right about that. For small and quick projects, vibe coding can work surprisingly well. In practice, the flow usually looks like this: the user gives the LLM a general prompt and leaves most of the specification decisions to the model. Something like: “Build me a weather website.” This is also close to one-shot prompting. The AI generates code, the user looks at the output, and if it does not match what they had in mind, they start correcting it: “No, I did not mean this,” or “Why does it only show one country?” or “Change this part.” Over time, through repeated back-and-forth, the project slowly gets closer to what the user actually wanted.
That sounds fine until you imagine it inside a real software development lifecycle.
Imagine working on a serious project and deciding to use vibe coding in the middle of an existing product. You jump in directly, start prompting, and the conversation turns into a chain of reactions: “No, that is not what I meant.” “Why did you build it like this?” “Fix this.” “That is not what I was trying to say.” Unless you are testing a model, exploring a new AI product, or building a quick prototype, this kind of development can easily create chaos. As I said at the beginning, it is a great way to test ideas quickly, but not a reliable way to build stable product systems.
To understand why, it helps to remember how software was developed before AI became part of the workflow.
If we imagine this inside the Software Development Life Cycle, it would likely create chaos. Imagine working on a serious project and suddenly deciding, “let me try vibe coding in this ongoing project,” and diving straight into it. Conversations would probably turn into something like: “no, no, that’s not what I meant…”, “why did you build it like this?”, “fix this!”, “that’s not what I was trying to say.” As mentioned at the beginning of the article, unless you are testing a model, trying a new GenAI product, or quickly experimenting with a prototype, vibe coding will probably end up breaking things.
So let’s remember our old friend, the Software Development Life Cycle, and recall what software development looked like before AI became part of the process.
Software Development Life Cycle (SDLC) In the Software Development Life Cycle, an idea that comes from a real need first enters a planning and design phase. In this phase, the team defines how the product should behave, what it should look like, and what its specifications are. Based on that, they form a clearer picture of what will actually be built.
After that, implementation begins. But implementation does not happen blindly. It happens together with testing. As the product is implemented, it is also continuously tested and improved. This is also why this approach is closely tied to incremental development. When implementation and testing mature together, the product reaches deployment. After deployment, the software continues to be maintained over time.
Traditional SDLC Process So what is the difference between this and vibe coding?
The main difference is that in SDLC, we first know what kind of software we are trying to build. There is a planning and design phase that defines this clearly. Then, based on that plan, the product is developed and tested incrementally.
In vibe coding, the opposite often happens. The product is shaped by “the vibe.” The user may not even fully know what they want from the first prompt. The method depends on the hope that the final result will eventually converge toward the idea in the user’s head. It leaves a lot of room for the LLM to fill in the blanks.
And because LLMs cannot read minds, that becomes a problem.
So what should we do if we want to avoid AI making wrong assumptions and building the wrong thing?
What if, instead of leaving the blanks open, we combine AI with the more structured logic of traditional SDLC from the very beginning?
That is where spec-driven development comes in.
Spec-Driven Development The purpose of spec-driven development is to give the LLM a clear direction and clear boundaries before implementation starts. Instead of letting the model guess the missing parts, as in vibe coding, we first define what we are building as explicitly as possible. Of course, this does not mean the developer already knows everything. Unknowns can still be explored through discussion with the LLM, or by using the model to surface industry best practices. That is part of the process too.
But the key difference is this: in vibe coding, code is the starting point. In spec-driven development, the starting point is the specification.
This is why spec-driven development can be seen as AI-assisted software development combined with traditional SDLC principles. In some sense, it feels like test-driven development and behavior-driven development on steroids. Before asking the AI to generate code, the developer first asks it to produce a structured specification based on desired behaviors, rules, and constraints.
In vibe coding, generating the code is the immediate starting point. In spec-driven development, the specification itself becomes the primary artifact, which then safely drives all downstream work, including actual code implementation, documentation, and testing
That specification becomes the primary artifact.
It acts like a contract that defines the project’s structure, technical direction, constraints, implementation tasks, and even testing expectations before any code is written.
The process usually works like this:
Spec-Driven Development Process
- Prompt Spec In the first step, the developer describes the product or feature they want to build as clearly as possible.
This is basically a product specification prompt.
For example:
I want to design a weather web application. Do not generate code yet.
Your task is to create a detailed specification document.
Context:
The application should display weather based on the user’s current location.
Users should be able to search for cities manually.
The application should show both daily and weekly forecasts.
Please generate a structured specification including:
-
Product goal
-
User stories
-
Functional requirements
-
Non-functional requirements
-
API requirements
-
UI behavior
-
Edge cases
-
Acceptance criteria
-
Possible architecture options
Do not implement anything yet. Only produce the specification.
The goal here is not just to give the model a vague idea. The goal is to define a clear problem and a clear scope.
At this point, the developer can still talk with the LLM to shape unclear boundaries, discuss tradeoffs, and clarify decisions. This is essentially the planning and design phase. Most of the process happens in conversation. Code generation does not happen yet.
- Requirements Generation Based on that initial specification prompt, the LLM generates a structured requirements document.
Instead of producing code, the model translates the product idea into a clear list of system capabilities and constraints. In other words, it breaks down what the system must do.
For example, the requirements generated for the weather application might look like this:
Detect the user’s current location using the browser’s geolocation API Allow users to search for a city manually Display current weather conditions Provide a 7-day forecast Integrate with an external weather data API Present the data through a simple, responsive UI At this stage, the developer does not implement anything yet. The goal is simply to review whether the generated requirements correctly represent the intended product.
- Validation The critical question at this point is:
“Do these requirements actually represent what I want to build?”
If the answer is no, the developer edits the requirements and the model regenerates them until the scope is correct.
This is one of the biggest differences from vibe coding.
In vibe coding, misalignment usually appears after code is already generated. The developer then spends time correcting the model’s assumptions through repeated prompts.
In spec-driven development, that misalignment is detected much earlier, at the requirements level, before any implementation begins.
- Edit and Design Once the requirements accurately reflect the intended product, the process moves into editing and technical design.
Here, the developer and the model refine the requirements and begin defining the system architecture.
Questions like these start to become clear:
Which framework should be used for the frontend? Is a backend service required? Where should weather data be stored or cached? How should the weather API integration work? What should the system architecture look like? In vibe coding, these decisions are often filled implicitly by the model and sometimes randomly.
In spec-driven development, these blanks are filled deliberately and explicitly before any implementation begins.
- Second Validation After the architecture and technical design are defined, the developer performs another validation step:
“Will this architecture and plan actually produce the product I want?”
If the answer is no, the process loops back to the editing and design phase.
Once again, no code is written yet. The goal is to reduce ambiguity as much as possible before the implementation stage.
- Implementation Only after the requirements and architecture are fully defined does the implementation phase begin.
At this point, the LLM can generate code. But unlike vibe coding, it is no longer guessing how the system should behave.
Instead, the model is implementing code within a clearly defined specification and architecture.
This changes the role of AI significantly. Instead of acting like an unpredictable builder, it becomes a structured implementation accelerator.
- Controlled Edit Loop After implementation, changes and refinements can still happen.
However, these edits are no longer random reactions to unexpected outputs, as often happens in vibe coding.
Instead, every change is evaluated against the specification.
This keeps the workflow anchored to a known plan and ensures that iteration remains aligned with the original product intent.
In short, vibe coding is great for exploration, experimentation, and fast prototyping. But when the goal is to build reliable products, structure still matters. By grounding AI-assisted development in clear specifications and SDLC thinking, we can keep the speed of AI without losing control of the system we are actually trying to build.