Skip to content
Move custom links under /@handle
Sniptide

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

docs/stories/team-invites.mdRaw
# 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.

Terminal
claude mcp add --transport http sniptide https://app.sniptide.com/api/mcp
Prompt
Read 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:

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.

All templates
  • PRD
    SpecsPRD template for AI coding agents

    A PRD template written so a coding agent can build from it, with numbered requirements, scope limits, technical notes and checkable acceptance criteria.

  • Project setupGitHub issue templates

    GitHub issue form templates for bug reports and feature requests, plus a config.yml that sends questions and security reports elsewhere.

  • Changelog
    WritingChangelog and release notes template

    A CHANGELOG.md template in the Keep a Changelog format, with a summary per release, the six change types and comparison links you can copy.

Pick where your library lives.

Use sniptide.com

Save your first pattern in the app, then connect Claude Code, Cursor or Codex with one sign-in in the browser.

Run it on your own server

One image and a database give you the app, the API and the MCP endpoint. Sniptide is open source under AGPL-3.0.

$docker compose up -d