From Vibe Coding to Agentic Engineering with Claude Code
You write a prompt, hand it to your coding agent, and wait. A few minutes later, you get back… something. Maybe it compiles. But it ignores half your requirements, invents an abstraction you never asked for, or quietly breaks a pattern the rest of the codebase depends on. So you re-prompt. And re-prompt again. And burn through the context window before you’ve shipped anything.
If that loop feels familiar, the problem usually isn’t the model. Left to guess, a Claude Code session fills the gaps you didn’t realize you’d left open: ambiguous requirements, unclear scope, missing acceptance criteria, and no way for it to verify its own work.
The fix isn’t a cleverer one-off prompt. It’s a repeatable process around the prompt. In this blog, I am going to show you the three-phase Claude Code workflow that I follow whenever I’m working on a coding task:
Thanks to this three-phase process, I am seeing more coding sessions end up in implementing what I need while also avoiding frequent long session runtimes, wasted sessions and context window overflows. Adopting this process shifts you from Vibe Coding to Agentic Engineering, and it’s the difference between hoping for good output and engineering it.
Vibe Coding vs. Agentic Engineering
Vibe Coding is the now-common practice of prompting an agent, skimming the result, accepting it if it looks about right, and moving on. The problem shows up the moment the code has to live in a real codebase: the agent fills any ambiguity with guesses, and you inherit whatever it guessed.
Agentic Engineering is the opposite stance. You treat the coding agent as a capable but literal collaborator and keep the engineering disciplines that earned their place over decades, such as clear requirements, a plan, tests, verification, and review. The agent does more of the typing; you stay responsible for the engineering.
Here’s the contrast at a glance:
Vibe Coding<br>Agentic Engineering
Requirements<br>Implied in a one-line prompt<br>Stated explicitly, with scope and intent
Planning<br>None (straight to code)<br>A plan you review before any coding starts
Verification<br>“Looks right”<br>Tests and acceptance criteria that the agent must meet
Review<br>Skimmed or skipped<br>Code review and a walkthrough before merge
Best for<br>Prototypes, throwaway scripts<br>Code that ships and has to be maintained
The three-phase process below is what Agentic Engineering looks like in day-to-day practice.
Start with a Structured Code Prompt to Capture Intent
A good code prompt gives the coding agent a single task with a well-defined scope and verification criteria. Here’s a prompt template you should copy and fill in before every coding task:
[One imperative sentence describing the task.] [One or two sentences<br>on why... the intent behind it.]
Before making any changes, read [relevant files, modules, or patterns<br>to reference].
The solution must [constraint], [constraint], and [constraint]. Do not<br>touch [out-of-scope items].
Write [testing expectations -- e.g., "unit tests for any new logic"]<br>and ensure the existing suite passes. The task is complete when<br>[verifiable criterion] and [verifiable criterion].<br>Instead of a one-line task statement, this prompt template encourages you to think about and communicate clearly:
A single, imperative task statement. One sentence, active voice, no ambiguity. "Add pagination to the /users endpoint," not "It would be good to handle large user lists maybe."
The intent behind the task. A brief "why" helps the agent make sensible judgment calls when it hits edge cases you didn't anticipate. "…so the endpoint doesn't time out on large datasets."
Pointers to relevant context. Name the specific files, modules, or existing patterns the agent should read before touching anything. Don't make it go hunting.
Constraints. Technical, stylistic, or operational limits the solution must respect — e.g., "don't change the public API surface", "follow the error-handling pattern in auth.ts", "no new dependencies".
Explicit out-of-scope items. Anything adjacent that a reasonable agent might assume is fair game. Being explicit here prevents well-intentioned over-reach.
Testability expectations. Should the agent write new tests, update existing ones, or just verify the suite still passes? Left unspecified, this is a common source of inconsistent output.
Verifiable acceptance criteria. Each criterion should be checkable without human judgment — a passing test, a specific curl response, a lint run with no errors. "It should work correctly" is not a criterion.
Here is an example prompt written using this template:
Add offset-based pagination to the `GET /users` endpoint. The<br>endpoint currently returns all users in one query, causing production<br>timeouts as the table has grown past 500k rows.
Before making any changes, read `src/routes/users.ts`, the existing<br>pagination pattern in `src/routes/posts.ts`, and the `paginate()`<br>helper in...