Blog 2026-06-04 7 min read Getting Started with Kiro — Part 3

Specs: From Requirements to Working Code

The Problem with Vibe Coding

Chat-based AI coding works fine for small changes. Fix a bug, add a field, refactor a method. You describe what you want, the AI does it, you move on.

It falls apart on anything bigger. A feature that touches multiple files, needs new infrastructure, requires coordination between services — that's not a single prompt. In Cursor or Copilot, you end up in a long chat session, re-explaining context, correcting drift, and hoping the AI remembers what it was doing three messages ago.

Specs are Kiro's answer to this. Instead of a conversation that evaporates when the session ends, you get a persistent document that defines the feature, breaks it into tasks, and lets Kiro execute those tasks autonomously.

How Specs Work

A spec lives in .kiro/specs/ inside your project. Each spec is a folder with three markdown files:

.kiro/specs/add-user-invitations/
├── requirements.md
├── design.md
└── tasks.md

You can create a spec from the Kiro sidebar or by asking Kiro to start one in chat. Either way, the workflow moves through three phases: requirements, design, tasks.

Screenshot: The Kiro sidebar showing the spec creation interface with the three-phase workflow

Phase 1: Requirements

Requirements are structured as user stories with acceptance criteria. Kiro generates these from your description of the feature, then you iterate on them.

## Requirement 1: Invite a User by Email

### User Story
As an account administrator, I want to invite users by email address
so that I can onboard team members without them needing to self-register.

### Acceptance Criteria
- [ ] POST /invitations accepts an email address and optional role
- [ ] System sends an invitation email with a unique token
- [ ] Token expires after 72 hours
- [ ] Duplicate invitations to the same email are rejected with 409
- [ ] Invitation record is stored with status PENDING

The acceptance criteria matter. They're what Kiro uses to determine when a task is done. Vague criteria produce vague implementations. Specific criteria produce testable code.

I usually let Kiro generate the first pass, then edit the requirements directly. Add constraints it missed, remove things that are out of scope, tighten the acceptance criteria. This is the design phase — you're deciding what the feature actually is before any code gets written.

Phase 2: Design

Once requirements are locked, Kiro proposes a technical design. This covers the implementation approach: what files change, what patterns to use, what the data model looks like.

## Design Overview

### API Layer
- New Lambda function: `CreateInvitation` in InvitationsController
- Request validation via FluentValidation
- Authorization: requires `invitations:create` capability

### Data Model
- DynamoDB entity: Invitation
- PK: `ACCOUNT#{AccountId}` / SK: `INVITATION#{Email}`
- GSI1: `INVITATION#{Token}` for token lookup
- TTL field for automatic expiration

### Service Layer
- InvitationService handles business logic
- Publishes `InvitationCreated` domain event to EventBridge
- Email sending delegated to NotificationService via event

The design phase is where steering files pay off. If you have conventions for your data model, service layer, and API patterns, Kiro follows them here. The design it proposes should look like something you'd write yourself.

If it doesn't, edit it. The design document is a contract. Kiro implements what's in the design, so fix it before moving to tasks.

Phase 3: Tasks

From the requirements and design, Kiro generates a task list. Each task is a discrete unit of work with clear inputs and outputs.

## Tasks

- [ ] Create Invitation entity with DynamoDB key schema and GSI
- [ ] Create InvitationService with CreateInvitation method
- [ ] Add FluentValidation validator for CreateInvitationRequest
- [ ] Create CreateInvitation Lambda function with authorization
- [ ] Publish InvitationCreated domain event on success
- [ ] Add CDK infrastructure for new Lambda and DynamoDB GSI
- [ ] Register new services in DI container

Tasks execute in order. Kiro picks up the first incomplete task, implements it, marks it done, and moves to the next one. In autopilot mode, this happens without you touching anything.

Screenshot: A tasks.md file showing completed checkmarks on early tasks and the current task in progress

Execution

Once you approve the task list, Kiro starts working. Each task follows the same loop:

  1. Read the task description and acceptance criteria
  2. Read relevant files in the codebase
  3. Implement the change
  4. Verify it compiles (runs the build)
  5. Mark the task complete
  6. Move to the next task

You can watch this happen in real time in the chat panel. Each task shows what files were read, what was written, and whether the build passed. If something fails, Kiro iterates on it — fixing compile errors, adjusting imports, resolving conflicts with existing code.

Screenshot: The chat panel during spec execution showing file reads, writes, and a successful build verification

If a task gets stuck (build keeps failing, circular dependency, missing context), Kiro will stop and ask for help. This is rare if your steering files are good, but it happens.

When to Use Specs vs Chat

Not everything needs a spec. Here's how I think about it:

Use chat for:

  • Bug fixes where you know the file and the problem
  • Small additions (add a field, add a validation rule)
  • Refactoring a single file or method
  • Questions about the codebase

Use specs for:

  • New features that touch 3+ files
  • Anything that needs new infrastructure (CDK, database changes)
  • Features where you want to think through the design before coding
  • Work you want to hand off and come back to later

The threshold is roughly: if you'd need more than 2-3 prompts to describe the full scope of the work, it's a spec.

Tips from Real Usage

Edit the requirements aggressively. Kiro's first pass at requirements is usually 80% right. The 20% it gets wrong — missing edge cases, over-scoped acceptance criteria, assumptions about your architecture — will propagate through the entire implementation if you don't catch them here.

Keep specs focused. One feature per spec. If you're tempted to put "add invitations AND add team management" in one spec, split them. Smaller specs execute more reliably and are easier to review.

Your steering files do the heavy lifting. A spec in a project with good steering files produces dramatically better output than the same spec in a bare project. The spec says what to build. Steering says how to build it. Both matter.

Review the design before approving tasks. The design phase is your last chance to course-correct cheaply. Once tasks start executing, you're reviewing implemented code instead of a plan. It's much faster to fix a design doc than to undo three completed tasks.

Specs persist across sessions. If you close Kiro and come back tomorrow, the spec is still there. Incomplete tasks pick up where they left off. This is the main advantage over chat — you don't lose context between sessions.

A Real Example

Most of the features in Oproto were built with specs. A typical one: adding audit logging to the service layer. The spec had 4 requirements (what gets logged, where it's stored, how it's queried, retention policy), a design that mapped to our existing patterns, and 9 tasks covering the entity, service, API endpoints, CDK changes, and event publishing.

Total execution time was about 40 minutes in autopilot. I reviewed the output, made two small adjustments (a key format that didn't match our convention, and a missing index), and merged it. The equivalent manual work would have been most of an afternoon.

That's the value proposition. Not "AI writes code for you" — that's table stakes now. It's "AI implements a designed feature end-to-end while you do something else."

What's Next

The next post covers Hooks: how to automate actions that trigger on file saves, tool use, and task completion. Hooks are what turn specs from "Kiro implements code" into "Kiro implements code and then verifies its own work."

Dan Guisinger

Dan Guisinger

AWS cloud architect and consultant specializing in system and security architecture. 20 years building enterprise applications in healthcare and finance.

Share: Share on LinkedIn

Building Features Faster with AI?

Spec-driven development changes how you think about feature delivery. I help teams adopt workflows that let AI handle implementation while engineers focus on design.