The Vibe Coder's Bible
Chapter 19

Building A Feature

Do not ask the agent to build a feature until the feature has a shape.

Chapter 19 - Building A Feature

Part: V - AI-Assisted Development Workflows

Thesis

A feature built with AI is a proposal that earns the right to merge through validation. The model proposes. The tests decide.

Key Line

Do not ask the agent to build a feature until the feature has a shape.

Feature Spec Before Code

The agent generates against its training distribution unless you give it something more specific.

Without a spec, “add user authentication” produces generic JWT middleware with hardcoded expiry values, a session table that contradicts your existing schema, and error messages that do not match the rest of the application. The agent did not misunderstand. It built the most common version of what you described.

A spec takes fifteen minutes to write. It defines scope, inputs, outputs, and the test that will prove correctness. Write it as a short document or a GitHub issue before opening a model prompt. The spec does not need to be formal. It needs to be specific enough that a wrong implementation is obviously wrong.

The format that works: what user need does this address, what data goes in, what comes out, what changes in the system, and what test proves it is correct. That is the entire spec.

Separate What The Model Proposes From What Owns The Answer

A feature built with AI has two authors, and they are not equal. The model proposes structure - the shape of the change, the code, sometimes the copy. Something else has to own what is true and what is allowed. Conflating the two is how “add user authentication” becomes hardcoded expiry values reaching production without anyone deciding that was acceptable.

Before writing the spec, name what the model may propose and what a deterministic component must own. In a checkout feature, the model may draft the confirmation copy; it does not own the total, which the pricing engine computes. In a support feature, the model may propose a refund; it does not own whether the refund is authorized, which the permission table decides. Say both halves out loud, not just the half the ticket is about.

Six fields belong in every feature spec, whether the feature only touches the build loop or the model keeps running inside it after ship:

  • Input schema. What shape is the model working from or producing? Chapter 16 covers the contract itself; the spec just names which one applies.
  • Source of truth. What component owns the actual answer this feature returns.
  • Validator chain. What checks run on the proposal, in what order, before it can affect anything.
  • State transition. What does the system change when this feature succeeds.
  • Trace event. What gets recorded, whether the feature succeeds or the model’s proposal is rejected.
  • User-visible fallback. What the user sees when the model’s proposal fails validation. Silence is not a fallback.

A feature spec missing any of these six is missing a decision, not missing paperwork. The decision still gets made - by whichever line of generated code happens to run first.

TDD With AI

Write the test before asking for the implementation.

Ask the model to write the test first. Describe the intended behavior and the expected inputs and outputs. The model will produce a test. Before using it, run it against no implementation - it must fail. A test that passes before any implementation is testing nothing.

A failing test is a precise specification. It tells the model exactly what “done” means. Implementation is then a matter of making that specific test pass, not of writing code that looks like it should work.

When the test passes, the feature is done. Not when the agent says it is done. Not when the code looks reasonable. When the test passes.

This sequence also catches a common failure: the model writes a test that mocks away the actual behavior being tested. If the test passes before the implementation exists, the mock replaced the real thing and the test is worthless. Catching this before writing any implementation code is far cheaper than catching it in production.

The Review Loop

Review generated code in small increments. A function at a time, not a file at a time, not a PR at a time.

The review surface per increment determines how much can go wrong between looks. A ten-line function has a bounded blast radius. A five-hundred-line file does not. The agent can generate plausible-looking changes across many files faster than a human can read them.

The prompt discipline that supports this: ask the model for one function, review it, ask for the next. This feels slower. It is not. The time spent reviewing a 500-line diff for the bugs that are actually there exceeds the time lost by working in smaller steps.

When reviewing each increment, read the code before reading the model’s explanation of it. The explanation is persuasive. It creates a mental model that filters what you see in the code. A readable explanation of a wrong function will make the wrong function harder to catch. Read the code first. Form your own read. Then compare to the explanation.

When To Ask vs. When To Run

The model can reason about expected behavior. It cannot tell you about actual behavior.

Use the model for design questions: what approach handles this edge case, what are the tradeoffs between these two implementations, what could go wrong with this approach. The model’s answers are useful input to a decision.

Use running code for all questions about what the code actually does. “Will this handle a null input?” is a question to answer with a test, not with a model explanation. The model will tell you what it intended. The runtime will tell you what happens.

The clearest version of this rule: if the answer matters enough to act on, run it. If it is context for a decision you are making, ask the model. Never substitute a model explanation for a test when the test is cheap to write.

Scope Discipline

The feature ticket defines scope. The agent does not.

AI-assisted scope creep is particularly dangerous because the agent generates plausible-looking changes across unrelated files without flagging them as out of scope. A request to add a sort parameter to an API endpoint can produce changes to the database schema, the ORM model, the admin panel, the API serializer, the test fixtures, and the caching layer - all in one diff, all looking reasonable, all changing things you did not ask to change.

Before running any agent prompt for a feature, write down what files are in scope. After the agent generates output, check every changed file against that list. Any file that appears in the diff but was not in the scope list gets scrutinized first: is this change required, or did the agent follow a pattern into territory that was not requested?

Stop the agent when it starts touching out-of-scope code. Ask for a revised approach that stays inside the boundary. Do not accept a large diff because most of it looks right.

Build The Verifier Before The Capability

Order matters as much as content. Build the validator chain before the feature gains the capability it validates.

This sounds backward - how do you write a check for an action that does not exist yet? The validator does not need the feature to exist. It needs the shape of the proposal and the rule it is checking. Write the schema. Write the authorization check against that schema. Write the test that proves an invalid or unauthorized proposal is rejected. Only then wire the model up to produce proposals in that shape.

Reverse the order - give the model the capability first, plan to add validation before it ships - and the validation gets written against whatever the model happened to produce during development, not against the full space of what it could produce in production. A verifier written after the fact tests the demo. A verifier written first tests the domain.

Two Examples, Same Shape

AI-assisted: a sort parameter. Spec: add ?sort=price_asc to the product listing endpoint. Input schema: an enum of four allowed sort keys. Source of truth: the query the ORM already builds; the feature only adds an ORDER BY clause. Validator chain: reject any sort value not in the enum with a 400. State transition: none - this is a read. Trace event: log the requested sort key. User-visible fallback: an unrecognized sort value falls back to the default order instead of erroring the whole request. The model drafts the endpoint change and the test. The validator chain is four lines and does not care what the model intended.

AI-native: a support-bot refund action. Spec: a chat agent may propose a refund when a customer describes a billing error. Input schema: a typed RefundProposal with order ID, amount, and reason - not freeform text. Source of truth: the order ledger and the refund policy table, not the model’s read of the conversation. Validator chain: order exists, amount does not exceed what was paid, reason matches an allowed category, proposals above a threshold require human approval. State transition: a refund record is written and the payment processor is called only after every check passes. Trace event: every proposed refund is logged whether approved or rejected, with the model’s stated reasoning attached as commentary, not as authority. User-visible fallback: a rejected proposal tells the customer the request is escalated to a human, not that the refund failed silently.

Both features start from a spec. The runtime feature’s spec has more to name, because more of it keeps running after the demo ends.

Acceptance Criteria

A feature is done when the acceptance criteria in the spec are met. Not when the code is written. Not when the tests pass.

The tests should encode the acceptance criteria. If the acceptance criteria cannot be expressed as tests, the criteria are underspecified. “The user should be able to log in” becomes: the endpoint returns a valid session token for correct credentials, returns a 401 for incorrect credentials, returns a 400 for malformed input, and rate-limits after five failed attempts. Each of those is a test. All four pass, or the feature is not done.

Acceptance criteria are not only about the happy path. A spec that only describes correct behavior has not specified what happens when the model’s proposal is rejected. Write rejection criteria alongside success criteria: what the system does when the input schema fails, when the source of truth disagrees with the proposal, when the validator chain rejects the action. “Returns a 400 for malformed input” is a rejection criterion. “Shows the escalation fallback and logs the rejected proposal to trace” is a rejection criterion for a runtime feature. A spec is not complete until both the accepted path and the rejected path have a test.

Handoff happens when the acceptance criteria are provably met. Provably means a test ran, not that the agent said so.

Practical Artifact - Feature Build Checklist

Run in order. Each gate must pass before the next step begins.

GateActionWhat It Protects
Spec existsWrite issue or SPEC.md with inputs, outputs, scope, and acceptance criteriaPrevents building the wrong thing
Six fields namedInput schema, source of truth, validator chain, state transition, trace event, and user-visible fallback are each written downSurfaces decisions the ticket would otherwise leave implicit
Scope documentedList files that are in scope for this featureCatches scope creep in the diff
Verifier built firstValidator chain is written and tested against the schema before the model is given the capabilityPrevents verification written only against demo output
Test writtenAsk model to write the test; confirm it fails with no implementationProves the test is real
Prompt boundedAgent prompt references the spec explicitlyKeeps generation on target
Diff scopedEvery changed file is on the scope list or has a written justificationCatches unintended changes
Tests passRun the full test suite, not only the new testCatches regressions
Acceptance criteria metEach acceptance criterion has a passing test, including the rejection pathProves the feature is done for both valid and invalid proposals
PR references specPR description links to the spec and lists passing testsCreates traceable history

Export

Copy this block into your CLAUDE.md, agent instructions, or project checklist.

Do not ask the agent to build a feature until the feature has a shape.

vcb_chapter: 19
title: "Building A Feature"
key_line: "Do not ask the agent to build a feature until the feature has a shape."
thesis: "A feature built with AI is a proposal that earns the right to merge through validation. The model proposes. The tests decide."
checklist:
 - item: "Write the spec before writing any prompt"
 protects: "Prevents building the wrong thing"
 - item: "Name input schema, source of truth, validator chain, state transition, trace event, and user-visible fallback"
 protects: "Surfaces decisions the ticket would otherwise leave implicit"
 - item: "Document which files are in scope"
 protects: "Catches scope creep in generated diffs"
 - item: "Build and test the validator chain before granting the model the capability"
 protects: "Prevents verification written only against demo output"
 - item: "Write the test first; verify it fails"
 protects: "Ensures the test is real and specific"
 - item: "Review one function at a time, not one file at a time"
 protects: "Keeps review surface manageable"
 - item: "Run code to verify behavior; ask the model to reason about design"
 protects: "Prevents model explanation from substituting for a test"
 - item: "Check every changed file against the scope list"
 protects: "Catches unasked-for changes across the codebase"
 - item: "Every acceptance criterion, including the rejection path, has a passing test before handoff"
 protects: "Proves the feature is done for both valid and invalid proposals"
  • Is there a written spec with inputs, outputs, and acceptance criteria? - prevents building the wrong thing
  • Are the six fields named: input schema, source of truth, validator chain, state transition, trace event, user-visible fallback? - surfaces decisions the ticket would otherwise leave implicit
  • Is the scope documented as a file list? - catches scope creep
  • Is the validator chain built and tested before the model is given the capability? - prevents verification written only against demo output
  • Does the test fail before any implementation exists? - proves the test is real
  • Is every changed file on the scope list? - catches unintended changes
  • Does the full test suite pass, not only the new test? - catches regressions
  • Does every acceptance criterion, including the rejection path, have a passing test? - proves the feature is complete for accepted and rejected proposals
  • Does the PR reference the spec? - creates traceable history

Practical Artifact

0/10 checked