Section 4Plan — PRD to tracer-bullet issues
Grilling produces a shared understanding. Now freeze it. Understanding that lives only in a conversation is fragile: the session ends, the context empties, and next Tuesday neither you nor the agent remembers exactly what was agreed. Worse, an unwritten agreement can't be reviewed — you can't point at a feeling and ask "is this still what we meant?" Writing the plan down turns a fleeting agreement into an artifact: something a fresh agent session reads in seconds, something you check finished work against, something that's still true after your own memory has moved on.
There's a second reason planning matters more with agents, not less. A human developer who half-remembers last week's discussion at least knows they're guessing. An agent with no plan doesn't guess visibly — it fills the gaps silently with plausible defaults, exactly the averaging behaviour Section 3 warned about. The plan is how the alignment you just paid for survives contact with a stateless machine.
The PRD — freeze the destination
Run /to-prd to turn the interview into a PRD — the "destination document" that states exactly what the finished feature does, who it's for, the user stories, and how you'll know it's done. This is what the agent builds toward and what you review against.
What "user stories" are. One-sentence descriptions of a feature from the point of view of the person using it, usually shaped like: "As a salon owner, I want to block out my holiday, so that nobody books a haircut while I'm away." The shape forces three answers at once — who it's for, what they can do, and why they'd bother. A PRD is largely a stack of these, plus the ground rules around them: what's explicitly out of scope, and what "done" means.
Then read the PRD — actually read it, before you accept it. This is the cheapest veto you will ever get. Changing a sentence in a document costs ten seconds; changing the same decision after it's been built costs hours of rework and review. Read it the way you'd read a contract: not "does this sound right?" but "is anything here not what we agreed — and is anything missing that we did agree?" The grill in Section 3 surfaced the decisions; the PRD is where you verify they landed on paper intact. If a decision you remember making isn't in the document, it doesn't exist — the agent builds from the text, not from the conversation.
Slice it vertically — every ticket a tracer bullet
Then run /to-issues to break the PRD into small, independent tickets. The rule that makes this work: every ticket is a tracer bullet — a vertical slice that cuts through all layers (database → backend → screen) instead of building one horizontal layer at a time.
Why "tracer bullet"? Tracer rounds are ammunition that glows in flight, so a gunner firing in the dark sees where the shots actually land and adjusts aim — instead of computing a perfect trajectory on paper and hoping. Andy Hunt and Dave Thomas borrowed the image in The Pragmatic Programmer: build one thin, working path through the whole system first, see where it lands, adjust. The alternative — specifying everything up front and firing once — is how software traditionally missed.
Ticket 1: all database tables. Ticket 2: all API endpoints. Ticket 3: all screens.
Nothing runs until the very end. Integration bugs surface last, when they're most expensive.
Ticket 1: "user sees their name after login" — one table, one endpoint, one screen, end to end.
Each ticket runs and is testable on its own. Feedback is near-instant, and slices can be built in parallel.
The three layers of an app. Almost every app is built in three layers: the screen you see and tap; the backend — the rules running on a server, deciding things like "is this slot still free?"; and the database, which remembers everything after the screen is closed. An endpoint is the backend's door for one kind of request from the screen ("book this slot"). So "one table, one endpoint, one screen" means the slice touches each layer exactly once — the thinnest possible cut that still goes all the way through.
The vertical rule has a quieter payoff that matters specifically for agents: a slice that fits in one ticket also fits in one session. The agent starts fresh, reads the ticket, builds the slice, and finishes before its context fills up with half-remembered detours. Horizontal tickets ("all the endpoints") sprawl — they touch everything, finish nothing, and outlive the session's ability to hold them. Small vertical tickets are how you keep each working session short, focused and reviewable, which Section 12 will turn into a discipline of its own.
Give every ticket a "done" a stranger could check
A ticket titled "improve the booking flow" can never be finished — there's no moment where improvement objectively stops. "After booking, the customer sees a confirmation screen with the date and time" can be checked by anyone: open the app, book, look. That's the standard each ticket needs — a description of observable behaviour, written so that a stranger (or an agent, or you in three weeks) could decide "done or not done" without asking anyone.
This isn't bureaucracy; it's the hook the next section hangs on. Section 5 turns each ticket's "done" into a failing test before any code is written — and a test can only be written from a checkable statement. A fuzzy ticket doesn't just risk a wrong implementation; it blocks the entire verification machinery downstream. Sharp "done" criteria are where testability starts, one ticket at a time.
One worked example — from PRD fragment to ticket
This chapter keeps naming its two artifacts without showing them, so here is one concrete pair from the salon app. First, the fragment of the PRD that covers cancellations:
## Cancellations
As a customer, I want to cancel my booking, so that
the slot frees up for someone else.
- Cancelling is allowed until 24 hours before the
appointment; after that the button is hidden and
the salon must be phoned.
- A cancelled slot becomes bookable again immediately.
- The salon owner sees cancellations in the day view.
Out of scope: refunds, cancellation fees, no-show tracking.
Done when: a customer can cancel an eligible booking and
the slot reappears as free in the booking calendar.
And the tracer-bullet ticket /to-issues cuts from it — title, short description, a "done" a stranger could check, and its blocker made explicit:
Title: Customer cancels a booking — slot becomes free
Description: Add a "Cancel booking" button to the
customer's booking detail screen, shown only while the
appointment is more than 24 hours away. Cancelling marks
the booking cancelled in the database and frees the slot
— one table change, one endpoint, one screen.
Done when: a stranger can book a slot, cancel it, and
immediately see the same slot offered as free again.
Blocked by: #12 "Customer sees their bookings after login"
Notice what the ticket is not: it doesn't mention refunds (the PRD ruled them out), it doesn't try to cover the salon owner's day view (that's its own slice), and its "done" sentence is something anyone could verify with the app in hand.
The board — a shared map of what blocks what
The tickets form a small board with clear blocking relationships. That map is what later lets you run several agents at once (Section 11) — each grabs an unblocked ticket.
Issues, tickets, boards. An "issue" (also called a ticket) is one entry in a shared to-do list: a title, a description, a status ("open", "in progress", "done"), and links to the issues that must be finished first — its blockers. A "board" is the same list laid out as columns by status, so a glance shows what's moving. GitHub and GitLab have this built in next to your code; the point isn't the tool, it's that the list is shared and the dependencies are explicit.
The blocking links are the part people skip and shouldn't. "Holiday blocking" needs "calendar exists" first; write that down as a link, not a mental note. Once dependencies are explicit, the board answers the most useful planning question automatically: what can start right now? Every unblocked ticket is a slot for a working session — yours or an agent's — and nothing gets started that's doomed to stall halfway on a missing prerequisite.
And when a ticket meets reality and reality wins — the slice turns out bigger than planned, or the PRD assumed something false — change the plan, not just the code. A board that no longer matches what's actually being built stops being a map and starts being a lie; five minutes of updating tickets keeps every future session, human or agent, working from the truth.
Prototype first when taste matters
Some decisions can't be settled in writing, no matter how good the grill was. How a screen feels, whether a layout reads at a glance, which of three interaction styles suits the salon owner with both hands in someone's hair — words are a poor medium for taste. For those, the cheapest path isn't more discussion; it's building throwaway variants and looking at them.
For UI or tricky state, spin up throwaway variations before you commit — the /prototype skill starts a tiny local preview in your browser and gives you a link to open, with an A/B toggle so you can click between options and impose your taste. The chosen variant is then re-implemented properly by the build agent — prototype code itself is never promoted.
The word "throwaway" is load-bearing. A prototype's job is to answer a question — "which of these three is right?" — and then die. Keep the decision, record it in the ticket or an ADR, and let the build agent re-implement the chosen variant properly. Promoting prototype code straight into the product is how a quick hack, built with none of the care the rest of this guide demands, quietly becomes a permanent resident.
One note on order, because Section 5 adds a second pre-UI ritual. For most screens, the agent's throwaway ASCII wireframe (Section 5) is the right first move — it settles layout and structure questions in seconds, in chat, with nothing to clean up. Reach for /prototype variants only when taste or interaction is genuinely contested — when you have to click something to know which option is right. Either way the ending is the same: decide, record the decision, and let the build agent re-implement it.
The prototype dies; the tickets live on — and each ticket's "done" a stranger could check is exactly what Section 5 turns into a failing test the computer runs.
Quick check: the agent grabs the ticket "improve the booking flow", asks zero questions, and starts building. What went wrong upstream?
The ticket was never finishable — "improve" has no observable "done", and an agent doesn't push back on a fuzzy ticket the way a colleague might; it fills the gaps silently with plausible defaults and confidently builds something. The failure happened at planning time: this ticket should never have reached the board without a "done" a stranger could check — one sentence of observable behaviour, like "after booking, the customer sees a confirmation screen with the date and time." With that sentence, the agent has a target and Section 5 can turn it into a failing test. Without it, nothing the agent builds can ever be verified.