---
title: "Writing requirements (EARS+)"
description: "How MySpec writes requirements and acceptance criteria with EARS+, with the patterns, short examples and tips for reviewing them."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.myspec.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Writing requirements (EARS+)

MySpec writes requirements and their acceptance criteria in **EARS+**. Knowing
the patterns makes generated requirements faster to review and easier to
correct.

**EARS** stands for *Easy Approach to Requirements Syntax*. It was developed by
Alistair Mavin and colleagues at Rolls-Royce. It uses a few keywords and a fixed
clause order to turn loose sentences into precise, testable requirements.
**EARS+** adds patterns for acceptance criteria, so each criterion reads like a
test case.

## Why EARS+

- **Less ambiguity.** The keywords say exactly when a requirement applies.
- **Consistency.** Every requirement has the same shape, whoever wrote it.
- **Easier testing.** A criterion such as "WHEN … THEN … SHALL …" maps directly
  to a test.
- **Gaps show early.** If you can't fill in the trigger or the response, some
  information is missing.

## The requirement patterns

The clauses of an EARS requirement always appear in the same order:

```text
WHILE <state>, WHEN <trigger>, the <system> SHALL <response>
```

Only the system and its response are required. Each pattern adds a keyword:

| Pattern | Keyword | Template |
|---|---|---|
| Ubiquitous | None | `The <system> SHALL <response>` |
| State-driven | `WHILE` | `WHILE <state>, the <system> SHALL <response>` |
| Event-driven | `WHEN` | `WHEN <trigger>, the <system> SHALL <response>` |
| Optional feature | `WHERE` | `WHERE <feature is included>, the <system> SHALL <response>` |
| Unwanted behavior | `IF` … `THEN` | `IF <unwanted condition>, THEN the <system> SHALL <response>` |
| Complex | A combination | `WHILE <state>, WHEN <trigger>, the <system> SHALL <response>` |

Examples:

- **Ubiquitous**: The system SHALL store all timestamps in UTC.
- **State-driven**: WHILE the device is offline, the app SHALL save new notes
  locally.
- **Event-driven**: WHEN a user selects "Export", the system SHALL download the
  current table as a CSV file.
- **Optional feature**: WHERE two-step sign-in is enabled, the system SHALL ask
  for a one-time code after the password.
- **Unwanted behavior**: IF a payment is declined, THEN the system SHALL keep
  the order open and show the reason.
- **Complex**: WHILE an upload is in progress, WHEN the user closes the tab,
  the app SHALL ask for confirmation.

Unwanted-behavior requirements are the ones most often forgotten. They describe
errors, failures and edge cases.

## How acceptance criteria are written

In `requirements.md`, every functional requirement (`FR-001`, `FR-002`, …) has
a description, the user roles it applies to, and acceptance criteria. Each
criterion follows one of these EARS+ patterns:

| Pattern | Template |
|---|---|
| Simple event | `WHEN <event> THEN <system> SHALL <response>` |
| Event with condition | `WHEN <event> AND <condition> THEN <system> SHALL <response>` |
| State-based | `WHILE <state> THEN <system> SHALL <response>` |
| Error handling | `IF <pre-condition> THEN <system> SHALL <response>` |
| Conditional event | `IF <pre-condition> WHEN <event> THEN <system> SHALL <response>` |

You may also see `WHERE` for criteria that only apply when an optional feature
is on. Criteria may be numbered `AC1`, `AC2` and so on.

A functional requirement looks like this:

```md
### FR-004: Password reset
**Description:** Users can reset a forgotten password by email.
**User Role:** Registered user
**Acceptance Criteria:**
- WHEN a user requests a reset for a registered email THEN the system SHALL send a reset link to that address
- WHEN a user opens a valid reset link AND enters a new password that meets the policy THEN the system SHALL save it and sign the user in
- IF the reset link has expired THEN the system SHALL show "This link has expired" and offer to send a new one
- IF the user is signed in WHEN they open a reset link THEN the system SHALL ask them to sign out first
```

Non-functional requirements (`NFR-001`, …) have a measurable target and a
priority instead:

```md
### NFR-001: Search performance
**Description:** Search results must appear quickly.
**Target:** 95% of searches return results in under 1 second
**Priority:** High
```

### Requirements for an existing codebase

In the MySpec brownfield workflow, `requirements.md` lists only what changes.
Added (`AR-`) and changed (`CR-`) requirements use the same EARS+ acceptance
criteria. A changed requirement strikes through the old criterion and adds the
new one below it:

```md
### CR-001: Idle sign-out
**Description:** Idle sessions now end sooner to meet the new security policy.
**User Role:** All users
**Acceptance Criteria:**
- ~~AC1: WHEN a session has been idle for 60 minutes THEN the system SHALL sign the user out~~
- AC2: WHEN a session has been idle for 15 minutes THEN the system SHALL sign the user out
```

Removed requirements (`BR-`) have no acceptance criteria. They give the reason
for the removal and point to where the original requirement is described in
your code.

In the OpenSpec workflow, delta spec files use the same idea in OpenSpec's own
format: each requirement states what the system SHALL do, followed by scenarios
written as **WHEN** … **THEN** … bullets. See [Spec files](/spec-files/).

## Tips for reviewing generated requirements

Check these points when the Requirements file reaches you:

- **One behavior per requirement.** If a requirement does several unrelated
  things, ask for it to be split.
- **Specific, not vague.** Replace words such as "fast", "easy", "all" or "any"
  with values or named things: "within 2 seconds", "admins and editors".
- **Errors are covered.** For each important event, look for an `IF … THEN`
  criterion that says what happens when it goes wrong.
- **Each criterion is testable.** Read it as a test case. If you can't say how
  you would check it, it needs more detail.
- **What, not how.** Requirements should not name frameworks, databases or
  architecture. Those belong in `solution.md`.
- **Measurable targets.** Every non-functional requirement needs a number you
  can measure.
- **Consistent with the constitution.** A requirement must not break a rule
  from `constitution.md`.
- **Not too many conditions.** A requirement with more than three conditions is
  usually clearer as two or more requirements.
- **Hard to write means unclear.** If a requirement is hard to express in EARS,
  information is usually missing. Settle it before moving on.

To fix what you find, select **Request Changes** on the file card, or use
**Request change** and the feedback items on the AI review card. See
[Review each spec file](/guides/generate-sessions/#review-each-spec-file).
To ask what a requirement means without changing anything, use `/btw`, for
example `/btw what does FR-004 mean?`. After the session, change requirements
in an [Edit session](/guides/edit-sessions/).

## Learn more

- [EARS, by Alistair Mavin](https://alistairmavin.com/ears/): the official EARS
  resource.

Source: https://docs.myspec.dev/spec-files/ears-plus/index.mdx
