---
name: backlog-writing
description: Write and split product backlog items that a team can estimate, build and test - INVEST checks, story splitting patterns, "As a / I want / so that" wording, Given/When/Then acceptance criteria, Definition of Ready and Done, and the mapping to Azure Boards work item types and fields (System.Description, Microsoft.VSTS.Common.AcceptanceCriteria, HTML formatting). Use this whenever the user asks to write, split, rewrite or refine user stories, product backlog items, features, epics, tasks or bugs; pastes a PRD, feature idea, meeting notes or a vague ticket and wants "stories out of this"; asks whether a story is too big, how to write acceptance criteria, what Given/When/Then should contain, what a Definition of Ready is, or which Azure Boards field or work item type to use in the Agile, Scrum, CMMI or Basic process. Also apply it when drafting the acceptance criteria section of a plan or a bug report's expected/actual wording.
metadata:
  technology: General
  type: development
---

# Backlog Writing
> **Targets:** Azure Boards (Agile, Scrum, CMMI and Basic processes) · **Verified:** 2026-09 against https://learn.microsoft.com/azure/devops/boards

A good backlog item is a conversation starter with a test attached: small enough to finish in days, valuable on its own, and specific enough that "done" is not a matter of opinion. Write for the person who will build and the person who will verify, not for the person who had the idea.

## 1. Decide first

| Question | Default | Change when |
|---|---|---|
| Which level is this? | Story (one sprint, one outcome) | Spans several sprints or teams → Feature; one technical step of a story → Task; a defect in shipped behaviour → Bug, kept as a Bug |
| Which story type name? | The project's process decides: User Story (Agile), Product Backlog Item (Scrum), Requirement (CMMI), Issue (Basic) | Never guess; read the parent's type or the project's work item types |
| Where do acceptance criteria go? | The Acceptance Criteria field | The type has no such field (Basic Issue, Task, some inherited types) → an "Acceptance criteria" heading inside the Description |
| How many criteria? | 2–6 per story, at least one error or edge path | More than 6 → the story is probably two stories |
| Estimate now? | Size S/M/L in the draft | The team estimates in points at refinement; never fill points for them |

## 2. Shape the item

1. **One outcome per item.** "As a <role>, I want <capability>, so that <benefit>." The benefit must be observable by that role; if you cannot name one, the item is a task, not a story.
2. **INVEST before you finish:** Independent (no hidden ordering), Negotiable (describes the what, not the UI or the code), Valuable (the role gets something), Estimable (the team can size it without a spike), Small (days, not weeks), Testable (every criterion has a pass/fail answer). One failed letter → split or rewrite.
3. **Split large items with a pattern, not by layer.** Workflow steps, business-rule variations, happy path first then edge cases, data variations, interfaces and platforms, CRUD operations, simple-then-performant, spike for the unknown. Never "front end story + back end story": neither delivers value alone. Patterns with examples: `references/splitting-patterns.md`.
4. **Keep bugs as bugs:** repro steps (numbered, from a known state), expected vs actual (exact values or messages), environment and version, impact. Do not rewrite a bug as a story.
5. **Write out-of-scope and assumptions** explicitly; they prevent the item from growing during the sprint.

## 3. Write acceptance criteria

- **Given / When / Then**, one behaviour per criterion, concrete values: `Given order 1002 with 4 lines, when I choose "Export CSV", then picking-1002.csv downloads with a header row and 4 data rows.`
- Cover the **happy path, at least one error path, and the boundary** (empty, maximum, permission denied). "Works correctly", "is fast", "is user-friendly" are not criteria; give the number, the message, the state.
- Non-functional needs are criteria too: `Given 5,000 lines, when I export, then the file is ready within 2 seconds`; accessibility: `then the button is reachable by keyboard and announced as "Export CSV, button"`.
- Criteria describe behaviour, never implementation ("calls the export service" is a task detail).

## 4. Definition of Ready and Done

**Ready** (before a sprint): title states the outcome; story text with role and benefit; acceptance criteria in Given/When/Then; dependencies and out-of-scope listed; sized by the team; no open question that blocks the first day of work.
**Done** (before closing): all criteria verified (by test or a named manual check); tests added at the right layer; documentation, configuration and rollout notes updated; reviewed and merged; no known defect left unlogged.

## 5. Put it in Azure Boards

| Draft field | Field reference name | Notes |
|---|---|---|
| Title | `System.Title` | Outcome, not activity ("Export picking list as CSV", not "CSV work") |
| Story text | `System.Description` | Large-text field (see below) |
| Acceptance criteria | `Microsoft.VSTS.Common.AcceptanceCriteria` | Large-text field; falls back to Description (see Decide first) |
| Repro steps (Bug) | `Microsoft.VSTS.TCM.ReproSteps` | Large-text field |
| Size | `Microsoft.VSTS.Scheduling.StoryPoints` (Agile), `.Effort` (Scrum), `.Size` (CMMI) | none in Basic |
| Tags | `System.Tags` | semicolon-separated |
| Area / Iteration | `System.AreaPath` / `System.IterationPath` | inherit from the parent |

Those three large-text fields are **HTML by default**. Azure Boards also accepts Markdown in them, per work item and per field, and that switch is one-way. So say which format you are sending: through the REST API add `{"op":"add","path":"/multilineFieldsFormat/System.Description","value":"Markdown"}`, and through the Azure DevOps MCP server pass `format: "Markdown"` (or `"Html"`) on the field you write. Markdown text saved into a field still set to HTML renders as one flat line — the most common way a good story arrives unreadable. Field-by-field details and both formats side by side: `references/azure-boards-fields.md`.

## 6. Deliverable format

```
## Draft backlog
| # | Type | Title | Parent | Size | Dependencies |

### <#>. <Title>
As a <role>, I want <capability>, so that <benefit>.
**Acceptance criteria**
- Given <context>, when <action>, then <outcome>.
**Non-functional requirements:** … **Dependencies / assumptions:** … **Out of scope:** …

## Open questions
- <question> - assumption used: <…>
```

## Checklist

- [ ] Each item names one role and one observable benefit
- [ ] Each story passes all six INVEST letters, or is split with a named pattern
- [ ] 2–6 Given/When/Then criteria per story, with concrete values and one error or boundary path
- [ ] Bugs keep repro steps and expected vs actual; not rewritten as stories
- [ ] Out of scope and assumptions are written down; unknowns are open questions
- [ ] Type name and fields match the project's process; the format sent matches the field's format
- [ ] No implementation detail in criteria; tasks hold the technical steps
- [ ] No secrets, credentials or personal data in any field

## Anti-patterns

- **"As a user, I want a button"** → name the real role and the outcome the button delivers.
- **Layer split (API story + UI story)** → split by workflow step or business rule so each story ships value.
- **Criteria such as "works as expected"** → write the input, the action and the exact result.
- **Epic-sized story with 15 criteria** → a Feature with 3–6 stories; criteria move down with them.
- **Bug rewritten as a story** → keep the Bug type with repro steps; the fix's tests are the criteria.
- **Markdown pasted into a field left as HTML** → send `format: "Markdown"` with it, or convert to `<p>` and `<ul><li>` first.

## Go deeper

- `references/splitting-patterns.md` — the eight splitting patterns with a before/after example each.
- `references/azure-boards-fields.md` — work item types per process, hierarchy and link types, field reference names, HTML formatting.
- Sibling skills: `api-design` when a story defines an API contract; the stack's `*-testing` skill to turn criteria into tests.
