Founders

A one-page spec for a first release

A first release needs a short document that settles four things: who it is for, what is in, what is deliberately out, and how anyone will know it is done. Everything else in a long spec is either a guess that will age badly or a decision nobody has made yet. This page gives a one-page template, an annotated fictional example, and a small script that catches the gaps most specs have.

The example product is a shared grocery list. It is fictional, as are the numbers in it.

What the page is for

A spec earns its place by doing three jobs.

  • Agreement. Two people reading the same page should expect the same thing at launch. If you work alone, the second reader is you in three weeks.
  • A cut list. When time runs short, the page already says what goes first, so the decision is not made under pressure.
  • A test. Each required item has a check someone else could run, which turns "finished" from a feeling into something visible.

DORA's description of a minimum viable product is a useful size guide: a prototype with just enough features to enable validated learning about the product and its business model. A first release is judged by what it teaches you, so the spec should hold only what that learning needs.

The skeleton, filled in

Here is the whole example. The sections that follow explain each part.

# Pantry List, release 1 (fictional example)
Owner: one named person. Status: draft. Date: 2026-10-17.

## Problem and user
Housemates share a grocery list through a chat thread, so items are repeated, missed or bought twice. The user is one person adding items on a phone in a shop aisle.

## Goal
Two people can keep one shared list without a chat thread. We will know when 3 households each use it for a full week of shopping.

## Scope
M1 Anyone with the list link MUST be able to view and edit that list. No accounts.
M2 Users MUST be able to add, tick off and remove items.
M3 Changes on one device MUST appear on another.
M4 Every screen MUST work by keyboard alone and at 360 px width.
S1 The list SHOULD suggest items typed before.
S2 The list SHOULD offer a dark theme.
W1 Not in this release: accounts, native apps, recipes, budgets.

## Done when
A1 (M1) a second browser opened with the link shows the same items and can edit them.
A2 (M2) an item can be added, ticked and removed using only a phone screen.
A3 (M3) an item added on device A appears on device B within 5 seconds, in 10 of 10 trials.
A4 (M4) all actions work with the keyboard alone, an automated accessibility check reports no violations on the three screens, and a manual pass finds none.

## Constraints
Lab LCP at or under 2.5 s, INP at or under 200 ms and CLS at or under 0.1 on the throttled test profile. Text meets WCAG 2.2 level AA contrast.

## Risks and open questions
Q1 Does a link alone give enough privacy for a grocery list? Decide before launch.
R1 If sync is late, M3 fails and the release waits. S1 and S2 are cut first.

## Release and rollback
Share with 3 households. The previous deployment stays available for instant rollback.

Problem and user

Start with one person doing one thing, as the GOV.UK Service Manual does for user stories: the actor, what they need, and why. The Manual's most useful instruction is that the goal is the most important part, and that if you struggle to write it, you should reconsider why you think you need the feature. Apply that to the whole release. If the problem takes more than two sentences, the release has more than one problem.

Name a situation, not a demographic. "One person adding items on a phone in a shop aisle" tells you the screen is small, one hand is busy and the connection may be poor. "Busy households" tells you nothing you can build against.

Goal

Write one sentence about what the release lets someone do, then one about how you will recognise success. Keep the second one observable and small. In the example it is three households using the list for a full week of shopping, which you can verify by asking them. Avoid goals that need an audience you do not have yet, and avoid goals that are only an internal feeling of progress.

Scope: Must, Should and Won't

Each in-scope line carries a requirement level. Borrowing the vocabulary of RFC 2119 gives you words with defined strength: MUST is an absolute requirement, and SHOULD means there may be valid reasons in particular circumstances to ignore the item, as long as the consequences are understood. RFC 8174 later clarified that only the uppercase forms carry those meanings. RFC 2119 also advises using the words with care and sparingly, and only where they are genuinely needed, which is good advice for a spec: if everything is a MUST, the word tells the reader nothing.

LabelMeaning in the specWhat happens when time runs short
MUST (M)The release is not shippable without itThe date moves, or the release is cancelled
SHOULD (S)Wanted, with a reason to cut if neededCut first, in the order written
Not in this release (W)Named and refused for nowStays out; goes to the next page

The third row does the most work. Writing down what you refuse stops it returning as a "small addition" in the final week. List it by name, as the example does with accounts, native apps, recipes and budgets, so a later request meets a written decision.

The example caps required items at five. That cap is a house rule, not a standard, and the script below enforces it so that you notice when a release is trying to be two.

Done when

GOV.UK describes acceptance criteria as a list of outcomes used as a checklist to confirm the work is doing its job, usually phrased "it's done when". Write one for every MUST and link it by id, so a reader can follow M3 to A3 without searching.

A criterion is good if two people would give the same verdict. Compare these two for the same item:

  • "Sync feels fast."
  • "An item added on device A appears on device B within 5 seconds, in 10 of 10 trials."

The second can fail, and that is why it is useful. Notice what it still leaves open: which network, which devices. Add those when they could change the outcome, and leave them out when they could not.

Constraints

Quality targets belong in the spec because they are the first thing cut under pressure. Two kinds are worth stating for a web product.

  • Accessibility. Name a target, such as WCAG 2.2 level AA, and say which screens it covers. Automated checks find only a share of problems, so pair them with a manual keyboard pass, as criterion A4 does.
  • Performance. web.dev lists the "good" targets for Core Web Vitals as LCP within 2.5 seconds, INP of 200 milliseconds or less and CLS of 0.1 or less, assessed at the 75th percentile of page loads. Those targets are defined for field data from real visits. A new product has few visits, so the example states them as lab targets on a throttled test profile and says so. See Core Web Vitals in plain language for what each metric means and the difference between lab and field data.

Risks and open questions

Keep two short lists. Open questions are decisions someone still owes, each with a deadline: the example asks whether a link alone gives a grocery list enough privacy and sets the answer to land before launch. Risks are things that could break a MUST, each paired with the response you will take. Pairing the risk with the cut order (here, that late sync holds the release and S1 and S2 go first) means the plan survives its first bad day.

Release and rollback

Say who gets it first, how many, and how you will go back. A first release that cannot be reversed deserves a second look at the scope. The mechanics are covered in preview deployments and rollbacks and depend on your host; the point for the spec is that the answer is written down before launch day, not discovered on it.

Four ways a one-page spec goes wrong

  • No refusal list. Without the Not-in-this-release line, every stakeholder's idea is an implicit yes.
  • Criteria that restate the requirement. "M3: changes appear on another device" followed by "A3: changes appear on another device" checks nothing. A criterion needs a number, a count or an observable action.
  • Constraints left for later. Accessibility and speed cost the least when they are designed in, and they are the first things dropped when a date slips, so they belong beside the scope.
  • Open questions with no owner or date. An unanswered question is a hidden MUST. Give each one a name and a deadline, or move it to the refusal list.

The same page works as a brief for anyone else building with you, human or tool. If part of the build will be drafted with an AI tool, the spec supplies the context that a good first-draft prompt needs: the user, the scope and the limits.

Checking the spec with a script

A spec is only as good as its links: every MUST needs a criterion, and every criterion needs something it checks. The script below is a plain-text linter for the format above. It checks the required headings, finds each M item and its matching A line, checks that M lines contain the word MUST, caps the number of MUST items at five and the length at 450 words.

import { readFileSync } from 'node:fs';
const spec = readFileSync(process.argv[2], 'utf8');
const lines = spec.split('\n');
const problems = [];

const need = ['Problem and user', 'Goal', 'Scope', 'Done when', 'Constraints', 'Risks and open questions', 'Release and rollback'];
for (const h of need) if (!lines.includes('## ' + h)) problems.push('missing section: ' + h);

const musts = lines.filter((l) => /^M\d+ /.test(l)).map((l) => l.split(' ')[0]);
const criteria = lines.filter((l) => /^A\d+ \(M\d+\)/.test(l));
for (const id of musts) if (!criteria.some((c) => c.includes('(' + id + ')'))) problems.push(id + ' has no acceptance criterion');
for (const c of criteria) {
  const ref = c.match(/\((M\d+)\)/)[1];
  if (!musts.includes(ref)) problems.push(c.split(' ')[0] + ' points at ' + ref + ', which is not a Must');
}
for (const l of lines.filter((l) => /^M\d+ /.test(l))) if (!l.includes('MUST')) problems.push(l.split(' ')[0] + ' lacks the word MUST');
if (musts.length > 5) problems.push(musts.length + ' Musts: a first release rarely survives more than five');

const words = spec.split(/\s+/).filter(Boolean).length;
if (words > 450) problems.push(words + ' words: over the 450-word limit');

console.log('words:', words, ' musts:', musts.length, ' criteria:', criteria.length);
console.log(problems.length ? problems.join('\n') : 'ok');

Run on the example, it printed:

words: 324  musts: 4  criteria: 4
ok

With the A3 line deleted, the same script printed the failure it exists to catch:

words: 304  musts: 4  criteria: 3
M3 has no acceptance criterion

The 450-word limit is a number picked for this template, not a standard for what fits on a page. Set your own and keep it.

When it does not fit

If the spec runs past a page, the release is too big, not the font too large. GOV.UK calls stories that would take more than a few weeks to develop and test epics, and advises splitting them into stories that fit within an iteration. DORA goes further for day-to-day work and recommends batches that can be finished in hours to a couple of days. Split the release by user outcome (a person can do a complete thing), not by technical layer (the database, then the screens), so each piece can be tried by someone.

Update the spec when decisions change, and add a dated line at the bottom for each change. A spec that nobody amends gets replaced by memory.

Checklist

  • State one user in one situation, and write the goal in a sentence you can check.
  • Label scope MUST, SHOULD or Not in this release, and keep the MUST list short.
  • Give every MUST an "it's done when" criterion that two people would judge the same way.
  • Put accessibility and performance targets in the constraints, and say whether they are lab or field targets.
  • Write the cut order, the open questions and the rollback before you start building.

Questions and answers

Why one page?

The limit forces choices. A spec that has room for everything decides nothing, while a page has room only for what would change the work: who it is for, what is in, what is out and how you will know it is finished. Treat the page as a constraint you set yourself, not a rule from any standard.

What is the difference between a user story and a spec?

A story, in the GOV.UK Service Manual's format, names the person, what they need and why. A spec for a release holds several of those needs together, adds what is out of scope, and states how each one is checked. The stories are the raw material.

How many items can a first release hold?

DORA recommends splitting work until a batch can be finished in hours to a couple of days. For a release the number is your choice; the example here caps required items at five, a house rule rather than a standard. If you exceed it, you are probably describing two releases.

Do the capitalised words need to follow RFC 2119?

No, but borrowing them helps. RFC 2119 defines MUST as an absolute requirement and SHOULD as something with possible valid reasons to ignore. RFC 8174 clarifies that only the uppercase forms carry those meanings, so keep them uppercase and use plain lowercase for ordinary prose.

Sources

  1. Writing user stories (GOV.UK Service Manual) gov.uk
  2. RFC 2119: Key words for use in RFCs to Indicate Requirement Levels rfc-editor.org
  3. RFC 8174: Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words rfc-editor.org
  4. Working in small batches (DORA) dora.dev
  5. Web Vitals (web.dev) web.dev