EARS, Fifteen Years On: The Requirements Format Built for the Agent Era

In 2009, Alistair Mavin sat with the airworthiness regulations for a Rolls-Royce jet engine control system and found something quietly…


EARS, Fifteen Years On: The Requirements Format Built for the Agent Era

In 2009, Alistair Mavin sat with the airworthiness regulations for a Rolls-Royce jet engine control system and found something quietly useful. The regulations mixed objectives, implicit requirements, explicit requirements, lists, and guidance, all at different levels and all in ordinary prose. Buried in the mess, the requirements that read cleanly shared a structure. Same clause order every time. A small set of words marking the trigger, the condition, the system, and the response. Mavin pulled the shape out, formalized it, and presented it at the IEEE International Requirements Engineering Conference that year. He called it the Easy Approach to Requirements Syntax. EARS.

The problem he was attacking has a long pedigree. Stakeholder requirements get written in plain English, and plain English hides its gaps. A sentence reads fine to its author and means three different things to three engineers downstream. On a jet engine program, that ambiguity propagates into rework, schedule slip, and risk nobody priced. Mavin saw that the fix needed no formal mathematical notation, only a gentle constraint on the English language.

What EARS actually is

EARS defines a grammar for requirements. Nothing about it ships as software, and that distinction matters once we reach the tooling. The grammar gives every requirement one canonical shape:

WHILE , WHEN , the SHALL .

The clauses always appear in that temporal order, and a small keyword set marks each one. From that single template, five patterns fall out.

Ubiquitous requirements hold all the time. They carry no trigger and no precondition: the control system shall maintain oil pressure above the minimum threshold.

Event-driven requirements fire on a trigger, which the keyword WHEN introduces. When the pilot advances the throttle, the control system shall increase fuel flow.

A state-driven requirement holds for the duration of a state, opened by WHILE. While the engine is in shutdown, the control system shall inhibit ignition.

Failure cases get their own pattern, the unwanted-behavior requirement, built from IF and THEN. If a sensor reading falls outside its valid range, then the control system shall flag the reading as invalid.

Some requirements apply only when a feature is present, and WHERE marks those. Where the aircraft includes thrust reversers, the control system shall monitor reverser deployment.

The sixth case is a combination. Stack a WHILE and a WHEN in front of the same SHALL and you get a complex requirement carrying both a precondition and a trigger. The keyword set stays small, the clause order fixed. A reader learns the whole grammar in an afternoon and never relearns it, per the author.

The SHALL carries more weight than it looks. It marks the mandatory system response and walls it off from everything that is context. Each EARS requirement names exactly one system, gives it one or more responses, and ties those responses to the conditions under which they hold. That makes the requirement testable on its face. When the throttle advances, fuel flow increases. You can write that test without a meeting.

Where it went for fifteen years

EARS did not vanish after 2009. It spread through the part of the industry that already cared about requirements: systems engineering, safety-critical work, aerospace, automotive, and medical devices. Bosch, Daimler, Dyson, Honeywell, Intel, NASA, Rolls-Royce, and Siemens picked it up. By 2019, Mavin and Philip Wilkinson published “Ten Years of EARS” in IEEE Software, a retrospective on a notation that had become standard practice across the safety-critical industries, where the cost of a faulty requirement runs high.

It stayed in that lane. The average web team shipping a CRUD app never met EARS. Requirements there lived in Jira tickets and Slack threads, written in whatever prose the author reached for, reviewed lightly or not at all. Constraining requirement language read as overhead, the sort of thing aerospace did because regulators demanded it. For a human team with shared context and the ability to walk over and ask, the overhead often was not worth paying. Someone could fill the gap with judgment.

Then the implementer stopped being a person.

Details stopped being optional

An AI coding agent has no shared context, and it cannot walk over and ask. It has a context window and the text you put in it. When a requirement leaves a gap, a human engineer fills it from domain knowledge and a quick question. An agent fills it from its prior, a statistically plausible guess about what you probably meant. The guess looks right and it compiles. You find where it drifted from your intent three weeks later.

This is the failure mode that earned a name in 2025. Vibe coding, prompting an agent in loose natural language and accepting whatever comes back, works beautifully for a prototype and falls apart somewhere past a few hundred lines. The agent guesses at everything left unstated, and the guesses compound into a codebase that does almost what you wanted. The fix that emerged across the whole industry was structural. Write the specification first, define the behavior and the constraints and the acceptance criteria, then let the agent implement against that contract.

Spec-driven development is the label, and EARS fit exactly where it was needed. The notation that constrains English into trigger, condition, system, and response is, by an accident of its original design, a format an agent parses without guessing. GitHub Spec Kit, Claude Code, Cursor, and the rest each shipped their own flavor of the same idea through 2025 and into 2026. DeepLearning.AI now runs a short course on spec-driven development with coding agents. The methodology crossed from experimental to ordinary in about a year.

The precision that read as aerospace overhead in 2014 turned load-bearing in 2026. EARS will not let you write “the system should handle errors gracefully,” because the grammar demands you name which trigger, which system, and which response. That demand was always good hygiene. With an agent reading the requirement, that hygiene decides whether the code follows your spec or the model’s guess at it.

What the agent writes on its own

Ask a coding agent for requirements with no further instruction, and watch what it produces. The output is usually competent and rarely EARS. Claude Code, asked cold, writes a structured markdown document: numbered functional requirements in RFC 2119 style, “the system MUST rate-limit requests,” with acceptance-criteria bullets underneath. Its native mechanism for specs is the CLAUDE.md file, plain markdown that carries project instructions across sessions, and it stays deliberately format-agnostic. EARS turns up in Claude Code only when someone installs it, through a spec workflow, a slash command, or a requirements subagent told to use the notation.

So the honest claim is narrow. Agents do not reach for EARS by instinct. The teams that have thought hardest about spec-driven development adopt it on purpose, because it fixes something their default output leaves broken.

The gap is structural, and it helps to name what already works. RFC 2119 is the reason MUST, SHALL, SHOULD, and MAY carry exact weight in a specification: MUST is mandatory, SHOULD is a strong recommendation open to a justified exception, MAY is discretionary. An agent reading SHOULD treats it as room to skip, which is what the word means. That precision is worth keeping, and the model already reaches for it unprompted.

RFC 2119 gives no fixed place for the trigger and the condition. “The system MUST lock the account after too many failed attempts” leaves “too many” and “after” floating, and two authors will phrase the surrounding context two different ways. EARS supplies the missing structure, putting the trigger in the WHEN clause, the state in the WHILE clause, the failure case in the IF/THEN clause, and the response after the modal verb. The two compose without friction, because EARS already uses “shall” for the response. Keep the clause structure from EARS and let an RFC 2119 keyword carry the obligation: WHEN the failed-attempt counter reaches five within fifteen minutes, the auth service SHALL lock the account for thirty minutes. That requirement is testable as written, and it reads the same no matter who on the team produced it.

Example: Account Lockout Requirements

Before (RFC 2119, ambiguous): “The system MUST lock the account after too many failed attempts.” Both “too many” and “after” are left floating.

After (EARS + RFC 2119): the one vague sentence resolves into a set of testable requirements, each with the trigger, condition, and response in fixed places.

US-1: Temporary account lockout

As an account owner, I want repeated failed logins to lock my account temporarily, so that a brute-force attempt cannot keep guessing.

Acceptance criteria:

AC-1.1: WHEN a login attempt provides invalid credentials, the auth service SHALL increment the account’s failed-attempt counter.

AC-1.2: WHEN the failed-attempt counter reaches 5 within a 15-minute window, the auth service SHALL lock the account for 30 minutes.

AC-1.3: WHILE an account is locked, WHEN a login is attempted, the auth service SHALL reject the attempt and SHALL NOT extend the lock duration.

AC-1.4: WHEN a login attempt succeeds, the auth service SHALL reset the failed-attempt counter to zero.

AC-1.5: WHEN the 15-minute window elapses with fewer than 5 failed attempts, the auth service SHALL reset the failed-attempt counter to zero.

AC-1.6: WHERE email notifications are enabled, WHEN an account becomes locked, the auth service SHALL send the account owner a lock notification.

Patterns used

Event-driven (WHEN): AC-1.1, AC-1.2, AC-1.4, AC-1.5

Complex (WHILE + WHEN): AC-1.3

Optional feature (WHERE): AC-1.6

Every response sits after a SHALL, and the negative obligation in AC-1.3 is stated explicitly rather than left implied.

The case for one format

Go ships with gofmt. You do not configure it or keep a style guide for it. You run it, and every Go file in the world comes out in the same canonical shape regardless of who typed it. Rob Pike’s line about it has aged well: gofmt’s style is no one’s favorite, yet gofmt is everyone’s favorite. One canonical form, whatever its style, means no one spends attention on formatting, diffs stay small, and tooling can rely on it.

Requirements have lived without a gofmt. Every author writes them in a personal idiom, every reader re-parses that idiom, and every agent reading the backlog inherits the variance. EARS supplies the canonical grammar that fixes the shape. Run a requirement through it and the trigger sits in the WHEN clause, the response follows the SHALL, the failure case takes the IF/THEN form, every time. A reviewer reads for meaning rather than decoding each author’s voice. The agent no longer infers the structure, because the structure is fixed.

Owning the grammar and applying it across a team are two different problems, and the second one needs a tool.

Making EARS the default

The cheapest place to enforce a format is the tool that writes it. Claude Code loads skills from a .claude/skills directory, each one a folder holding a SKILL.md file: a short description telling the agent when the skill applies, and a body of instructions it follows when the description matches. Commit that folder to the repository and every teammate's Claude Code inherits the same skill, the way they already inherit a linter config or an .editorconfig.

A requirements skill is a small file. Its description claims any work that touches requirements or acceptance criteria, so it triggers without anyone typing “EARS.” The body carries the grammar: the five patterns, the rule of one system and one trigger per requirement, the RFC 2119 keyword for the response, and a short recipe for turning loose prose into EARS. The frontmatter alone does most of the routing:

---
name: ears-requirements
description: Write and convert requirements and acceptance criteria into
EARS, using RFC 2119 keywords for obligation strength. Use whenever
writing or reviewing requirements, acceptance criteria, user stories,
or a requirements.md, even if the user does not say "EARS."
---

The body’s job is to override the default from a few paragraphs back. Instead of loose RFC 2119 prose, the agent writes “WHEN a login attempt provides invalid credentials, the auth service SHALL reject the attempt and return HTTP 401.” Same RFC 2119 keyword the model already prefers, now seated in a fixed clause structure and numbered as an acceptance criterion a test can cite.

This is the gofmt comparison made literal. The skill does the formatting, the repository holds it, and the canonical form ships with the code. A new engineer clones the repo and writes EARS on the first day without being told, because the agent they already use was handed the rule.

EARS workflow tooling

A skill covers the repository you commit it to, and one agent. The rest of the chain, from a rough product idea through review and into a sprint, is where some teams want a platform built around the whole workflow. Fettink is one. You describe a feature in plain language, and it generates the acceptance criteria in EARS, in the WHEN/THEN, WHILE/SHALL, and IF/THEN forms, every requirement testable and consistent no matter who wrote it.

It does not stop at the criteria. Fettink runs a four-stage pipeline, requirements to tech spec to system design to task specs, generating each stage from the one before it with a team approval gate between every step. Nothing advances until the required reviewers sign off. The EARS criteria post automatically to the linked GitHub pull requests, so the contract the agent built against travels with the code. A sprint board decomposes the task specs into pointed tickets that move through their columns as PRs open and merge.

The consistency is the part that matters here. A PM capturing requirements in Fettink’s product workflow and an engineer refining them in the spec pipeline produce requirements in the same shape, because the tool generates that shape rather than asking each person to hand-write it. The variance that used to live in the gap between authors collapses. Every requirement parses the same way, for the reviewer and for the agent alike.

I have spent enough hours hand-converting loose tickets into EARS to know that the conversion is the tax. Doing it once is fine. Doing it for every requirement, on every feature, across a team that keeps drifting back to prose, is the part that does not happen. Tooling that emits the canonical form by default is how the format survives contact with a real backlog.

Fettink is not the only tool reaching for this. GitHub Spec Kit runs an agent-agnostic version from the command line, working across many coding tools rather than tying you to one. OpenSpec, Tessl, and BMAD each stake out their own point on the same spectrum, from lightweight spec files to spec-as-source. Fettink aims at teams rather than solo developers, and the handoff is where that shows: a PM captures requirements and business value, the tool generates the EARS criteria, and one click hands engineering a pre-populated spec session with the approval gates already in place. Pick whichever fits how your team already works. I reached for it here because it shows the single-format idea end to end, from a PM’s sentence to a ticket on the board.

Why now

The grammar is fifteen years old and unchanged, which is the useful part. EARS did not adapt to the agent era. The constraint it imposed for jet engine regulators, forcing the trigger, the condition, the system, and the response into the open, is exactly the constraint an agent needs in order to implement without filling the gaps itself. The cost of leaving a gap rose. A vague requirement used to cost a conversation with the engineer who caught it. Handed to an agent, it costs a code path, written with full confidence, wrong in a way that survives a quick read and surfaces later in production. The places that adopted EARS fifteen years ago were the ones where a wrong requirement killed people, and they kept it because it worked. The rest of us are arriving at the same conclusion now, at the smaller stakes of software that merely ships wrong.

By Joshua McDonald on May 25, 2026.

Canonical link

Exported from Medium on August 26, 2026.