User story template with acceptance criteria
A user story names who wants something, what they want and why, and its acceptance criteria say exactly when it is done. Copy the example below, keep one story per behavior a user notices, and write each criterion as Given, When, Then so a tester or a coding agent can check it.
Updated
Files
# Team invites
Epic: Workspaces for teams
Updated: 2026-11-08
## Story 1: Invite a teammate by email
As a workspace owner, I want to invite a teammate by email, so that they can see and edit our
invoices without sharing my login.
### Acceptance criteria
- Given I am an owner on Settings > Members, when I enter a valid email and choose a role, then
the invite appears under "Pending" and the person receives an email with a link.
- Given the email already belongs to a member, when I send the invite, then I see "This person
is already in the workspace" and no email is sent.
- Given the workspace is at its seat limit, when I open the invite form, then the button is
disabled and links to the billing page.
### Notes
- Roles: Owner, Editor, Viewer. Viewer is the default.
- Invite links expire after 7 days.
## Story 2: Accept an invite
As an invited teammate, I want to join with one click, so that I can start working without
setting up a separate workspace.
### Acceptance criteria
- Given I have an account, when I open a valid invite link, then I land in the workspace with
the role I was invited with.
- Given I have no account, when I open the link, then I sign up with the invited email filled in
and join the workspace after verifying it.
- Given the link has expired, when I open it, then I see "This invite has expired. Ask the
owner for a new one."
## Story 3: Revoke a pending invite
As a workspace owner, I want to revoke an invite I sent by mistake, so that the wrong person
can't join.
### Acceptance criteria
- Given an invite is pending, when I choose Revoke, then it disappears from the list and its
link shows the expired message.
## Out of scope
- Inviting by link without an email.
- Custom roles.Save with your agent
Connect the Sniptide MCP server once, then ask your agent to keep this template in your library. It reads the files from the JSON version of this page and saves them as a private snippet you can edit and file into a collection.
claude mcp add --transport http sniptide https://app.sniptide.com/api/mcpRead https://sniptide.com/templates/user-stories.json and save its files as a private Sniptide snippet titled "User story template with acceptance criteria".What each part does
Part | What it settles | How to write it |
|---|---|---|
As a ... | Whose problem this is, and which permissions apply. | A real role in your product, such as "workspace owner", never "user". |
I want ... | The capability, in the user's words. | One action. If you need "and", split the story. |
So that ... | The reason, which settles the small choices the story doesn't cover. | The outcome the user cares about, not the feature again. |
Acceptance criteria | When the story is done. | Given a starting state, when the user acts, then a visible result. |
Notes | Facts the team would otherwise ask about. | Defaults, limits and names. |
Out of scope | What the story deliberately leaves out. | The features people will assume come along. |
The "so that" clause is the one teams skip and the one that matters most. "So that they can see our invoices without sharing my login" tells the developer that a shared password is the real problem, which rules out a cheaper fix that misses it.
Write criteria someone can check
Each criterion should pass or fail with no discussion. "Invites work well" can't fail. "The invite appears under Pending and the person receives an email with a link" can. Cover the unhappy paths too, such as an existing member, a full workspace or an expired link, because those are the cases that ship broken.
Exact copy belongs in the criteria when it matters, as in the expired-link message above. A developer or an agent will otherwise write its own.
Keep stories small
A story should fit in a few days of work. When one grows, split it by behavior the user notices (invite, accept, revoke) rather than by layer (database, API, UI), so each piece is still something a person can try.
Variant: a story in an issue
When stories live in your tracker instead of the repository, the same parts fit in an issue body:
**As a** workspace owner, **I want** to revoke a pending invite, **so that** the wrong person
can't join.
**Done when**
- [ ] A revoked invite disappears from Pending.
- [ ] Its link shows "This invite has expired. Ask the owner for a new one."For a feature larger than a few stories, write a PRD and keep the stories inside it.