Requirements
A document carries its requirements beside the screens that answer them — what the product must do, the criteria that say it does, and links validate() checks.
Requirements
Requirements say what the product must do, in the same document as the screens that answer them: each one links the screens it is about, and validate() reports a link to a screen that is not there.
Requirements are a draft part of Framewerk 1: the shape may change between minor versions until it is marked stable. Screens, components, flows and styles are stable.
Examples
A screen, and the requirement it answers:
A capability and a task under it:
Anatomy
{
"id": "order-a-coffee",
"title": "A customer orders a coffee from the menu",
"type": "user-story",
"scope": "capability",
"source": "stakeholder",
"priority": "P0",
"status": "implemented",
"linkedScreens": ["menu", "order"]
}
Seven fields are required: id, title, type, scope, source, priority and status.
Because requirements are draft, a document that states a formatVersion and carries any names them at the top level: "drafts": ["requirements"]. validate() reports an error when it does not. See The document.
Scope is the level. A capability says what the product does and never closes; a task is a piece of the work that makes a capability true, and names it in parentCapabilityId.
Status is how far the work got: proposed, accepted, in-progress, implemented, blocked, verified. Why a requirement stopped being live is a separate field, resolution: fixed, wont-fix, duplicate, cannot-reproduce, superseded. A superseded requirement may name its replacement in supersededBy.
Type is one of user-story, requirement, acceptance-criteria, bug, feedback, qa-note. Source is one of stakeholder, research, agent, audit. Priority is P0, P1 or P2. A bug may carry a severity: critical, major, minor, cosmetic.
Criteria are the acceptance checklist. Each has an id unique within its requirement, a text, and verified.
Links point into the same document:
| Field | Names |
|---|---|
linkedScreens | ids from screens |
linkedFlows | ids from flowPackages |
personas | ids from project.personas |
parentCapabilityId, supersededBy | the id of another requirement |
validate() reports a missing scope, a value outside a list, and a linkedScreens, linkedFlows, personas or parentCapabilityId entry that names nothing in the document, as errors. A supersededBy that names nothing is a warning.
Optional fields: feature (the area of the product), description, tags, blockerReason, refCode (a short handle people say aloud), reporter and assignee (a name to show, never an account id), and the ISO 8601 datetimes createdAt, updatedAt, startedAt and closedAt.
A tool may add its own fields to a requirement. validate() passes over fields it does not know.
The value lists are exported, so a form or a schema reads them and does not retype them:
import { REQUIREMENT_STATUSES, validate, type Requirement } from "@framewerk/spec";
What the format does not carry
A requirement in a document is a record. Everything that does work on one stays in the tool that holds the document. Airframe adds, and does not publish:
- the account behind an assignee or reporter, the build a requirement rides, and its milestone
- Features, test plans, the roadmap and boards
- the agents and MCP server that write requirements, status reconciliation, alignment against code, and the test walker
Stability
Draft. Requirements are a draft part of Framewerk 1: the shape may change between minor versions until it is marked stable. Screens, components, flows and styles are stable.