Vibe Coding Fundamentals & AI-Driven Development
"Vibe coding" — describing what you want and letting AI write it — went from meme to daily practice fast. This chapter separates the useful core from the hype: what it is, where it genuinely accelerates you, where it quietly creates liabilities, and the disciplines that keep AI-generated code trustworthy.
AI coding assistants (Claude Code, Cursor, Copilot, and others) can write, explain, and refactor code with you. Used well they're a huge accelerator; used blindly they introduce subtle bugs. This section covers the tools and — more importantly — the habits that make AI-assisted coding safe and productive.
The words you'll hear (in plain terms):
| Term | What it actually means |
|---|---|
| AI-assisted development | coding with an AI helper that suggests, writes, or edits code. |
| pair programming | two 'developers' working together — here, you + the AI. |
| autocomplete vs agent | inline suggestions vs. an AI that edits files and runs commands. |
| verification | checking the AI's output (read it, run tests) instead of trusting it. |
| prompt / context | what you tell the assistant + the code it can see, which shape its output. |
What you need before starting:
- Basic programming experience so you can judge the AI's output.
- The Claude Code intro (C3) pairs well with this section.
- The relevant tool installed (or read along to compare them).
New to the topic? Read this box, then take the chapters in order — each section is tagged essential → expert so you always know the depth you're at.
Learning objectives
- Define vibe coding and AI-driven development, and where each fits.
- Explain the spectrum from autocomplete to fully agentic coding.
- Apply the core loop: intent → generate → verify → refine.
- Name the real risks — trust, security, skill atrophy — and how to manage each.
- Write prompts and set up context that make AI coding tools reliable.
What "vibe coding" actually is essential
The term (coined in early 2025) describes coding by describing intent in natural language and letting an AI generate, run, and iterate on the code — often without reading every line. At its loosest it means "trust the vibes, ship what works." That's fine for a throwaway prototype and dangerous for production. The useful reframe: vibe coding is a spectrum of how much you delegate, and the skill is choosing the right point on it for the stakes.
The delegation spectrum essential
AI coding tools sit at increasing levels of autonomy. Knowing which level you're operating at tells you how much verification you owe.
First, what is vibe coding? It means describing what you want in plain English and letting an AI write the code — sometimes without reading every line. This picture shows that "letting the AI do it" is not one thing but a sliding scale of how much work you hand over. Read the line from left to right: the further right, the more the AI does on its own.
- The horizontal line is the scale of delegation — how much you trust the AI to do without you. Each coloured dot is one level, labelled above it, with a short hint below.
- Autocomplete (far left, green): the AI finishes the single line or block you're already typing — the smallest step, like a smarter tab-complete.
- Chat / edit (blue): you ask it questions and it edits code on request — the note "you drive" means you're still steering every move.
- Agent (purple): now it changes many files and even runs commands by itself ("multi-file, runs") — you're supervising, not typing.
- Autonomous (far right, amber): you hand it a whole task and it works largely on its own.
- The line of text at the bottom is the whole point: more delegation → more verification you owe. The more the AI wrote, the harder you must check it before trusting it, because you wrote less of it yourself.
In short: There's no "best" spot on this line — pick the level that matches the stakes. A throwaway script can sit far right; code that ships to real users belongs left, where you check more.
The core loop: intent → generate → verify → refine essential
Every productive AI-coding session, at any autonomy level, runs the same loop. The one step people skip — verify — is the one that separates shipping from shipping bugs.
This is the repeating cycle every good AI-coding session follows, no matter which tool you use. Read the four boxes left to right, then notice the curved arrow underneath that loops back to the start — that's why it's called a loop, not a straight line.
- Intent (first box): you say clearly what you want — the goal, any rules, and what "done" looks like. Vague intent gives vague code.
- Generate: the AI writes the code from your intent. This is the step people think is the whole job — it isn't.
- The straight arrows between boxes show the normal forward flow: intent leads to generate, which leads to verify, which leads to refine.
- Verify (shown in amber, the emphasised box): you check the result — read it, run it, run tests. The red caption warns this step is NOT optional: skipping it means you're "gambling," not coding.
- Refine: you sharpen your request based on what you saw, then the curved arrow at the bottom carries you back to Intent to go round again. Each lap gets the code closer to what you actually meant.
In short: The one habit that separates shipping working software from shipping bugs is never skipping Verify. If you remember one thing from this diagram, remember that the loop always passes through the amber box.
| Step | What good looks like |
|---|---|
| Intent | Specific goal + constraints + "done" criteria — the Chapter 2 prompt discipline, applied to code |
| Generate | Let the tool write it; give it the right context (see §Context below) |
| Verify | Read the diff, run it, run tests, check edge cases — proportional to the stakes |
| Refine | Correct the intent (not just "no, try again"); the loop converges when intent is sharp |
Where it accelerates you — and where it doesn't intermediate
| AI coding shines at… | AI coding struggles with… |
|---|---|
| Boilerplate, scaffolding, config | Novel algorithms & subtle logic |
| Familiar patterns in popular languages | Obscure libraries / niche domains (little training data) |
| Tests, docs, refactors with clear intent | Deep architecture decisions |
| Explaining unfamiliar code | Debugging where the root cause isn't in view |
| Prototypes & one-off scripts | Security-critical or high-blast-radius code |
The real risks intermediate
These aren't reasons to avoid AI coding — they're the things a professional manages deliberately.
| Risk | What it looks like | How to manage it |
|---|---|---|
| Trust / correctness | Confident code that's subtly wrong; passes a glance, fails an edge case | Verify proportional to stakes; tests are your safety net |
| Security | Injected vulnerabilities, hardcoded secrets, unsafe defaults | Review security-sensitive code line by line; scan; never trust generated auth/crypto blindly (T1) |
| Skill atrophy | You can generate it but no longer understand it | Read what you accept; understand before you ship; use it to learn, not to avoid learning |
| Maintainability | Fast-generated code you can't debug or extend later | Own the code as if you wrote it — because you're responsible for it |
| Hallucinated APIs | Calls to functions/packages that don't exist | Run it; the compiler/tests catch these fast |
Making AI coding tools reliable intermediate
Tool output quality is mostly a function of the context and intent you give it — the same lesson as prompting (Chapter 2) and Claude Code's CLAUDE.md (C3). These habits transfer across every tool in this module.
| Habit | Why it works |
|---|---|
| Give it your conventions | A project rules file (CLAUDE.md, .cursorrules, etc.) stops it guessing your style, test cmd, and no-go zones |
| Be specific about intent | "Add a --json flag that prints the result as JSON, with a test" beats "make it output JSON" |
| Point at the right files | Relevant context in, relevant code out; irrelevant context dilutes it |
| Ask for a plan first on big changes | Cheaper to redirect a plan than a 12-file diff (C3) |
| Tell it to verify | "Run the tests and fix failures before finishing" turns a generator into a checker |
Common pitfalls advanced
| Pitfall | Fix |
|---|---|
| Skipping the verify step | Read, run, and test proportional to the stakes — always |
| Prototype-grade trust on production code | Match rigor to blast radius; own every shipped line |
| Trusting generated auth/crypto/security code | Review it line by line; scan; never ship it unread (T1) |
| Vague intent ("make it better") | Specific goal + constraints + done-criteria |
| Accepting code you don't understand | Understand before you ship; you own it either way |
| No project rules file | Give the tool your conventions once, reuse every session |
Exercises advanced
Exercise V1.1 — Locate yourself on the spectrum
Context: Knowing your own delegation habits is the first step to calibrating them. Placing real tasks on the spectrum reveals whether you over- or under-verify for the stakes.
Your task: For three recent coding tasks, place each on the delegation spectrum (autocomplete → autonomous) and say what verification the stakes actually demanded.
Requirements:
- Place each of three real tasks on the autocomplete–autonomous spectrum
- State the verification level the stakes actually demanded for each
- Judge whether you were over- or under-verifying on any of them
- Tie the verdict back to how cheaply each result could be checked
💡 Hint: Compare the autonomy you used against the verification the stakes deserved — the gap is your miscalibration.
Exercise V1.2 — Run the loop deliberately
Context: The fastest way to feel why verify is non-negotiable is to run the same feature twice: once accepting the first output unread, once through the full loop. The difference is usually a hidden edge-case bug.
Your task: Pick a small feature and do two passes — one accepting the AI's first output unread, one running the full intent→generate→verify→refine loop — then compare.
Requirements:
- Run pass 1: accept the first generation without reading it
- Run pass 2: run the full loop with real verification and refinement
- Compare on bugs, edge cases, and how well each matched your actual intent
- Draw the conclusion about why the verify step is non-negotiable for anything real
💡 Hint: The unverified pass usually looks fine and hides one edge-case bug — the loop catches it exactly at the verify step.
Show what to look for
The unverified pass usually looks fine and hides an edge-case bug or a mismatch with what you meant. The verified loop catches it in the "verify" step — which is exactly why that step is non-negotiable for anything real.
Exercise V1.3 — Write a project rules file
Context: A project rules file is the reusable context that makes any AI coding tool behave like it knows your project. Writing one now powers the rest of the V2–V5 exercises.
Your task: For a project you know, write the rules file you'd give any AI coding tool.
Requirements:
- Include the test command and the lint command
- Include at least two project conventions
- Include one ‘never touch this’ rule
- Keep it reusable — this same file will power the V2–V5 exercises
💡 Hint: Encode your project's specifics (commands, conventions, no-go zones), not generic best practices the tool already knows.
🪜 Practice ladder beginner → industry
Six graded exercises, easy to real-world. Try each before opening its solution.
Context: Every AI coding workflow runs the same loop, and each step has one thing the tool cannot supply for you. Naming them is how you spot which step you're skipping when things go wrong.
Your task: State the four steps of the vibe-coding core loop and, for each, name the one thing you must supply that the tool cannot.
Requirements:
- List the loop: intent → generate → verify → refine
- For intent, supply a precise, testable description of ‘done’
- For generate, supply the context (files, constraints, examples) the model needs
- For verify, supply the judgment on whether it meets intent and is correct
- For refine, supply the specific correction, not ‘try again’
- State that the loop fails when you skip verify and let generated code accumulate unchecked
💡 Hint: The tool owns generation; you own intent and verification — map each step to which side supplies it.
Show solution
The loop is intent → generate → verify → refine.
| Step | You must supply |
|---|---|
| Intent | A precise, testable description of what ‘done’ means |
| Generate | The context (files, constraints, examples) the model needs |
| Verify | Judgment: does this actually meet the intent & is it correct? |
| Refine | The specific correction, not ‘try again’ |
The tool generates; you own intent and verification. The loop fails when you skip verify and let generated code accumulate unchecked.
Context: Delegation should scale with how cheaply you can verify the result. Matching the level of autonomy to the task is the difference between acceleration and a mess.
Your task: For autocomplete, chat/scoped-edit, and autonomous-agent modes, give one task each where that level is the right amount of delegation.
Requirements:
- Autocomplete: a task verified instantly as you read it (e.g. familiar boilerplate)
- Chat/scoped edit: a bounded change you can diff and review in one pass (refactor a function, write a test)
- Autonomous agent: a well-specified, low-risk, test-covered multi-file chore with contained blast radius
- State the principle: delegation scales with how cheaply you can verify — high autonomy on unverifiable work is where it goes wrong
💡 Hint: Pick the level by asking how fast you can check the output, not how much you'd like to hand off.
Show solution
| Delegation level | Good-fit task | Why |
|---|---|---|
| Autocomplete (line/block) | Filling boilerplate you already know the shape of | Verification is instant — you read the line as it appears |
| Chat / scoped edit | Refactor a function, write a test, explain code | Bounded change you can diff and review in one pass |
| Autonomous agent | Well-specified, low-risk multi-file chore (rename, migrate a pattern) with tests | Verifiable by the test suite; blast radius contained |
Principle: delegation should scale with how cheaply you can verify the result. High autonomy on unverifiable work is where vibe coding goes wrong.
Context: The most dangerous vibe-coding pitfall is accepting code you don't understand: it compiles, the demo works, it merges — and no one can debug it later. The guard is a concrete habit, not good intentions.
Your task: Pick the most dangerous common pitfall and describe the concrete habit that guards against it.
Requirements:
- Name the pitfall: accepting code you don't understand
- Describe the ‘explain-back’ gate before accepting a non-trivial generation
- The gate requires you to state what it does line-by-line, what inputs break it, and why this approach over the obvious alternative
- If you can't explain it, you don't merge — you ask the tool to explain, add a pinning test, or rewrite it simpler
- Explain that the habit turns generated code into understood code, the only kind you can maintain
💡 Hint: The test is whether you could defend every line in review as if you'd typed it yourself.
Show solution
Most dangerous pitfall: accepting code you don't understand. It compiles, the demo works, so it merges — and no one on the team can debug it later or spot that it silently mishandles an edge case.
Guard: the ‘explain-back’ gate. Before accepting a non-trivial generation, require yourself to state (a) what it does line-by-line, (b) what inputs break it, and (c) why this approach over the obvious alternative. If you can't, you don't merge it — you ask the tool to explain, add a test that pins the behavior, or rewrite it simpler.
The habit turns generated code into understood code, which is the only kind you can maintain.
Context: A weak prompt costs you four rounds of iteration; a reliable prompt front-loads the verification criteria so the first generation is already checkable. Seeing the before/after makes the payoff concrete.
Your task: Rewrite the weak request ‘write a function to parse the file’ into a reliable prompt and explain what each addition buys.
Requirements:
- The rewrite pins the signature and return type (removes shape ambiguity)
- It specifies explicit error behavior for the edge cases you'd otherwise re-prompt for
- It encodes non-functional constraints (e.g. stream, don't load whole file)
- It asks for tests so verify becomes a one-command check, not a read-through
- Explain what each addition buys in fewer iteration rounds
💡 Hint: A reliable prompt states the contract and the acceptance test up front so the first output can be checked, not just read.
Show solution
Before: ‘write a function to parse the file’ — ambiguous format, no contract, no error behavior. You will iterate 4 times.
After:
Write parse_orders(path: str) -> list[Order].
- Input: a CSV with headers id,customer,total_cents (total_cents is an int).
- Return a list of Order dataclasses (define it).
- Skip rows with a missing id; raise ValueError on a non-integer total_cents.
- Do not read the whole file into memory; stream line by line.
- Include a docstring and 3 pytest cases: happy path, missing id, bad total.| Addition | Buys |
|---|---|
| Signature + return type | Removes shape ambiguity |
| Explicit error behavior | Pins the edge cases you'd otherwise re-prompt for |
| ‘stream line by line’ | Encodes the non-functional constraint (memory) |
| ‘3 pytest cases’ | Makes verify a one-command check, not a read-through |
A reliable prompt front-loads the verification criteria so the first generation is checkable.
Context: When a team adopts AI coding tools, the risk isn't slower typing — it's unowned, untested, unreviewable code slipping in under ‘the AI wrote it.’ A short PR standard keeps the velocity without the erosion.
Your task: Write the 5-point PR standard that keeps velocity without eroding code quality as a team adopts AI coding tools.
Requirements:
- Author owns it fully — ‘the AI wrote it’ is not a review defense
- Tests are mandatory for generated logic (generation makes them cheap)
- No unexplained code — if a reviewer asks ‘why?’ and the author can't answer, it doesn't merge
- Diffs must be reviewable — reject giant agent dumps, require scoped commits
- Secrets & licensing check on generated code
- Explain that the standard keeps the gain (fast authoring) while blocking the loss (unowned/untested/unreviewable code)
💡 Hint: Each rule targets one specific way generated code erodes quality — ownership, testing, understanding, reviewability, and provenance.
Show solution
- Author owns it fully. ‘The AI wrote it’ is not a defense in review; the human author is accountable for correctness as if hand-written.
- Tests are mandatory for generated logic. Generation makes writing tests cheap, so there is no excuse — behavior must be pinned.
- No unexplained code. If a reviewer asks ‘why this?’ the author must answer; if they can't, it doesn't merge.
- Diff must be reviewable. Reject 2000-line agent dumps; require scoped, reviewable commits even if generated.
- Secrets & licensing check. Scan generated code for hard-coded secrets and verbatim-copied licensed snippets.
The standard keeps the gain (speed of authoring) while blocking the loss (unowned, untested, unreviewable code).
Context: ‘Works in the demo’ optimizes for the happy path; production is defined by the paths the demo never hit. Rescuing a vibe-coded prototype is an assess-then-harden job, not a blind rewrite.
Your task: Give the assessment plan and hardening checklist for taking a vibe-coded prototype that demos perfectly to production.
Requirements:
- Assess first: map what exists, list actual features, and separate understood parts from ‘magic’ (highest risk)
- Find the missing edges the demo skipped: bad input, empty state, concurrency, network failure, large inputs
- Harden across correctness (tests over real behavior before changing anything), input handling, secrets/config, failure modes, observability, and data safety
- State the lesson: vibe coding defers the verification and edge-case work — budget for it explicitly instead of trusting the demo
💡 Hint: Don't rewrite blindly — pin current behavior with tests first, then harden the paths the demo never exercised.
Show solution
Reality: ‘works in the demo’ optimizes for the happy path; production is defined by the paths the demo never hit. Do not rewrite blindly — assess, then harden.
- Map what exists: read the code, list the actual features, and identify which parts are understood vs magic. Magic parts are highest risk.
- Find the missing edges: what happens on bad input, empty state, concurrent use, network failure, and large inputs? Prototypes almost never handle these.
| Hardening area | Action |
|---|---|
| Correctness | Add a test suite over real behavior before changing anything |
| Input handling | Validate & sanitize all external input; define error responses |
| Secrets/config | Move hard-coded keys to config; rotate anything committed |
| Failure modes | Timeouts, retries, graceful degradation on dependency failure |
| Observability | Logging + metrics so prod failures are diagnosable |
| Data safety | Backups/migrations; no destructive ops without guards |
Lesson: vibe coding is excellent for reaching a working prototype fast; the production cost is the verification and edge-case work it deferred. Budget for that explicitly instead of trusting the demo.
✓ Checkpoint — you can move on when you can…
- Define vibe coding vs AI-assisted engineering and when each fits.
- Place a tool/task on the delegation spectrum and its verification burden.
- Run the intent→generate→verify→refine loop and explain why verify is essential.
- Name the key risks and how you'd manage each.
- Set up context/rules that make an AI coding tool reliable.
Knowledge check check yourself
The lesson frames the intent -> generate -> verify -> refine loop and calls one step the "load-bearing" one. Which step, and why is skipping it described as "gambling, not coding"?
Show answer
According to the delegation spectrum, why does moving further right (toward autonomous agents) increase the verification you owe rather than decrease your workload?