AI 9 min

The SDD Pipeline in Practice: From EARS Syntax to Atomic Tasks

Discover how to apply Spec-Driven Development in a real cycle with Spec Kit, transforming vague ideas into atomic and governed tasks.

Written by Samir El Azem Crovetto • Senior Backend Engineer & DevSecOps

Surely after talking so much about constitutions and governance architectures, you are eager to see how all this translates into real terminal commands. At the end of the day, what we developers like is to open the console, see files, and execute things.

Today we are going to come down from the conceptual sky to the land of the terminal. We will do a full walkthrough of a real development cycle using Spec Kit (that open-source GitHub Swiss army knife we talked about in the previous post). We will simulate having to add a typical feature in a project: a table reservation system for a restaurant application.

You will see how a simple vague idea transforms into a fully governed and structured atomic checklist of tasks, leaving no room for the AI to improvise or hallucinate along the way.


1. Deploying the scaffolding: specify init

First things first. For Spec Kit to start working in the project, you need to install its CLI and initialize the repository. In production, the cleanest way to do this is using uv (the ultra-fast Python package manager) so we don't fight with global dependencies.

You just have to run this command at the root of your project:

uv tool install specify-cli
specify init my-restaurant-project --integration copilot

(Note: The --integration flag tells Spec Kit which AI agent you work with daily, whether it's Copilot, Claude Code, or any other compatible agentic editor).

This initialization command will create a hidden structure in your repository inside the .specify/ folder. That is where Spec Kit saves its command templates, validation scripts, and the internal memory of the pipeline.

Once this is done, your preferred AI agent will have automatic access to a series of slash commands (/speckit.*) directly in the editor's chat console. From here, the human stops beating around the bush interactively and starts guiding the flow.


2. Step 1: Specify without hallucinations (The magic of EARS)

Most disasters in AI-generated code happen because we ask for things like: "Create a table reservation system for me." For a human, that makes sense. For an LLM, it is an open invitation to invent. The AI will decide on its own if the user can book for a hundred people, what happens if you select a date in the past, or in what format the email is saved.

In SDD we do not let the AI assume anything. To do this, we use the specify command:

/speckit.specify Add table reservation functionality to the restaurant assistant. Customers must be able to book a table by providing their name, number of people, date, and time. They must also be able to check their reservations. The system must confirm before saving and handle special requests like "table next to the window" or "birthday celebration".

When launching this command, Spec Kit automatically creates a specific Git branch for this feature (e.g., 012-table-reservations) and generates a clean specification file at specs/012-table-reservations/spec.md.

But the truly important thing is not the file, but the syntax it uses to define the business rules. Spec Kit comes prepared to force the AI to write the rules using the EARS (Easy Approach to Requirements Syntax) notation.

EARS is basically a way of structuring logical sentences with rigid templates to eliminate any trace of ambiguity. Instead of writing free prose, the acceptance rules in spec.md are drafted following these patterns:

  • Ubiquitous (Always active):
  • Syntax: The [system] shall [do something].
  • Example: The system shall always display reservation times in a 24-hour format.
  • Event-Driven (When something happens):
  • Syntax: WHEN [the event occurs], the [system] shall [do something].
  • Example: WHEN the customer confirms the details on the screen, the system shall process the reservation.
  • Unwanted Behavior (If something bad happens, error handling):
  • Syntax: IF [an unwanted condition occurs], THEN the [system] shall [do something].
  • Example: IF the number of diners exceeds the maximum capacity of the table, THEN the system shall deny the reservation with an explanatory error message.
  • State-Driven (While in a specific state):
  • Syntax: WHILE [in this state], the [system] shall [do something].
  • Example: WHILE the payment gateway is out of service, the system shall mark the reservations as "Pending confirmation".

By forcing the AI (and ourselves) to write requirements with this level of mathematical rigor, ambiguity disappears. System behavior under edge cases is perfectly defined before writing a single line of code.


3. Step 2: /speckit.clarify (The uncomfortable interview)

Writing a perfect specification on the first try is almost impossible. We always leave some loose ends. In the traditional flow, these loose ends are discovered by the programmer mid-development who decides to improvise based on their judgment.

In SDD, before moving on to the technical phase, we execute the clarify command:

/speckit.clarify

This command is like passing a static logic test to our English or Spanish specification. Spec Kit scans the spec.md file looking for contradictions, silent assumptions, or missing data. Upon finishing, the AI does not start programming: it switches to interviewer mode and asks you multiple-choice questions.

In our reservations example, the interaction in the console would look like this:

AI: I have analyzed the reservations specification. I have 3 critical doubts to resolve before continuing:

1. Cancellations: You haven't specified if the user can cancel an already confirmed reservation. How do we proceed?

* [A] Allow cancellation at any time.

* [B] Allow cancellation only with a minimum of 2 hours in advance.

* [C] Do not allow cancellations via chat (requires calling the restaurant).

2. Diner limit per table: What is the maximum capacity allowed for a single online reservation?

* [A] Maximum 8 people (larger reservations require direct contact).

* [B] No technical limit (it is assumed there are giant tables).

3. Past dates: What happens if a user tries to book for a date that has already passed?

* [A] Deny with a 400 error.

* [B] Automatically redirect to the nearest available date.

Please reply with the chosen option for each point (e.g., 1B, 2A, 3A).

You reply in the chat quickly ("1B, 2A, 3A"), and the AI takes care of rewriting and injecting those decisions directly into the spec.md file, using the corresponding EARS syntax. The business contract is now sealed and watertight.


4. Step 3: /speckit.plan (Technical design under the Constitution's magnifying glass)

Once we know exactly what we want to build, it's time to define how we are going to do it at an architectural level. For that, we launch the plan command:

/speckit.plan The backend will use Node.js with Express, saving data in a local SQLite database to simplify deployment.

Magic happens under the hood here. The /speckit.plan command reads our polished specification, but it also mandatorily loads the repository's Constitution (constitution.md) that we talked so much about in the previous post.

The AI analyzes your technical proposal and crosses it with the immutable laws of your architecture. If in your Constitution you put that "It is forbidden to add external dependencies without validation" or that "Every database must be migrated using reversible SQL files", the technical plan will adapt strictly to those restrictions.

As a result of this step, Spec Kit will generate three fundamental files within the feature folder:

  • plan.md: The technical roadmap. Which files are going to be created, which existing services will be modified, and how the logic will be structured.
  • data-model.md: The database design. In our case, the definition of the reservations table with its types (UUID for the id, VARCHAR for the name, INTEGER for the quantity, etc.) and its integrity constraints.
  • research.md: Research notes. If the AI had to search for the compatibility of a date library or analyze the performance of SQLite under concurrency, it leaves it documented here with its technical justification.

5. Step 4: /speckit.tasks (The real execution checklist)

With the technical design approved, the last thing we want is for a developer (or an AI) to try to implement the entire reservation system in a single sitting. Gigantic changes in a single prompt saturate the context window of the models, causing incomplete code or broken patches.

To avoid this, we break the plan down into ultra-granular tasks using the command:

/speckit.tasks

Spec Kit reads the plan, the data model, and the designed APIs, and spits out a file called tasks.md in the feature folder. This file is a checklist with a super strict and sequential format:

# Task Checklist: Table Reservation Feature

## Phase 1: Database and Integration
- [ ] [T001] [P] Create SQL migration script for the `reservations` table in `db/migrations/003_reservations.sql`.
- [ ] [T002] [P] Add initial test data (seed) in `db/seeds/reservations_seed.sql`.

## Phase 2: Contracts and API Logic (TDD)
- [ ] [T003] [P] Write integration tests for the `POST /api/reservations` endpoint verifying rejection of past dates and capacities over 8 people.
- [ ] [T004] [P] Write integration tests for `GET /api/reservations` verifying listing by user.

## Phase 3: Controllers Implementation
- [ ] [T005] Create Express controller `controllers/reservations.js` with input validations.
- [ ] [T006] Create database service `services/reservations.js` to persist reservations.

## Phase 4: Polish and Verification
- [ ] [T007] Run linter and full test suite to guarantee zero regression.

State management in tasks

Pay attention to the details of this checklist, because they are not mere ornaments:

  • The [P] (Parallel) tag: Tells the execution engine that these tasks are independent and can be performed in parallel by different sub-agents (e.g., creating the database table and preparing the test data).
  • The task IDs ([T001], [T002]): Serve so that the implementation agent knows exactly what it is doing and can update the state atomically.

During the actual coding phase (/speckit.implement), the agent will mark the status of each task using a syntax that supports pauses and interruptions:

  • [ ] - Pending task.
  • [>] - Executing task (the agent is working on it right now).
  • [x] - Successfully completed task.
  • [!] - Failed or blocked task (if the test fails or there is a compilation error).

6. Step 5: /speckit.analyze (The final guardian)

Before allowing the implementation agent to start writing code, we have a final optional but highly recommended security step:

/speckit.analyze

The analyze command performs a cross-consistency audit between all the files we just generated. It compares spec.md (what the business asks for), plan.md (the designed technical solution), tasks.md (the execution steps), and the repository's Constitution.

If the AI detects that the specification requested that "the system must allow special notes like a table next to the window", but in the data-model.md you haven't defined any text column to save comments in the reservations table, the analyzer will stop the flow dead in its tracks and generate a critical discrepancy alert. You will have to adjust the database plan before programming.


Flow Summary: Your role in this pipeline

Notice how your way of working has changed with this walkthrough. Instead of spending two hours fighting with Express syntax or debugging why a SQL object returns an undefined in the console, you have spent fifteen minutes:

  1. Defining the logical rules of the game using a robust syntax (EARS).
  2. Resolving real business doubts before they turn into code bugs.
  3. Auditing that the technical design respects the laws of your repository.

The resulting code generated by the AI in the next step (/speckit.implement) will be clean, secure, tested from the start, and will fit perfectly into your architecture. You have stopped typing code to start designing logical contracts.

In the next article, The Requirements Interview and the 'SpecOps' Loop: How to Use AI Sparring and Rewrite Code Painlessly we will take a step further into extreme automation. We will see how tools like Google Antigravity and the Model Context Protocol (MCP) take this flow into an armored environment, running tests in isolated sandboxes and letting the AI interact with real local browsers to self-correct its own interface flaws before opening the Pull Request. See you in the next article!


📚 Spec-Driven Development (SDD) Series

  1. Spec-Driven Development (SDD): AI Agent Governance and the End of 'Vibe Coding'
  2. The Governance Chassis: Constitution vs. AGENTS.md (And how not to drown in sync debt)
  3. The SDD Pipeline in Practice: From EARS Syntax to Atomic Tasks
  4. The Requirements Interview and the 'SpecOps' Loop: How to Use AI Sparring and Rewrite Code Painlessly
  5. The Challenge of Existing Code (Brownfield) and Managing Multiple Specs with Jira/Git
  6. Google Antigravity and MCP: Sandboxing, Self-Correction and the Cloud