Stop Vibe Coding. Start Writing Specs.

11 min read

Last month I asked an AI agent to “build a login page.” It did. It also added a signup flow I didn’t ask for, used a database I don’t use, and named everything in a way that made no sense. Technically it worked. It just wasn’t what I wanted.

That’s the problem with jumping straight to code. The AI fills the gaps with guesses and its guesses are not your intentions.

Spec-driven development fixes this. You write the spec first. Then the AI builds from it. In this blog, let me show you what that means.

First, what is vibe coding?

Vibe coding is when you just prompt to the AI and let it run. You type “build me a login page,” see what comes out, then react. If it’s wrong, you type “no, do it this way” and go again. You’re steering by vibes (YOLO)

It’s fun. It’s fast for small stuff. And honestly it’s how most people start with AI coding but the catch is that the AI is guessing the whole time. It guesses your tools, your structure, your edge cases. For a weekend experiment, fine. For real work that you or a team will maintain, those guesses pile up into a mess.

Why “just build it” goes wrong

When you give an AI a vague prompt, three things happen:

  1. AI guesses the missing details.

  2. AI picks tools and patterns you may not want.

  3. You spend more time fixing its guesses than you saved.

Eg: I once prompted, “add search to my blog” The agent built a full-text search with a new library, extra config, and a caching layer. I just wanted to filter a list of 20 items. A one-line filter would have done it.

The AI wasn’t wrong. My prompt was.

What is a spec?

A spec is a clear description of what you want before any code gets written. But here’s the part people miss: a good spec isn’t just “what the feature does.” It holds the technical details too.

Which API endpoints. Which data model. Which existing library to reuse instead of installing a new one. What the error cases are. How things should be named. The spec is where an engineer writes down all the decisions the AI would otherwise guess. Specs push for team collaboration.

Think of it as the instructions you’d give a new teammate on day one, except you also tell them which tools to use and which patterns to follow. This is known as Spec driven development.

The three parts of a good spec

You don’t need a template with 40 fields. Keep it to three parts.

1. Requirements (what you want ?) : Plain language. What should this do? Who is it for? It is the scope.

Feature: Password resetUser clicks "Forgot password"  
- User enters their email  
- If the email exists, send a reset link  
- Link expires after 1 hour  
- Do NOT tell the user if the email doesn't exist (security)

That last line matters. It’s the kind of detail an AI won’t guess, and it’s exactly where things go wrong.

2. Design (the technical details) : This is the heart of spec-driven development. You write down the real engineering decisions.

Design:  
- Add a POST /reset-request endpoint  
- Generate a token, store it in the tokens table with a 1-hour expiry  
- Send email using the existing mailer service (do NOT add a new library)  
- Add a POST /reset-confirm endpoint to set the new password  
- Hash the new password with the existing bcrypt util  
- Rate limit to 3 requests per email per hour

Every line here is a decision the AI would otherwise guess. Which table. Which mailer. Which hashing util. This is where engineers add the most value, and it’s why the spec is an engineering artifact, not just a product note.

3. Tasks (break it into steps) : Small, ordered chunks. Each one testable.

Tasks:  
1. Create the reset-request endpoint  
2. Add token generation and storage  
3. Wire up the email  
4. Create the reset-confirm endpoint  
5. Add tests for expired and invalid tokens

Now the AI builds one step at a time. You check each step before moving on. Catch a problem at step 2 instead of debugging a giant mess at the end.

How engineers actually benefit

We as an engineer want to code, not fill out documents. But with AI in the loop, the spec is the highest-leverage thing you can write, because it’s what the AI actually builds from. AI is changing the way we engineers used to work.

Think about where your time goes today. You write a prompt, the AI produces something, and then you spend the next hour massaging it into what you meant. The spec moves that thinking to the front. You make the hard decisions once, in plain sight, before a single line of code exists. When you catch a wrong assumption in a ten-line spec, it costs you a sentence. When you catch it in five hundred lines of generated code, it costs you your afternoon.

The spec also keeps the AI honest as agents drift. They wander off and start solving a problem you didn’t ask about. When that happens, you don’t re-explain everything from scratch. You point at the line it ignored and say “this one.”

The spec becomes the shared contract between you and the agent.

And it doesn’t stop being useful once the code ships. A new engineer reads the spec and understands the feature in minutes instead of reverse-engineering it from the code. Reviewers check the implementation against the spec instead of guessing what you intended. And six months later, when someone asks “why is it built this way,” the answer is written down instead of lost in a Slack thread. The spec is documentation that happens to also drive the build.

Where the spec fits in the SDLC

For years the flow was: product writes requirements, engineers write code, and somewhere in between a design doc got written that nobody opened again. The doc was a formality. The code was the truth.

In the AI era that flips. The spec isn’t a formality anymore, it’s the thing that produces the code. So it moves to the center of the process, and the way a team works reorganizes around it.

Step 1: Product still writes the PRD. That part doesn’t change. They describe the what and the why: “users need to reset their password,” the business goal, the user need, no implementation. It’s the problem, not the solution.

Step 2: Then engineers take that PRD and write the SDD, the spec. This is where the thinking happens. They decide the endpoints, the data model, which existing libraries to reuse, the edge cases, and how to break the work into tasks. Everything the AI would otherwise guess gets pinned down here. This is the engineering work now. Not typing out every line, but making the decisions that shape every line.

Step 3: Once the SDD is approved. engineers gives the story to the AI agent and builds it, task by task. Because the real decisions are already made, it isn’t guessing its way through. It’s executing a plan. You review each step against the spec as it goes.

Step 4: when something changes, and it always does, a bug shows up or a requirement shifts, you don’t patch the code and move on. You update the SDD first, then let the agent rebuild from the new version. The spec stays the source of truth. The code is just its latest output.

AI gen; Prompt by human

AI gen; Prompt by human

That’s the mindset shift worth sitting with. The code used to be the thing you protected and the docs drifted out of date. Now the spec is the thing you protect, and the code follows it.

An SDD template you can steal

You don’t need anything fancy. Here’s the skeleton I use. Copy it, fill it in, hand it to your agent.

SDD: [Feature name]  
Author:   
JIRA Number:   
  
1. Context  
Link to the PRD. One or two lines on the problem and who it's for.  
>> Ties to PRD-123. Users forget passwords and have no way to recover  
>> their account without contacting support.  
  
2. Requirements  
What the feature must do. Include the edge cases and the "do nots."  
- User requests a reset with their email  
- If the email exists, send a reset link  
- Link expires after 1 hour  
- Do NOT reveal whether an email exists (security)  
- Rate limit to 3 requests per email per hour  
  
3. Out of scope  
What you are deliberately NOT building. This stops the agent from  
wandering.  
- No SMS reset  
- No "security questions" flow  
- No changes to the existing login page  
  
4. Design  
The technical decisions. This is the part the AI builds from.  
  
**Data model**  
- tokens table: id, user_id, token_hash, expires_at, used_at  
  
**Endpoints**  
- POST /reset-request -> takes email, always returns 200  
- POST /reset-confirm -> takes token + new password  
  
**Reuse (do not add new libraries)**  
- Existing mailer service for the email  
- Existing bcrypt util for hashing  
- Existing rate-limit middleware  
  
**Flow**  
1. /reset-request generates a token, stores the hash, emails the link  
2. /reset-confirm validates token, checks expiry, sets new password  
3. Mark token as used so it can't be replayed  
  
5. Edge cases  
- Expired token -> 400 with a generic message  
- Already-used token -> 400  
- Unknown email -> still return 200 (don't leak existence)  
  
6. Tasks  
  1. Create the tokens table + migration  
  2. Build POST /reset-request with token generation  
  3. Wire up the reset email  
  4. Build POST /reset-confirm  
  5. Add rate limiting  
  6. Tests: expired token, used token, unknown email, happy path  
  
7. Open questions  
Things you haven't decided yet. Answer these before the agent starts.  
- Should reset links be single-use per request, or invalidate all  
older links when a new one is issued?

Two things make this template work.

The Out of scope and Open questions sections are the ones people skip, and they’re the ones that save you.

  1. Out of scope keeps the agent from building things you didn’t ask for. 
  2. Open questions force you to resolve the ambiguity before the AI guesses for you.

And you don’t fill every section for every task. A small change might only need Requirements and Tasks. A gnarly feature needs all seven. Match the spec to the size of the work.

A simple before and after

Before (vibe coding)

Prompt: “Build a to-do app
You get: a to-do app with a framework you didn’t pick, features you didn’t ask for, and no way to know if it matches what was in your head. This is vibe coding. Fast, but a gamble.

After (spec-driven):

Prompt: “Requirements: a to-do app where users can add, complete, and delete tasks. Tasks save to local storage so they survive a refresh. No login needed.

Design: single HTML page, vanilla JavaScript, no frameworks. One tasks array, saved to localStorage on every change.

Tasks: 1) render the list, 2) add a task, 3) mark complete, 4) delete, 5) load and save from localStorage.

You get: what you actually wanted. And when the AI drifts, you point at the spec and say “this line, you missed it.”

Do you always need a spec?

No. And this is important. For a quick script or a throwaway experiment, vibe code it. Just prompt and go. Writing a spec for a 5-line snippet is overkill.

Reach for a spec when:

  1. The task has more than a few steps
  2. You care about specific behavior (security, edge cases, naming)
  3. You’ll come back to this code later
  4. You’re working with a team

If you’d write instructions for a human before handing off the work, write a spec for the AI too.

How to start tomorrow

You don’t need a tool. Open a text file. Before your next real feature, write three short sections: what you want, how it should work (with the tech details), and the steps to get there. Hand that to your AI instead of a one-line prompt. Then watch how much less you have to fix.

I still catch myself vibe coding “just build X” when I’m lazy. Every single time, I pay for it later. The spec takes five minutes. The cleanup takes an hour.

Write the spec. Let the AI build it. That’s the whole idea.


Thank you for reading this. If you like this, then please share in your network . Give a clap, leave a comment.

You can contact me at X or LinkedIn

Happy Learning!!