Back

The anti AI vibe coding guide


Foreword

From here onwards, by “AI” I mean models made by companies like “Anthropic”, “DeepSeek”, “Gemini”, “OpenAI” (in alphabetical order).

What makes this article different?

100s of people have made the same claims of how to vibe code effectively. All of them work, but there’s no reason as to why they work. Additionally, many are just people trying to make a bit from the AI hype train.

I’m coming in as an anti vibe-coding standpoint, trying to help vibe-coders understand why professional developers have mixed stances, and what my 2 cents are in trying to make vibe-coded projects better.

Learn Coding.

Regardless of people saying “Coding is dead”, it isn’t. Surprise surprise, the anti AI developer is claiming that coding isn’t dead. Yes.. and No.

Say I told you to explain how to implement an authentication system for a website if you have never coded or developed something.

Your prompt might look something like: “Make me a website that takes in a username, email and password. It should support login and signup, and should save this data and then let me access the rest of the website. Also make all the other features in the website require login.”

Now even if you’re a developer, you might think this is a decent prompt. I think so to. But there are flaws.

  • What features should be gated?
  • What about forgot password?
  • What the hell should the token be? A JWT?
  • Should I verify the email?
  • How should the frontend save the token? Local storage?
  • How should the backend save the password? Plain text 💀??
  • Should I be able to log in with the username or email or both?
  • Should it be a first name + last name or just username?
  • Is username meant to be unique?

Every single one of these points means the LLM has to make a guess. Storing passwords in plain text for something like a prototype might be fine.. but definitely not for a production application. All of these have their own usecases, and an AI shouldn’t be making the decision. The person making the feature should be.

I like fixing this by adding a clause to my prompt: “Don’t assume anything. Clarify everything. Make smart decisions based on the usecase, but don’t hesitate from asking questions.”

It makes a lot of sense to add this, but I haven’t heard anyone recommend this.

Coming back to the point of learning coding, if you weren’t a developer (or someone in the tech industry), I don’t think you would have thought of all of this. You probably don’t even know what hashing, JWT, “endpoints” even are. That’s why learning to code is still important.

Prompt schematics

I asked people what kinds of prompt they would use to make: “a web application that can display json data in neat tables and graphs and stuff”

It’s a stupid application. But it was to see what their prompting style and what their methods would be to get an LLM to follow instructions strictly.

I asked in a few discord servers, and here are the responses I got:

  1. Get Model A to make a Specsheet. This would contain things like what are the required “commands to pass” (i.e. cargo test, cargo check and cargo clippy for rust), quality gates, project information, and commit style.

  2. Initialise a new project manually, and then just have AI implement each feature one by one.

  3. Use the Test Driven Development (TDD) Skill and have multiple sub-agents run in parallel with specific workflows.

  4. Just prompt a frontier model with the goal and let it do its thing.

Now these are what others are using, what I’ve found to work best for me is what I’m gonna slowly explain through the course of this article so hold on a bit.

Now lets eliminate each of these prompts and analyse whats wrong with them, and where the output quality would roughly stand.

  • The fourth one can easily be eliminated as being too vague. It would come last, and while it might succeed on smaller tasks, it definitely fails on bigger projects.

  • The third one is something I haven’t used, but from my understanding, its inefficient but structured. It burns through a lot of tokens trying to get the code to match the tests since it can’t see the tests.

  • The second one is an amazing method. I’ve used it and it gets the job done really quickly. But personally it’s not a great way to start and is exhausting for the human prompting, since they have to get AI to understand and add each new feature, and then verify it themselves.

  • The first one is by far my favourite, and also the closest to the method I’ve researched. It defines a clear set of rules to follow, and also the project definition is there as well.

The journey of Vibe Coding.

Vibe coding isn’t just prompting AI “Make me a website that can do X using Y” at chatgpt.com

It’s become a mess of different tools like Claude Code, Codex, OpenCode, Amp, Cursor, Trae, VSCode, Zed, and one of the billion other AI Agentic coding providers.

I don’t care which one you use, but you should be using a harness and not copy pasting code into Notepad and then saving it as a .html or a .py file and double clicking the file to run it.

Once you’ve picked your harness, and connected the provider of your choice, the next step is gonna be prompting.

I’m going to vibecode a self hosted openrouter (LLM proxy gateway) in rust, with the UI done in astro.

Step 1: Phasing

I started off by running cargo new and then opening opencode in that directory. Then I gave deepseek-v4-flash (opencode zen free) a description of what I wanted to make:

Make me a backend proxy using Rust Axum Tokio and Sqlx (postgres) for LLM response unification and OpenAI compatible endpoints. The first user should signup and be saved as a Owner and the remaining people should be saved as “Invite Pending”. The admin users can then change their roles to either Admin or User. Both users and admins can use the API proxy but configuration of the providers should be restricted to admins. Plan this out into a phase based approach where each phase is as detailed and is grouped up with relevant tasks.

(The actual prompt was slightly different since I forgot to copy it and I lost it.)

Now If you take a look at the last bit of the prompt, you’ll notice I ask it to plan out phases. This is to reduce token usage since each “Phase” becomes a feature implementation, and hence only that specific feature related code is required to be generated.

After I had it write the files to phases/phase_n.md, the next step came in.

Step 2: Rules

Each project should have a set of rules. This should be separated since it’s something the LLM has to abide by and not actually reference and use as a spec sheet. Putting different things inside different files leads to a well “understood” context window.

Since it was a rust project, I told it to create this rule set:

  • For every feature, there should be relevant unit tests
  • Every feature should have 0 warnings and errors for cargo check, cargo test, cargo clippy
  • Every feature should be built in a scalable manner, and only implement the feature from the relevant phase.
  • Don’t ever use .unwrap() unless there is a valid and safe reason to.
  • Manual modification of Cargo.lock is not allowed.
  • Use cargo add to add packages. Don’t modify Cargo.toml

I added a clause where I told it to also add implementation details to the respective phase document. This is optional.

This was then put into a Rules.md in the project root.

Step 3: Prompt

The same prompt was going to be used multiple times. Read Rules.md, Don’t break the rules, implement phase X, etc. So I had it make a prompt and put it inside AGENTS.md.

“Make me a prompt that will tell the AI Agent to use the rules and accordingly implement the phase.”

This was then saved to AGENTS.md.

Step 4: Implementation

Now the implementation phase begins.

Everything from Step 1 - 3 was done in a single session. In the implementation, for each phase, we will use a new session to minimise the context window to only be the context needed for the specific phase.

Now for each phase you’re implementing:

  • Tell the AI Agent to implement phase X and to read AGENTS.md and RULES.md to understand what phases mean.
  • Once it finishes, verify everything it was meant to implement in the specific phase.
  • Keep prompting it with descriptive error messages (Like I’m getting the error message X in the console when I do Y)
  • Once you’re done with the phase, new session and loop this step.

The results

For the self hosted openrouter in rust, the LLM generated 12 phases, and for 10-11 of the phases, the task was achieved in a single prompt. It may have asked a few questions regarding implementation but the entire implementation was complete in about 13 prompts. 1-2 phases had a bug that required me to tell the AI the bug and it fixed it. All in all, each session used a consistent 40% context window usage.

The UI is still underway, and I still am yet to try and hack the server to see how secure it is. I’ll be writing a blog post on that as well, and no it will not be AI hacking.

The server functions with every single API endpoint working, and the implementation working well. Everything functions as I would have intended it to, and the code’s structuring was pretty decent as well. My only complaint is that they used mod.rs and not the newer rust module format. The module format.


The code is pretty well structured, and I would be happy to work on this codebase manually. However it has a few stupid things like calling reqwest::Client::new() every single time a chat completion request is sent.

You can see what people in the RPLCS (Rust programming language community server) had to say here

I would say that the best advantage of this vibe coded project is the naming and the error messages. They are fairly clear and relevant, without having to manually type the messages.

Theres also things like the OpenAPI route descriptions which are pretty well documented, and hence was easy for me to get started with the frontend UI.

Conclusion

Learning coding is still a good idea if you’re going to vibe code. It’s something that will improve your vibe coded apps due to correct terminology and the right ideology.

Additionally, using a phase based approach and creating multiple new sessions for each project is ideal.

Using git is a must for reverting to working versions or locating the source of the bug, manually or via AI Agents.

Now time for me to scan the backend for vulnerabilities and document my findings on that.