Writing the work

How to write a user story

A good story is small enough to build in a sprint, specific enough to test, and honest about the assumptions it carries.
steps
9
named failure modes
5
definition-of-done criteria
6

How to write a user story, in one paragraph

A story is the smallest slice of user-visible value your team can ship: one parent epic, one sprint, testable by someone who did not write the code. Good means a developer who missed refinement can build it from the ticket alone, and a tester can pass or fail every criterion without asking your opinion. It names the user, the change to their experience, the acceptance criteria, the signal that will prove the epic is moving, and the assumptions it carries. If nothing a user can see or do changes, it is a chapter, not a story.

That is the procedure. The call is where it meets your delivery structure.

Talk it through

What these are. The delivery operating model our engagements install alongside client teams: the method underneath the agentic work rather than the agentic work itself, published in full and free to use. It is written for the person running a quarter, not for a buyer, so if you are evaluating us, read the five priced engagements or the case studies instead.

When to use this

Write stories while the parent epic is still moving through its product phases, because that epic cannot leave Ready for Dev without at least one product-approved story attached. This is an AI-augmented team practice: AI-native teams stop at the epic and write an outcome ticket instead.

Time to run it once
About two hours, plus sizing at refinement
What you need
  • The delivery tracker
  • The approved parent epic

If you do not have those in place, the call is a good place to work out what comes first.

Talk it through
On this page
9 steps

Step by step

Each step is deep-linkable, so you can send a colleague the one that is in dispute.

  1. 1

    Anchor the story to an approved epic

    Open the parent epic before you open the blank ticket.

    Three checks: it links to exactly one outcome, it carries a stated share of that outcome's currency target, and it sits in this quarter's roadmap. A missing link or a blank value means fix the epic first, because a story hanging off a broken chain is work nobody can defend at the end of the quarter. If the epic is not product-approved yet, write the story anyway and stage it in the backlog. It cannot start until approval lands, and the epic cannot leave Ready for Dev until a story under it is approved. Someone goes first.

  2. 2

    Prove the slice is vertical

    Check the slice crosses every layer it touches: data, service, interface.

    "Build the payments API" and "Build the payments screen" are two halves of nothing shippable. Slice instead on one step in the workflow, one type of user, one business-rule variation, one data source out of several, or the happy path with the edge cases as siblings behind it. Then run one test on what you are about to write. If we shipped only this, could a real user do something they could not do yesterday? If the answer is no, you are holding a chapter, and a chapter belongs to a story, not to an epic.

  3. 3

    Title it as the change to the user

    Write the title as a person doing a thing: "Returning customer pays with a saved card", not "Implement saved-card retrieval".

    The subject is the user, the verb is observable from outside the codebase, and the whole thing runs under about ten words. If the only honest subject is a service or a component, you sliced by layer, so go back a step. Skip the "As a user, I want, so that" template unless your team still reads it closely. On most boards it has become a formatting ritual that pads the title and buries the specifics in a clause nobody finishes.

  4. 4

    Write context that reads cold

    Assume the reader missed refinement and gets no follow-up conversation.

    Four sentences, in this order: which user, where in the journey, what happens today, what should happen once this ships. Link the discovery evidence rather than summarising it, so the claim stays attached to its source, and link the epic rather than restating it. Then add a line headed "not in this story", naming the sibling tickets that cover the rest. Leaving the boundary implicit is the fastest route to gold-plating: a developer with a gap in front of them fills it generously, and the sprint pays for it.

  5. 5

    Write acceptance criteria a tester can run

    Three to seven criteria, each one passable or failable by someone who did not write the code.

    Given, when, then works. A plain checklist works. Opinions do not: replace "the page should feel fast" with "the saved-card list renders within 500ms at p95 on a 4G profile", and "the flow should be intuitive" with the click count or the exact error copy. Write the negative paths as deliberately as the happy one: empty state, expired data, the dependency timing out, the user who has none of the thing. Put the non-functional rules that matter here as numbers or named standards, not in a document nobody opens.

  6. 6

    Name the signal that proves it worked

    The epic carries the currency.

    The story carries the signal that tells you the epic is moving. Write four things down: the metric, today's baseline, the dashboard or query the number is read from, and the event or property the build has to emit for that number to exist at all. If the instrumentation does not exist yet, make it an acceptance criterion in this story rather than a follow-up nobody schedules. This is what makes monthly outcome validation possible later. A story that ships with no way to read its effect becomes an argument in three months' time.

  7. 7

    Write down the assumptions and open questions

    Every story carries assumptions: traffic volumes, what a third party returns, how many users sit in the segment.

    List each one with what you will do if it turns out wrong, in a single line: assume under 5% of sessions hit this, if it is higher we add pagination. Then list the open questions with a named owner and a date, not "the team" and not "soon". Two rules keep this honest. A question that blocks the build blocks the story leaving the backlog. A question you have chosen to proceed without is a decision, recorded as one, not an omission somebody finds mid-sprint.

  8. 8

    Size it with the team, split anything oversized

    Take it to the fortnightly refinement and size it with the people who will build it, not at your desk.

    If they cannot build and review it inside one sprint, split it now, while splitting is cheap, along the same seams you used to slice: rule variations, user types, data sources, happy path first. Record the size so it feeds your throughput data and the forecasts. Do not pre-split an oversized story into chapters to make it feel manageable. Chapters are what a developer creates mid-build when a story turns out bigger than expected, and writing them upfront hides the size problem from the people sizing it.

  9. 9

    Take it through product approval

    Approval is a check, not a signature.

    The approver confirms three things: the slice is user-visible, every acceptance criterion is testable by someone else, and the story belongs under this epic rather than a neighbouring one. Do this early for at least one story per epic, because the epic cannot leave Ready for Dev without product approval, engineering approval and one approved story attached, and that story is usually what everyone is waiting on. One rule for the approver: if you would have to explain the ticket in person for it to make sense, send it back rather than explaining it.

Bring a real piece of work to the call and we will walk it through these.

Talk it through
Worked example

Worked example: a saved-card story at a fictional retailer

Northbay Outdoors is an invented online retailer and every number below is invented with it.

Outcome (L1)
cut abandonment at the mobile checkout. Target £1.2m of additional annual revenue, currently in Working On, spanning two quarters.
Epic (L2)
saved payment methods for returning customers. Planned share of the outcome £380k, sitting in the Q3 roadmap, product and engineering approved.
Story title
Returning customer pays with a saved card.
Context
a customer who has bought at least once in the past twelve months reaches the payment step on mobile. Today they retype the full card number every time, and the session recordings from the March discovery (linked on the ticket) put 38% of mobile drop-off on that screen. Once this ships, cards stored on a previous order appear as selectable options showing brand, last four digits and expiry, and the customer pays with CVV only. Not in this story: adding a new card during checkout, editing or deleting stored cards, and desktop. Those are three sibling tickets under the same epic.

Acceptance criteria. One: a customer with one or more stored cards sees them listed at the payment step, most recently used first, showing brand, last four digits and expiry. Two: selecting a stored card and entering the correct CVV completes the payment. Three: a customer with no stored cards sees the existing card form, unchanged. Four: an expired stored card is listed but disabled, with the message This card has expired. Five: if the payment provider does not respond within three seconds, the existing card form is shown and no error page appears. Six: the list renders within 500ms at p95 on a 4G profile. Seven: the build emits checkout_payment_method_selected with a method property of saved_card or new_card.

Signal
share of mobile checkouts completed with a stored card. Baseline 0%, because the feature does not exist yet. Read from the checkout funnel dashboard, using the event added in criterion seven. The epic's own measure stays mobile checkout completion rate, baseline 61.4%.
Assumptions
roughly 45% of mobile sessions are returning customers with a stored token, and if it turns out to be under 20% the epic's £380k share goes back to the outcome owner before more stories are written. The provider returns brand and expiry on the stored token, and if it does not, criterion one drops to last four digits only.
Open question
does risk require step-up authentication on stored cards above £250? Owner: the risk lead, answer due 14 August. This one blocks the build, so the story stays in the backlog until it is answered.
Size
five points at refinement, comfortably inside a two-week sprint. Product-approved the same day, and it is the approved story that lets the epic leave Ready for Dev.

Yours will look different. Thirty minutes is enough to see how.

Talk it through
Failure modes

Where this goes wrong

  1. 01

    Slicing by layer because that is how the team is organised.

    "API work" and "front-end work" each look like a story, and neither ships anything a user can use, so neither can be credited with any part of the epic's planned value at validation. It happens when the org chart rather than the user's journey is doing the splitting.

  2. 02

    Acceptance criteria written for the people who were in the room.

    Fast, clean and intuitive pass review because everyone present knows what was meant, then fail in testing three weeks later when the ticket is the only surviving record. The cost lands on whoever picks the work up, not on whoever wrote it.

  3. 03

    The thirty-criterion story.

    Length is the tell that it is an epic wearing a story's ticket type. It happens because splitting feels like losing the thread of the feature, so the author keeps adding criteria instead of siblings, and the team sizes something nobody can finish in a sprint.

  4. 04

    Starting work on a story whose epic is not product-approved.

    The gate exists because an unapproved epic is still moving: its scope, its share of the outcome, sometimes the outcome itself. Work started against it gets rebuilt, and the rebuild eats capacity the quarter had already promised elsewhere.

  5. 05

    Writing stories in an AI-native team out of habit.

    Decomposing an outcome ticket into stories strips out the surrounding context the model needed and pre-empts judgement the model can exercise itself. The habit outlives the mode change because the ticket templates and the refinement calendar did not change with it.

Definition of done

Done means

  • The story links to exactly one epic, and that epic links to one outcome with a currency target and sits in this quarter's roadmap.
  • Someone who was not in refinement could build it from the ticket alone, with no follow-up conversation.
  • Every acceptance criterion can be passed or failed by a person who did not write the code, and at least one covers a negative path.
  • The metric, its baseline, where the number is read from, and any instrumentation the build must add are all named in the ticket.
  • The team has sized it and agrees it fits inside one sprint, or it has already been split into stories that do.
  • Product has approved it, so it is either free to start or deliberately staged behind an epic still waiting for approval.

If you recognise one of those already happening, that is a good call to have.

Talk it through
If your team is AI-native

In an AI-augmented team the story is the unit of work and this guide applies as written. AI can draft a first-pass story structure from a committed epic, which beats starting from an empty backlog, but the criteria, the signal and the assumptions need a human edit before approval: a model drafting from epic text will produce plausible criteria that nobody can pass or fail, and confident assumptions it has no basis for. In an AI-native team, do not write stories at all. The unit of work is an outcome ticket at epic level carrying the currency share, the key user journeys and the test requirements, handed over whole. Splitting it into stories strips out the context the model needed and pre-empts judgement it can exercise itself.

The two delivery modes, side by side →

Which mode your team is actually in is the first thing we establish on a call.

Talk it through
The subject behind the procedure

Where this sits in a programme

The procedure is the same whatever you are building. These cover what it runs into when the thing being built is agentic.

If you want this run inside a programme rather than read, that is the conversation.

Talk it through
book a call

Want help installing this?

These guides are free and you owe us nothing for using them. If you would rather have operators install the operating model alongside your teams and stay until it sticks, that is what our engagements do.

most start with a fixed-price AI Readiness Audit · £44,000 · 4 weeks · working prototypes

// pick a slot · cal.com/tenhaw/professional-servicesLIVE CALENDAR

Calendar not loading? Open it on cal.com or email hello@tenhaw.com.

Questions

Who writes the story, the product manager or the engineer?

One named person owns the ticket. In an AI-augmented team that is usually the product manager, who owns the context, the acceptance criteria and the signal. Engineers shape the slice and set the size in refinement, and they are the ones who catch a slice that is secretly two. Approval is a separate pair of eyes from whoever wrote it, otherwise the check is not a check. On Tenhaw engagements that ownership sits with two or three senior people under partner oversight from James Rooney, and that is the whole delivery team.

How small is too small?

There is no minimum size, only a floor on visibility, so anything that changes what a user can see or do can be a story however small. If it changes nothing user-visible, it is a chapter under a story rather than a story of its own. The signal you have gone too small is three tickets that always ship together and none of which makes sense alone. That is one story that got filleted.

The epic is not product-approved yet. Can I write stories against it?

Yes, and you should. Write them and leave them staged in the backlog. They cannot start until the epic is product-approved, and the epic cannot leave Ready for Dev without at least one product-approved story attached, so the writing has to happen first. What you should not do is start building against an epic whose scope or currency share is still moving.

Do we still need the As a user, I want, so that template?

Only if your team still reads it. The template's job was to force the user and the benefit into the ticket. If the title names the user and the change, and the context links the discovery evidence behind it, the template adds a sentence and no information. Keep it if it earns its place in your refinement conversation, drop it if people's eyes slide past it, but do not keep it and then write vague criteria underneath.

What does it mean to slice a user story vertically?

A vertical slice crosses every layer it touches, data, service and interface, so shipping it alone changes something a real user can do. "Build the payments API" and "Build the payments screen" are two halves of nothing shippable. Slice instead on one step in the workflow, one type of user, one business-rule variation, one data source out of several, or the happy path with the edge cases as siblings behind it. Then run one test on the slice. If we shipped only this, could a user do something they could not do yesterday? If not, it is a sub-task under a story, not a story of its own.

How many acceptance criteria should a user story have?

Three to seven, each one passable or failable by someone who did not write the code. Given, when, then works, and so does a plain checklist; opinions do not. Replace "the page should feel fast" with a number, such as "renders within 500ms at p95 on a 4G profile", and write the negative paths as deliberately as the happy one: empty state, expired data, the dependency timing out. Treat length as a diagnostic too. A story with thirty criteria is an epic wearing a story's ticket type, and the fix is sibling stories, not more criteria.

Should every user story have a metric?

Yes, but not a financial one. The epic carries the value; the story carries the signal that shows the epic is moving. Write four things on the ticket: the metric, today's baseline, the dashboard or query the number is read from, and the event the build must emit for that number to exist at all. If the instrumentation does not exist yet, make it an acceptance criterion in this story rather than a follow-up nobody schedules. Tenhaw reads its own work the same way, reporting measurable value monthly and recording a month that delivers none as a failed month. A story that ships with no way to read its effect becomes an argument in three months' time.

How do you handle assumptions and open questions in a user story?

List every assumption with what you will do if it turns out wrong, one line each. Assume under 5% of sessions hit this, and add pagination if it is higher. Give every open question a named owner and a date, not "the team" and not "soon". Then apply two rules. A question that blocks the build blocks the story leaving the backlog. A question you have chosen to proceed without is a decision, recorded as one, so nobody discovers the gap mid-sprint.

How much detail does a user story need?

Enough that a developer who missed refinement can build it from the ticket alone, with no follow-up conversation. That means four sentences of context in a fixed order: which user, where in their journey, what happens today, what should happen once this ships. Link the discovery evidence and the parent epic rather than restating them. Then add a line headed "not in this story", naming the sibling tickets that cover the rest. A developer with a gap in front of them fills it generously and the sprint pays for it, which is why an implicit boundary is the fastest route to gold-plating.

Should an AI-native team split an epic into stories?

No. In The Tenhaw Way, stories are an AI-augmented practice, for teams where a developer writes the code and AI assists. An AI-native team, where the model builds and the developer directs and verifies, stops at the epic and writes an outcome ticket instead: the value share, the key user journeys and the test requirements, handed over whole. Tenhaw publishes both modes in full and free to adopt without hiring anyone, and the line between them falls at exactly this ticket type. Splitting that into stories strips out the context the model needed and pre-empts judgement it can exercise itself. The habit tends to outlive the mode change because the ticket templates and the refinement calendar did not change with it.

How long does it take to write a user story?

About two hours for the ticket itself, plus sizing with the team at refinement. That two hours covers anchoring the story to an approved epic, checking the slice is vertical, four sentences of context, three to seven acceptance criteria, the signal with its baseline, and the assumptions with what you will do if each one is wrong. Tenhaw writes stories to that same two hours inside client teams. If it is taking a day, the slice is too big or the parent epic is still moving and the story keeps chasing it, so the problem is upstream rather than in the writing. Fix that first. Two hours is cheap against a vague ticket that passes review and then fails in testing three weeks later.

What should you leave out of a user story?

Everything this ticket will not deliver, named rather than assumed. Add a line headed "not in this story" listing the sibling tickets that cover the rest. An implicit boundary is the fastest route to gold-plating, because a developer with a gap in front of them fills it generously and the sprint pays for it. Edge cases can sit behind the happy path as siblings when that keeps the slice shippable. Leave out anything with no user-visible change, since that is a chapter under the story rather than a story of its own. Leave the discovery evidence and the epic detail out too, and link both instead, so each claim stays attached to its source.

How should a user story be titled?

Title it as a person doing a thing, so "Returning customer pays with a saved card", not "Implement saved-card retrieval". The subject is the user, the verb is observable from outside the codebase, and the whole title runs under about ten words. If the only honest subject you can find is a service or a component, you sliced by layer rather than by the user's journey, so reslice before writing anything else. That makes the title the cheapest diagnostic on the board. A ticket named after a component is usually layer-sliced work, and layer-sliced work ships nothing a user can use, so it cannot be credited with any part of the epic's planned value at validation.

What does product check before approving a story?

Three things, and it is a check rather than a signature. Is the slice user-visible, can every acceptance criterion be passed or failed by someone else, and does the story belong under this epic rather than a neighbouring one. The approver has to be someone other than the author, or nothing is actually being checked. If you would have to explain the ticket in person for it to make sense, send it back instead of explaining it. Do this early for at least one story per epic, because the epic cannot leave Ready for Dev without product approval, engineering approval and an approved story attached.

Where do non-functional requirements go in a user story?

In the acceptance criteria, as numbers or named standards, not in a document nobody opens. Performance, resilience and accessibility rules only get tested if a tester can pass or fail them, so write "the saved-card list renders within 500ms at p95 on a 4G profile" instead of "the page should feel fast", and "if the payment provider does not respond within three seconds, the existing card form is shown and no error page appears" instead of a note about graceful degradation. Keep them beside the functional criteria for the same slice. A non-functional rule that lives one layer up in a standards page is a rule nobody was asked to meet on this ticket.

Can a story sit under more than one epic?

No. A story links to exactly one epic, and that epic links to one outcome that carries a currency target and sits in this quarter's roadmap. If a story looks like it serves two epics, either you sliced across the seam between them and are holding two stories, or the epics themselves overlap and need fixing before more work hangs off them. Product approval checks that link deliberately, because the chain is what lets you say at the end of the quarter which work moved which number. A story hanging off a broken chain is not a filing problem, it is work nobody can defend.

What does AI get wrong when it drafts a user story?

The parts it cannot know. Given a committed epic, a model produces a plausible ticket structure fast, which beats an empty backlog, but it writes criteria that sound testable and that nobody can actually pass or fail, and assumptions stated with a confidence it has no basis for. It does not know today's baseline, the dashboard or query the number is read from, or whether the event the build must emit exists yet. Tenhaw's engineering handbook, open on GitHub, holds 72 rules an agent enforces rather than a human remembers. Treat the draft as a first pass and edit three things by hand before approval: the acceptance criteria, the signal, and each assumption with what you will do if it is wrong.

What does a well-written user story look like?

Tenhaw's story guide works one through end to end at Northbay Outdoors, an invented retailer with invented numbers. It is titled "Returning customer pays with a saved card", and the context says a customer who has bought in the past twelve months reaches the mobile payment step, retypes the full card number today, and afterwards selects a stored card showing brand, last four digits and expiry and pays with CVV only. Seven criteria cover the empty state, an expired card and a three-second provider timeout. The signal is the share of mobile checkouts paid with a stored card, baseline zero. It was five points at refinement and product-approved the same day.