· user-stories · ai-assisted-delivery · invest
AI prompts for user stories: how to get vertical slices, not backend tickets
Ask AI to split an epic and it hands you a 'backend story' and a 'frontend story' — the exact split that gets bounced. Here is how to prompt for vertical slices, run an INVEST self-audit, and catch the detail it invents.
Writing user stories with AI is the most over-promised, under-specified task in the whole “AI for product managers” genre. The pitch is that you paste an epic and get sprint-ready stories. What you actually get, from the generic prompt, is a decomposition that no engineering team will accept — and if you don’t already know why, you will ship it and find out in refinement.
The failures are consistent enough to name. Here are the three that matter, and how to prompt around each.
Failure 1: AI splits stories horizontally
Ask a model to “break this epic into user stories” and, more often than not, it slices along the architecture:
- As a developer, I want to build the quote API endpoint…
- As a developer, I want to build the quote screen…
- As a developer, I want to add the database schema for quotes…
This is a horizontal split — one story per layer of the stack. It is the single most common thing that gets bounced, because none of those stories delivers anything a user can observe on its own. The database story ships nothing. The endpoint story ships nothing a coordinator can see. You cannot demo any of them, you cannot get feedback on any of them, and if you ship two of three you have a half-built feature and zero delivered value.
What you want is vertical slices: each story cuts through every layer it needs and delivers one thin, observable capability end to end. The model won’t do this by default because horizontal splitting is easier — the layers are right there in the architecture, whereas a vertical slice requires understanding what the user can do after the story ships.
So the prompt has to state the rule explicitly, and state the anti-pattern by name:
Each story must be a vertical slice that delivers observable user value. No “backend story” / “frontend story” / “database story” splits. Use the form “As a [role], I want [capability], so that [value]”, where [capability] is something the role can see or do after the story ships.
Naming the forbidden pattern matters. “Deliver value” is advice the model will nod at and ignore; “no backend story splits” is a constraint it can actually check itself against.
Failure 2: no self-audit, so quality is invisible
The second failure is subtler. Even a decently-split set of stories arrives with no signal about which ones are weak. You get six tidy paragraphs, they all look fine, and you walk into refinement to discover that story four can’t be estimated because a rule is undefined and story six isn’t testable at all.
The fix is to make the model grade its own work in the same call, against a standard it can’t wave away. INVEST is the right standard because each letter is a concrete question: Independent, Negotiable, Valuable, Estimable, Small, Testable. Append this to the decomposition prompt:
Then audit your own output: produce an INVEST table (each story × I/N/V/E/S/T, mark ✓ or ✗ with one word why) and flag any story you would bounce in refinement.
Two things happen. First, the ✗ marks tell you where to look before the team’s time is spent — a story marked ✗ on Testable is a story with no clear acceptance criteria yet. Second, and more useful, the audit occasionally contradicts the decomposition: the model writes a story, then flags its own story as un-estimable because a dependency is unresolved. That contradiction is the model doing your risk assessment for you. A row that is all ✓ deserves more suspicion than one with an honest ✗ — the self-audit runs lenient, so treat every ✗ as real and every clean row as unverified.
Doing epic → story decomposition well
Put those together and the difference is stark. Here is a Parcelio epic — Parcelio being the fictional parcel-logistics platform I use for every example on this site, so nothing here is a real client:
Epic: Multi-parcel shipments. Coordinators can quote and book up to 20 parcels as one shipment: one quote total, one booking, one customs pack covering all parcels, one consolidated charge on the invoice. Today the platform is strictly 1 parcel = 1 shipment.
The horizontal answer would be “quote-aggregation service story,” “multi-parcel UI story,” “invoice-export story.” The vertical decomposition, prompted properly and constrained to eight stories with a self-audit, returns slices like these:
S1. As a logistics coordinator, I want one quote for up to 20 parcels, so that I see a single
total instead of quoting 20 times.
S2. As a logistics coordinator, I want to book a multi-parcel quote in one action and receive
one label per parcel, so that a partial failure never leaves me half-booked.
(The label-API looping and rollback live INSIDE this story — that IS the observable
"atomic booking" behaviour, not a separate backend story.)
S5. As a finance viewer, I want one consolidated charge line per multi-parcel shipment in the
invoice export, so that reconciliation matches what was booked.
INVEST AUDIT (excerpt)
| Story | I | N | V | E | S | T | Bounce? |
|-------|---|---|---|---|---|---|---------|
| S2 | ✗ | ✓ | ✓ | ✓ | ✗ | ✓ | Largest story; keep atomicity, split label-retry UX if needed |
| S4 | ✗ | ✓ | ✓ | ✗ | ✓ | ✗ | BOUNCE — "one customs pack, all parcels": customs advisory
hasn't confirmed a multi-line declaration is valid in every
corridor. Not estimable or testable until they answer. |
Look at what S2 does: it explicitly pulls the tempting “atomic booking” backend work inside a user-facing story, and says so in a parenthetical, so nobody re-splits it in refinement. And look at S4: the model wrote the story and then bounced its own story, because the rule it depends on isn’t decided. That bounce is worth more than the six stories around it. It is a decision you now go get before the sprint, not a surprise you hit during it.
Failure 3: AI invents acceptance detail that isn’t in the source
This is the one that will actually hurt you, because it hides inside good-looking output.
When the source material is thin, a model does not leave gaps — it fills them, plausibly. Give it “coordinators can book up to 20 parcels” and it will happily generate a story asserting “parcels over 20 are rejected with an error message,” or “each parcel must have a declared weight above 0.1 kg,” or a specific rollback timeout. None of that was in your epic. Some of it might even be right. But you didn’t decide it, nobody confirmed it, and it is now sitting in a story wearing the same confident tone as the parts you did decide.
Invented detail is more dangerous than vague detail for one reason: vagueness gets bounced,
specificity gets built. “The system handles errors” triggers a question in refinement. “Parcels
over 20 are rejected with SHIPMENT_PARCEL_LIMIT_EXCEEDED” triggers a developer building
exactly that — a limit you never agreed on, an error code you never defined.
There is no prompt that eliminates this, but you can corner it. Instruct the model to mark anything it introduces that wasn’t in your input:
Mark every business rule, limit, error case, or field you introduced that was not present in the epic or context I gave you, with
[ASSUMED — confirm]. Do not silently promote an assumption to a requirement.
Then your review job becomes finite and specific: find every [ASSUMED — confirm] tag and
either confirm it with the rule’s owner or delete it. That is a five-minute pass with a clear
definition of done, instead of a vague duty to “check the AI didn’t make things up” that you
will, under deadline, skip.
The honest workflow
AI is genuinely good at the mechanical half of story-writing: taking a decided scope and casting it into consistent, well-formed vertical slices with a self-audit attached, in the time it takes to read one. It is structurally bad at the half that matters — deciding the scope, knowing your rules, and telling you what it doesn’t know. So use it for the first half and keep the second:
- Prompt for vertical slices, anti-pattern named, capped at eight stories.
- Demand an INVEST self-audit in the same call; trust the ✗ marks, distrust the clean rows.
- Make it tag every
[ASSUMED — confirm]it introduces. - Read the bounces and the tags. That is your refinement prep — the decisions to go get before the story is anyone’s problem in a sprint.
Get the prompt
The full epic → story decomposition prompt — with the vertical-slice constraint, the built-in INVEST self-audit, and its documented failure modes — is prompt 04 in the free slice: 10 documented AI prompts for POs, drafted from a production AI-assisted specification pipeline. Each ships with when to use it, what to paste in, a worked Parcelio example, and where it breaks. Email-gated, free, no listicle.
Subscribe and get the free slice →
— Pierre K.