Skip to main content

A PM's Guide to Vibe-Coding: Requirements First, Code Second

Updated 9 min readMarkdown

For about a year, my team kept a shared resource — meeting rooms — in a spreadsheet and a group chat. Someone would write "Room B, Thursday 2–4pm?" in the chat. Someone else would check the spreadsheet. Someone would forget to update it. And then two teams would show up at the same door at the same time, each holding a laptop and a reasonable claim to the room.

It worked badly, and everyone knew it worked badly. Nobody had time to build a real system for it. And I am a project manager, not a programmer — I hadn't written production code in years.

So I did the thing every PM seems to be doing now: I asked an AI coding assistant to build it for me. I want to be honest about what happened next. The AI did not magically turn my idea into software. It turned my requirements into software — and the difference between those two sentences is the whole story.

The requirements came first

Before I opened the editor, I spent a day writing the rules. Not a PRD, not a forty-page spec — just a list, in plain language, of how the thing had to behave. Four questions did most of the work:

  1. Who can use it? Anyone on the team, no approval needed. If a tool needs a gatekeeper, people go back to the group chat.
  2. When can they book? Within a fixed window ahead of time — far enough to plan, short enough that nobody hoards rooms weeks out.
  3. What happens when two people want the same slot? The second booking fails, clearly, in words a human understands. No silent overwrites, ever.
  4. What happens when someone cancels? The slot frees up immediately, and the system shows it as free. No ghost bookings.

Those four answers became the spine of everything I asked the AI to build. Everything else — the layout, the colours, the buttons — was decoration.

Here is the part nobody warns you about: the AI will also invent rules. Mine did, on the first day. It added an auto-expiry rule I never asked for — unconfirmed bookings would vanish after two hours. It sounded sensible. It was also completely made up, and it would have deleted real bookings made by real people who simply hadn't clicked a confirmation nobody told them about.

So I learned the first real lesson of vibe-coding, and it is a PM lesson, not a coding lesson: every rule in the system must come from your written spec. If a behaviour isn't in the list, it doesn't exist. I added one line to the top of my spec, and it stayed there for the whole build: "Build only the rules written here. Do not add rules of your own."

The rules I insisted on, the ones the AI would never have written by itself, were the boring human ones:

  • One active booking per person per day. Not because the system needs it, but because without it, one organised person books every room and everyone else goes back to the spreadsheet.
  • Every booking shows a name. Not an ID, not an email — a name. When two people collide, they need to know who to talk to. Software can't resolve that conversation; it can only make it possible.
  • The system never moves or deletes a booking silently. If something changes, the person affected gets told. This rule cost me an afternoon of argument with the AI, which kept trying to "helpfully" resolve conflicts on its own. I kept deleting that help.

Those three rules are the whole difference between a tool people trust and a tool people route around. The AI was very good at the first kind of rule — the logic. It was blind to the second kind — the trust. That part was my job, and no prompt would have done it for me.

The workflow: small prompts, real acceptance tests

The tools were deliberately boring: an AI coding assistant in my editor, plain HTML, CSS and JavaScript with no framework, a private repo for version control, and Cloudflare Pages for hosting. Nothing exotic. The point of the exercise was the method, not the stack.

I wrote prompts the way I write tickets: context first, then the rule, then what "done" looks like — one feature at a time. I never asked for the whole app at once. Every prompt ended with the same acceptance line: "Done means I can run this end to end with test names and the result matches the rule above."

"Test names" is doing a lot of work in that sentence. I never tested with real people or real bookings. I invented a small cast — test users with obviously fake names — and ran the same manual checklist after every single change:

  • Book a room. It works.
  • Book the same room at the same time again. It must fail, clearly.
  • Cancel a booking. The slot must show as free immediately.
  • Book a time in the past. It must fail.

If any step failed, the feature wasn't done, no matter how good the code looked. That checklist caught more problems than any code review would have, because I was testing behaviour, not code — which is exactly what a PM is good at.

Pitfall 1: The AI invented a rule

Symptom: A test booking disappeared. No error, no message — it was just gone.

Cause: The auto-expiry rule from the first day. I had told the AI to remove it, and it said it had. It had removed it from one place and left it in another.

Fix: I stopped trusting "done" and started trusting the checklist. I also started keeping a written inventory of the rules — one numbered list, in a file the AI could read — and made the AI check its work against it. "Rule 7 says bookings never expire. Find every place the code expires a booking." That kind of prompt works. "Make sure there are no bugs" does not.

Pitfall 2: The happy path only

Symptom: The first version looked finished. You could book a room, see it on the calendar, feel productive. Then I tried to cancel a booking and there was no way to do it. No button, no flow, nothing.

Cause: I had described the sunny-day flow first — the booking — and the AI built exactly what I described and stopped. It had no reason to build cancellation, because I hadn't mentioned it yet.

Fix: I rewrote the spec so the unhappy paths came before the features: cancel, conflict, no-show, booking in the past. Every feature prompt now starts with "here is what can go wrong" and only then "here is what it should do." It feels backwards. It works.

Pitfall 3: The fix that broke something else

Symptom: I asked the AI to fix the conflict check. It did. It also broke the date picker, which had been working fine for a week.

Cause: The AI rewrote a whole file to fix three lines. A whole-file rewrite is a whole-file opportunity to break things.

Fix: Two habits. First, I ask for the smallest possible change: "change only the conflict check function, nothing else." Second, I keep a dated snapshot of the working code before every big change, so I can roll back in a minute instead of debugging for an hour. The snapshot habit has saved the project twice. The "smallest change" habit has saved it a dozen times.

One small piece of the actual logic, to show how unremarkable the code is. The whole conflict check is this:

// Two bookings conflict if their time ranges overlap
function hasConflict(existing, next) {
  return next.start < existing.end && existing.start < next.end;
}

Four lines. The hard part was never the code. The hard part was deciding that this — and only this — counts as a conflict, and writing it down before anyone typed anything.

Data and review: what I can and can't say yet

Usage numbers: to be added. I don't publish internal figures, and I won't invent any here. What I can say, qualitatively, is this: the spreadsheet is gone, the group chat stopped being the source of truth, and the complaints about two teams at one door stopped. That's a real outcome and I'm labelling it as what it is — observed, not measured.

What I cut, and why:

  • Auto-approved recurring bookings. Sounded useful. Then the edge cases multiplied: what if the room is closed that day, what if the person leaves the team, who owns a booking that repeats forever? Cut it. A simple tool that works beats a clever tool that needs a manual.
  • A waitlist. Nobody asked for it after launch. A feature nobody asks for is a feature you maintain for free. Cut it.
  • Calendar sync. Scope creep, honestly. It would have doubled the build for a problem nobody had yet. If people ask for it three times, I'll build it. They haven't.

Cutting is the PM's real contribution to a vibe-coded project. The AI will happily build everything you mention. Your job is to decide what not to build.

Three things I'd tell any PM who wants to try this

  1. Write the rules before you write the prompt — if you can't state a rule in one sentence, the AI can't build it either.
  2. Test with fake names and fake data, end to end, after every single change — never on the real thing.
  3. Keep a dated snapshot before every big change — the AI will eventually break something that worked.

None of those is about code. All three are things PMs already know how to do. That's the actual insight here: vibe-coding didn't make me a programmer. It gave me a way to apply the skills I already had — requirements, acceptance criteria, and saying no — directly to software.

This is part 1 of a 3-part series: requirements, workflow, review. Part 2 goes deeper into the workflow — the prompt patterns that worked, and the test checklist I still use. Part 3 is the honest review after a month of real use.

If you want the rest, my weekly newsletter is Output Mode on Substack — a new issue every Saturday.

About the author

  • I'm Wayfinder, a project manager. I build small internal tools with AI and write about what it gets wrong — and right. My weekly newsletter is Output Mode on Substack.

No comments yet. Be the first to comment.