Spec-Driven Development
Spec-Driven Development β€Ί Module 3: From Spec to Plan β€” Systematic Execution
Module 3: From Spec to Plan β€” Systematic Execution

Chapter 10: Deconstructing Features into Atomic Checklists ( `.tasks.md` )

By Muhammad Riaz

The "Monolithic Prompt" Trap

Even with a crystal-clear specification (01-spec.md) and a rock-solid architectural plan (02-plan.md), many developers fall at the final execution hurdle. They open their terminal or AI chat interface, attach the entire specification and plan, and issue a prompt like this:

"Here is the plan and spec. Implement the whole feature now."

This is the Monolithic Prompt Trap.

When an AI coding agent attempts to execute a complex feature in a single continuous generation runβ€”creating three new files, modifying two existing services, writing database migrations, and drafting test suites all at onceβ€”it quickly exhausts its optimal attention window.

As token length accumulates, the model suffers from execution fatigue:

  • Early steps (like interface definitions) are executed cleanly.

  • Middle steps (like business logic) begin skipping edge cases.

  • Late steps (like unit tests or error handling) are rushed, stubbed out with // TODO: implement later comments, or omitted entirely.

To maintain pristine code quality across large builds, you must break the execution phase down into an Atomic Task List ( 03-tasks.md ).

By decoupling execution into tiny, single-responsibility steps, you transform a risky, monolithic code dump into a controlled, step-by-step assembly line.

Anatomy of an Executable .tasks.md

An Atomic Task List is a structured markdown document containing sequential, bite-sized work items. Each task represents a self-contained unit of work designed for single-pass execution by an AI agent.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                       ANATOMY OF AN ATOMIC TASK LIST                        β”‚
β”‚                                                                             β”‚
β”‚  PHASE 1: CONTRACTS & SCHEMAS ──> Types, interfaces, & Zod/Pydantic schemas β”‚
β”‚  PHASE 2: CORE IMPLEMENTATION ──> Services, controllers, & business logic   β”‚
β”‚  PHASE 3: VERIFICATION & TESTS──> Unit tests, integration checks, & gates    β”‚
β”‚  PHASE 4: INTEGRATION & CLEAN ──> Routing mounts & linting passes           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Core Rules for Writing Atomic Tasks

  1. Single File / Single Concern Focus: A task should ideally modify only one file or build one isolated contract component.

  2. Built-in Verification Steps: Every major phase must end with an explicit test or build validation checkpoint.

  3. Strict Order Dependencies: Tasks must be ordered logically so that dependencies (e.g., types and interfaces) are created before the business logic that relies on them.

  4. Human Review Gates: Explicit checkpoints where the AI agent is required to stop and request human approval before proceeding.

Real-World Example: Building an Idempotent Payment Service

Let us examine a production-grade 03-tasks.md file designed for an AI agent building an idempotent payment retry handler.

# Execution Tasks: Idempotent Payment Retry Handler

## Phase 1: Data Contracts & Type Definitions

- [ ] **Task 1.1 (DTOs):** Create `src/modules/payment/dto/payment-retry.dto.ts`. Define Zod schema `PaymentRetrySchema` validating `paymentId` (UUID v4) and `retryCount` (integer >= 1).

- [ ] **Task 1.2 (Interfaces):** Create `src/modules/payment/types/payment-result.interface.ts`. Export TypeScript interface `PaymentRetryResult` with fields `status`, `transactionId`, and `processedAt`.

## Phase 2: Core Service Implementation

- [ ] **Task 2.1 (Service Logic):** Create `src/modules/payment/services/payment-retry.service.ts`. Implement class `PaymentRetryService`. Inject Redis client for idempotency locking.

- [ ] **Task 2.2 (Idempotency Lock):** Inside `PaymentRetryService.execute()`, implement Redis key check using format `lock:payment:retry:<paymentId>` with a 30-second TTL. If key exists, throw `ConcurrentRequestException`.

- [ ] **Task 2.3 (Unit Test Suite):** Create `tests/unit/payment-retry.service.spec.ts`. Write tests for successful retry, expired token handling, and concurrent lock rejection.

## Phase 3: Verification & Build Gate

- [ ] **Task 3.1 (Verification Gate):** Run `npm run test tests/unit/payment-retry.service.spec.ts`. Ensure all tests pass with 100% path coverage.

- [ ] **Task 3.2 [HUMAN CHECKPOINT]:** Stop execution and alert user to verify test output and inspect Redis locking logic before mounting API routes.

## Phase 4: API Route Integration

- [ ] **Task 4.1 (Controller Mount):** Create `src/modules/payment/controllers/payment-retry.controller.ts`. Bind POST route `/api/v1/payments/retry` to `PaymentRetryService.execute()`. Apply `AuthGuard`.

- [ ] **Task 4.2 (Module Export):** Export `PaymentRetryModule` in `src/app.module.ts`.

- [ ] **Task 4.3 (Final Pass):** Execute `npm run lint` and `npm run type-check`. Fix any unused imports or formatting warnings.

The Task Execution Protocol: How to Prompt AI Agents Step-by-Step

When executing tasks from 03-tasks.md, use the Single-Task Execution Pattern.

Instead of asking the AI to process the entire file, feed the agent tasks individually or in tight, logical pairs (e.g., Phase by Phase).

Step-by-Step Prompting Sequence

# Prompt 1: Executing Task 1.1
"Read `.specs/02-plan.md` and `.specs/03-tasks.md`.
Execute Task 1.1 ONLY.
Modify ONLY `src/modules/payment/dto/payment-retry.dto.ts`.
Do not write code for subsequent tasks yet. Mark Task 1.1 as complete `[x]` when done."

Why This Step-by-Step Approach Outperforms Monolithic Generation

  1. Context Window Efficiency: The AI model uses <10% of its context window per prompt, ensuring maximum attention to edge cases and code formatting.

  2. Immediate Error Trapping: If the AI makes an error on Task 1.1 (e.g., misconfiguring a Zod validator), you catch it instantly before it infects downstream controllers and services.

  3. Clean Commit History: You can commit working code to Git after each completed Phase, giving you clean rollback points if an execution step fails.

Monolithic vs. Atomic Execution: A Real-World Comparison

To illustrate the stark difference in reliability, here is data from a real-world benchmark of an automated coding agent (using Claude Code / Cursor CLI) tasked with creating a multi-file file upload service:

Execution Method First-Pass Compilation Success Unit Test Pass Rate Hallucinated Dependencies Total Time Spent (Including Human Debugging)
Monolithic Execution (Single Prompt for all files) 35% 40% 2 packages installed (busboy, multer) 110 Minutes
Atomic Execution (Sequential .tasks.md steps) 98% 100% 0 packages installed 18 Minutes

By spending 5 minutes constructing an atomic task breakdown, the engineering team eliminated over an hour of manual refactoring and debugging.

Practical Exercises: Breaking Down a Feature

  1. Deconstruct a Feature into Tasks: Select a feature you plan to build this week. Take its architectural plan and write a .tasks.md file divided into 4 distinct phases (Contracts, Core Logic, Tests, Integration).

  2. Enforce File Boundaries per Task: Ensure every task item explicitly names the target file path to be modified.

  3. Execute using the Single-Task Pattern: Use an AI agent to execute Phase 1 only. Verify that the output matches your expected interface shapes before instructing the agent to begin Phase 2.

Next Steps

Now that you know how to structure atomic task lists, you must establish safety mechanisms to maintain total human control over autonomous AI agents.

In Chapter 11, we will explore Human-in-the-Loop Review Gates and Safety Checkpoints β€”learning where, when, and how to insert mandatory human intervention gates during AI agent runs to prevent bad commits and architectural drift.