The original is one click away. Open original ↗
Practical vibe coding techniques for better AI-generated code
Executive overview
AI coding tools produce inconsistent results without deliberate structure. Treating vibe coding like engineering — with plans, tests, and version control — yields dramatically better outcomes.
The best vibe coding practices are just good software engineering practices applied to LLM-driven workflows.
Choosing the right tool
- Non-coders: start with Lovable or Replit for visual, UI-first iteration.
- Experienced developers: jump straight to Cursor, Windsurf, or Claude Code.
- Running two tools (e.g. Cursor + Windsurf) in parallel on the same project lets you pick the better result.
Planning before coding
- Before writing any code, use the LLM to produce a comprehensive plan in a markdown file inside the project folder.
- Mark features explicitly as out of scope to prevent scope creep.
- Implement the plan section by section; check each section works before moving on.
- Commit to git after each working section so you can revert cleanly.
Version control is non-negotiable
- Use git religiously — don't rely on built-in revert tools in the IDE.
- Start each new feature from a clean git state.
- After multiple failed prompts,
git reset --hardand feed the final working solution back into the LLM on a clean base. - Accumulating failed attempts produces layered junk code; resetting avoids this.
Writing tests
- Get the LLM to write tests, but push for high-level integration tests over unit tests.
- Simulate end-to-end user flows rather than testing individual functions.
- Tests catch regressions when the LLM silently modifies unrelated logic.
- Write tests before moving to the next feature.
Fixing bugs
- Paste error messages directly into the LLM — no explanation needed.
- For complex bugs, ask the LLM to propose three or four possible causes before writing any fix.
- Reset after each failed fix attempt; do not let fix attempts accumulate.
- Add logging when stuck. Switch models if one fails — different models succeed where others don't.
- Once the root cause is found, reset all changes and give a clean, precise fix instruction.
LLM instruction files
- Write explicit instruction files (cursor rules, windsurf rules, CLAUDE.md, etc.).
- Detailed instructions make the agent significantly more consistent and effective.
Documentation
- Download API docs locally into a project subdirectory rather than pointing the agent at live URLs.
- Instruct the LLM to read docs before implementing anything that depends on them.
Complex new features
- Build complex features as a standalone project in a clean code base first.
- Get a small reference implementation working, then point the LLM at it when integrating into the main project.
Architecture and tech stack
- Prefer modular, service-based architecture with clear API boundaries — easier for both humans and LLMs.
- Avoid massive monorepos with deep interdependencies.
- Mature frameworks with large training datasets (e.g. Rails) produce more reliable LLM output than niche languages.
Useful extras
- Paste screenshots directly into the coding agent to demonstrate UI bugs or share design inspiration.
- Use voice input (e.g. Aqua) to dictate at ~140 wpm — LLMs tolerate imperfect transcription well.
- Refactor frequently once tests are in place; ask the LLM to identify repetitive code.
- LLMs handle non-coding DevOps tasks (DNS, hosting setup, image resizing) well — use them for that too.
- Keep experimenting: model rankings shift weekly; test new releases across different task types.
More like this — when you're ready for early access.
Join the waitlist for a personal account and content recommendations based on what you're working on.
No spam. Unsubscribe at any time.
You're on the list. We'll be in touch before launch.