Lesson 12
Specs as Living Artifacts
Shifting How You Think About Specs
You already use spec mode - but if you've been treating specs as planning scaffolding that you discard once the feature ships, this lesson reframes them as living verification artifacts that serve multiple purposes over the life of the code.
The key shift: specs aren't just "how we planned the work." They're the source of truth from which code and tests are independently derived. They're the "why" that outlives any particular implementation.
The Two Spec Types
Kiro has two distinct spec types, each modelling a different development workflow:
Feature Specs
For building new capabilities. Two workflow variants:
| Variant | Starting point | Flow | Best when |
|---|---|---|---|
| Requirements-First | What the system should do | Requirements → Design → Tasks | You know the behaviour you want but not the implementation |
| Design-First | How to build it technically | Design → Requirements → Tasks | You have a technical approach in mind and want to formalise it |
Both produce the same three artifacts:
- Requirements - what the system shall do (EARS notation)
- Design - how it will be built (architecture, data model, interfaces)
- Tasks - discrete implementation steps Kiro executes
You can't switch variants mid-spec. If you need to change approach, create a new spec.
Bugfix Specs
For fixing defects. Models how experienced developers approach bugs:
- Root cause analysis - identify why the bug exists, not just what it does
- Fix design - what should change AND what should NOT change
- Regression prevention - ensure the fix doesn't break existing behaviour
The "explicitly preserve what shouldn't change" part is key - it prevents the fix from being broader than necessary.
How to initiate each type
When you start a Spec session, you should see the choice between Feature Spec and Bugfix Spec. The exact UI may vary by Kiro version - look for a type selector when creating a new spec, or describe your intent clearly ("I need to fix a bug where...") and Kiro may route you to the bugfix workflow based on your description. If you don't see a choice, try explicitly stating "create a bugfix spec" in your prompt.
The Bug-as-Spec-Gap Pattern
When a bug appears in code that was built from a spec, ask: did the spec miss this case, or did the implementation deviate from the spec?
This is a diagnostic mental model - but it's also a prompt you can give Kiro directly. Point Kiro at the spec and the bug, and ask: "Does the spec cover this scenario? Are the property tests passing?" Kiro can read both artifacts and tell you where the chain broke.
| Diagnosis | Action |
|---|---|
| Spec was incomplete - didn't cover this scenario | Update the original feature spec with the missing requirement, then re-derive property tests for the new requirement. Fix only the affected area. |
| Code diverged from spec - spec is correct but code doesn't match | Use a bugfix spec to fix the code. The property tests from the original spec should already be failing - confirming the divergence. |
| Both - spec was ambiguous, code interpreted it wrong | Clarify the spec first, then fix the code. Re-run full PBT to verify. |
This is powerful because it turns debugging into a structured process: check the spec, check the tests, identify where the chain broke.
Feature Spec Anatomy (What Lives in .kiro/specs/)
Each spec creates a directory:
.kiro/specs/
└── order-discount-rules/
├── requirements.md # EARS-format requirements
├── design.md # Technical design decisions
└── tasks.md # Implementation tasks (with status)These are markdown files - human-readable, committable to git, reviewable in PRs.
EARS: Writing Requirements That Generate Good Tests
EARS (Easy Approach to Requirements Syntax) is the notation Kiro uses for requirements. It matters because property-based tests are derived directly from these statements - clearer requirements → better properties.
| Pattern | Template | Example |
|---|---|---|
| Ubiquitous | THE [system] SHALL [behaviour] | THE System SHALL display prices in GBP |
| Event-driven | WHEN [trigger], THE [system] SHALL [behaviour] | WHEN a user adds an item to cart, THE System SHALL update the cart total |
| State-driven | WHILE [state], THE [system] SHALL [behaviour] | WHILE the user is unauthenticated, THE System SHALL redirect to login |
| Optional | WHERE [feature], THE [system] SHALL [behaviour] | WHERE premium subscription is active, THE System SHALL show ad-free content |
| Unwanted | IF [condition], THEN THE [system] SHALL [behaviour] | IF the payment gateway times out, THEN THE System SHALL retry once then show an error |
Each requirement maps naturally to a property test:
- "THE System SHALL display prices in GBP" → for any product,
getPrice(product).currency === 'GBP' - "WHEN a user adds an item to cart, THE System SHALL update the cart total" → for any user and any item,
cart.total === previousTotal + item.price
The more structured your requirements, the better Kiro can derive properties.
Parallel Task Execution
When you click "Run all Tasks" on a spec, Kiro doesn't just run them sequentially. It:
- Builds a dependency graph from the task list
- Identifies which tasks touch the same files (never run in parallel)
- Identifies which are truly independent (run concurrently)
- Runs setup/infrastructure tasks first
- Runs independent implementation tasks in parallel via sub-agents
This connects directly to Lesson 8 (Sub-agents) - each parallel task runs in its own isolated context.
Spec Lifecycle: From Creation to Maintenance
Create spec → Define requirements → Generate design → Generate tasks
│
▼
Execute tasks (parallel where possible) → PBT verifies each task
│
▼
Feature ships → Spec stays committed in git
│
▼ (months later)
Bug reported → Check: is spec incomplete or did code diverge?
│
├── Spec gap → Update spec → Re-derive property tests → Fix code
│
└── Code divergence → Bugfix spec → Surgical fix → PBT re-run
│
▼
Requirements change → Update spec → Kiro re-derives tests → Implement deltaSpecs in Pull Requests
Since specs are committed to git, they appear in pull requests alongside the code. This transforms code review:
- Reviewers can read the intent (spec) alongside the implementation (code)
- Instead of guessing what the developer intended, they ask: "does the code match the spec?"
- Requirements are visible - reviewers can challenge whether the spec itself is complete
- Design decisions are documented - no "why was it done this way?" questions later
This is especially powerful for team code review - junior developers get clarity on intent, senior developers can review the design without reading every line of code.
Iterating on Specs
Specs aren't frozen after creation. If during implementation you realise a requirement is wrong, missing, or ambiguous:
- Update the requirement in
requirements.md - Regenerate affected tasks (or add new ones)
- Continue implementation from where you left off
The spec stays as the authoritative record of what changed and why. This is normal - specs evolve as you learn more about the problem. The key is that the spec always reflects current intent, not original intent.
Strategic Spec Management
Organising specs at scale
With hundreds of specs over time, organisation matters. Kiro stores specs flat in .kiro/specs/, but you can add structure:
Naming conventions:
- Prefix with domain:
commerce--order-discounts,auth--session-management - Prefix bugfix specs:
fix--discount-rounding-bug - Optionally include date:
2026-06--order-discountsfor temporal context
Archiving completed specs:
- Move fully-implemented, stable specs to
.kiro/specs/_archive/- still in git, still searchable, not cluttering the active view - Keep specs active while the feature is still evolving or has known gaps
Linking related specs:
In requirements.md, reference related specs: "See also: ../payment-processing/ for the upstream pricing model this depends on." This creates a navigable web of intent.
General principles:
- One spec per feature/fix - never a monolithic application spec
- Commit specs to git - they're reviewed alongside code in PRs
- Keep specs updated - when requirements change, update the spec first, then the code
Cross-cutting context lives in steering, not specs
Application-wide knowledge (architecture, conventions, shared patterns) belongs in steering. Each spec is self-contained for its feature but reads steering for the broader context. This avoids duplication across specs.
Meta-overview for humans
Consider maintaining a manual steering file or reference doc that indexes your specs by domain - not for Kiro (it reads specs directly) but for humans navigating the project:
---
inclusion: manual
---
# Spec Index
## Commerce Domain
- order-discount-rules/ — discount calculation logic
- payment-processing/ — Stripe integration, retry logic
- cart-management/ — add/remove items, persistence
## User Domain
- user-authentication/ — login, session, JWT
- notification-preferences/ — email/push settingsWhen to Create a Spec vs. Just Code
| Use a spec when | Just vibe-code when |
|---|---|
| Complex feature with multiple requirements | Simple change you could describe in one sentence |
| You want PBT verification | Pure UI/styling work |
| Multiple people need to understand the intent | Exploratory/prototype work |
| You need traceability (requirement → test → code) | Quick fix where you already know the solution |
| The feature will be maintained long-term | Throwaway or temporary code |
Your Tangible Win
You now think about specs strategically: as living verification artifacts, not disposable plans. You know both spec types (feature + bugfix), both feature variants (requirements-first + design-first), how EARS requirements map to property tests, the bug-as-spec-gap pattern, parallel task execution, and how specs/steering/PBT form an integrated system.