AI Engineer Code 2025
Spec-Driven Development: Agentic Coding at FAANG Scale and Quality — Al Harris, Amazon Kiro
Read the talk
Spec-Driven Development: Agentic Coding at FAANG Scale and Quality
Al Harris walks through Kiro’s requirements, design and task workflow, showing how external research, editable specs and explicit tests give developers more control over agentic coding.
From a talk by Al Harris
Before you start: Familiarity with coding agents, unit tests and basic TypeScript will help; the article explains the spec workflow and property-testing concepts as they appear.
Scaling development without losing control
How do you give an AI coding agent more complex work while retaining control over what it builds and confidence in the result? That was the problem behind Kiro, an agentic IDE developed by a small Amazon team. Al Harris, a Principal Engineer who had spent roughly a year on the product, describes its beginnings as three or four people exploring a different development workflow. Although funded through the organization supporting Q Dev, the team deliberately pursued a separate product direction. Kiro entered public preview on July 14, 2025, and general availability on November 17, 2025. Its goals were to handle more complex problems, improve operator control and produce more reliable code.
Vibe coding puts much of the process in the operator’s hands: supply the guardrails, impose a workflow and notice when the agent has gone off course. Spec-driven development makes that process explicit. It draws on familiar engineering practices—Waterfall, Agile and XP—while using fast generation to shorten the feedback loop.
Requirements are discovered through building and reviewing, not only through upfront discussion. Generate a design and it may expose a side effect that changes the requirements. Revise those requirements, regenerate the design and inspect the consequences. Requirements, acceptance criteria and stakeholder-reviewed design artifacts become things you can iterate on within a tight development loop, rather than documents handed downstream once.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Turning acceptance criteria into properties
Kiro begins with a prompt and turns it into requirements with acceptance criteria. Those criteria use EARS, the Easy Approach to Requirements Syntax: structured natural language that identifies the circumstances under which a system must produce a particular response. The structure became more consequential with the general-availability rollout of property-based testing, roughly four months after preview. Requirements could now feed the generation of correctness properties.
Property-based testing searches for counterexamples. Libraries such as Hypothesis in Python, fast-check in Node and Clojure’s spec library generate inputs to challenge a stated invariant. One counterexample is enough to show that the implementation violates the property. Finding none increases confidence only to the extent that the property and generated inputs capture the intended behavior; passing tests does not prove the requirements are universally satisfied.
The resulting workflow connects intent to implementation:
- Turn the prompt into requirements and acceptance criteria.
- Develop a design and identify correctness properties.
- Generate a task list from that design.
- Execute the tasks and test the resulting code against the properties.
The specification carries functional requirements, non-functional constraints and design concerns through this process. Harris gives it three complementary meanings: a set of artifacts describing the system at a particular point, a structured development workflow, and supporting tools that improve reproducibility. Property-based testing is one such tool.
Another is requirements verification. Harris describes scans for excessive ambiguity, invalid constraints and conflicting requirements, with classic automated reasoning helping resolve the conflicts. Around that core, Kiro provides steering documents—persistent guidance comparable to memory or Cursor rules—along with MCP integration, image support and software hooks. These controls supplement the specification rather than replacing it.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Bring external information into the spec
Early users found the workflow too constrained, particularly when requirements depended on information outside the repository. MCP servers can supply that information during requirements, design and implementation. A task tracker can provide product intent before code generation begins; a documentation server can inform a design decision before it becomes an implementation task.
To configure a server in the demonstrated interface:
- Open the Kiro panel using its ghost icon.
- Use the plus button under MCP servers, or ask Kiro to add a server and provide its location or JSON configuration.
- Inspect the installed server in the panel, then enable, disable or allowlist its tools as needed.
Harris warns against changing tools deep into a long session because doing so can break the prompt cache. The underlying tool-definition cache mechanism invalidates dependent cached prefixes when definitions change; current deferred-discovery mechanisms can preserve those prefixes, so the workshop warning should not be generalized to every modern tool-loading operation.
The first example starts with work already described in Asana. One task asks for a view model and controller for an API. With the Asana MCP installed, Kiro can recognize the task URL and retrieve its metadata. Harris shows two distinct operations: generating requirements from his open tasks, including user and property management, and starting code synthesis for a selected task. The slides have reversed titles, but the operational distinction matters: retrieving a task and specifying it is a separate decision from implementing it.
Harris offers Lofty Views, the sample application used in those examples, and a Nobel Prize MCP backed by the Nobel Prize API as projects to explore. The latter can be installed with uvx or cloned from the repository shown in the recording. He then attempts a live research workflow with Lofty Views, a simple CRUD application: use Fetch to retrieve examples from similar products, with Brave Search or Tavily Search as alternatives. An attempt to start the stale local project is canceled; a possible switch to an AgentCore project is also deferred. The proposed Fetch workflow is therefore an example to try, not a completed live result. In his sharpening metaphor, MCP is the initial 200-grit pass: useful added capability, with more control still to come.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Make the artifacts express what you need to review
The next, 400-grit pass changes the generated artifacts themselves. At the design approval checkpoint for Lofty Views’ user-management UI, Harris asks Kiro to include ASCII wireframes. Architecture alone does not tell him enough about the screens the team is about to build. The agent adds the diagrams, initially with awkward text wrapping that needs correction.
Once the wireframes are readable, a concrete design question becomes visible: should the Add User button stay at the top of the screen? That can be discussed and changed before implementation. Natural-language artifacts can carry extra material wherever it improves review; their structure supports reproducibility without making their contents untouchable. The completed design now includes the UI mocks alongside the architectural material.
The same customization applies to task completion. An agent may declare itself finished after repeatedly failing to fix tests. A task that merely repeats requirements and acceptance criteria leaves too much room for that interpretation. For an AgentCore memory checkpointer, Harris asks for explicit unit-test cases that must pass before the task is complete, then proposes agent hooks to enforce those checks. Completion should be tied to observable conditions, not the agent’s confidence.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Challenge the solution embedded in the prompt
The 800-grit pass changes the process. Harris’s initial request sounds straightforward: add memory to an AgentCore agent by dumping conversations into an S3 file after every execution. But it combines a desired capability—session persistence—with a storage choice. The agent obediently researches how to use S3, turning a familiar technology into an architectural constraint before alternatives have been considered.
After requirements, design and tasks have been generated, Harris asks whether this is the idiomatic way to achieve persistence. That reopens the decision. The agent uses MCP tools to investigate and recommends AgentCore Memory, a capability Harris had not known about. S3 remains an option, and DynamoDB arises as another possible storage direction. The recommendation that AgentCore Memory is more future-proof needs closer examination; the first two alternatives are not necessarily the full design space. The workflow gives a starting structure, but the operator can interrupt it to request more research.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
A live persistence spec stays anchored to S3
For the substantive live demonstration, Harris starts from a Node.js and TypeScript project with a CDK stack deploying an AgentCore runtime. The initial agent and infrastructure were vibe coded. He then added commitlint, Husky, Prettier and ESLint, reaching a baseline he knew he could deploy to his personal AWS account. AWS is the choice here because it lets him move quickly while learning AgentCore.
To give the agent documentation beyond its built-in knowledge, he adds the AWS Documentation MCP Server and Fetch. He then restarts the persistence spec from an existing directory whose files have been removed. The request introduces a session ID and reads and writes conversations to an S3 file. Kiro begins gathering context from the project’s documentation and source, after which Harris asks it to research the best approach and propose alternatives.
This run illustrates the limits of that intervention. Kiro discovers that LangGraph, the project’s agent framework, already has native persistence through checkpointing. But it does not use the AgentCore documentation MCP and does not discover AgentCore Memory. It revises the requirements around LangGraph’s checkpointing while retaining the original S3 decision. Asking for research helps, but the initial prompt still anchors the design.
Harris approves the requirements and moves to design. The user story now calls for a custom S3-based checkpointer so the agent can use LangGraph’s native persistence mechanism with S3. Its acceptance criteria use EARS-style trigger-and-response clauses. Harris explains why this matters beyond readability: structured requirements can be parsed by non-LLM systems and passed to automated reasoning tools, reducing dependence on whatever a model happens to generate.
The Markdown design describes the server, checkpointer and S3 interaction, including implementation sketches. Kiro then formalizes correctness properties from the agreed requirements and design, a capability introduced with the November 17 release. The intended connection is precise: if the extracted properties correctly represent the requirements, and the implementation satisfies those properties, the tests provide evidence that the implementation matches the requested system. Reviewing that translation matters especially when moving beyond a prototype.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
From execution plans to living specifications
An audience question asks how this differs from Cursor’s planning mode. Harris has not used it recently enough to make a definitive feature comparison. After the questioner describes an execution plan, the discussion turns to what should remain after implementation: documentation of what the system does, not just instructions for making a change.
Harris describes bidirectional synchronization between the specification and evolving system as a long-term goal. The initial spec creates a substantial review burden—three large new Markdown files—but subsequent changes should be reviewable as focused diffs: a requirement was relaxed, another added, and the design changed accordingly. Inside the Kiro team, spec reviews have largely replaced standalone design-document reviews. An internal MCP tool exports the Markdown into a wiki where the team comments together. The intended artifact is living documentation, whereas an architecture decision record captures a decision at a particular time.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Why editable documents still need structure
A spec is a set of requirements, design and task documents, with templates implicit in Kiro’s system prompts. In the demonstrated product, the navigation makes those phases explicit and imposes a fairly rigid order.
That order does not suit every engineering problem. A refactor may begin with a technical note rather than known requirements. Kiro uses synchronization primitives to stop concurrent agents from interfering with one another; an engineer might first explore whether a mutex or semaphore can be removed, then work backward to the requirements that must change. The team is exploring more flexible entry points while preserving the rich artifacts.
Structure also enables software around the agent. Harris describes task-dependent use of LLMs and other reasoning systems, rather than treating every operation as a conversation with Sonnet or Gemini; ordinary chat still goes directly to an LLM. Design sections, including the testing strategy, can be changed conversationally. Task documents have tighter structural obligations because task-management UI, optional-task handling and the task-list language server depend on them.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Run Gramps, and retain what deployment teaches
The project finally gets its full introduction: Gramps is an AgentCore-hosted dad-joke generator. Its jokes should be clean, pun-based and endearingly corny. The reason for persistence is practical: repeated requests currently produce the same joke. Harris wants requests within a session to carry enough history to produce different jokes.
The generated spec still uses S3 despite the known AgentCore Memory alternative. Harris deliberately continues with that choice, leaving a correction for later. He asks Kiro to run all tasks in order. The explicit ordering works around a preview-build prompt issue in which a request to run all tasks could be interpreted as parallel execution.
As execution proceeds, he shows steering documents for commit conventions, AgentCore operations and deployment to his development account. These preserve operational details learned through trial and error, such as required CDK flags and parameters. After resolving such a problem, he asks Kiro to record what it learned in steering; in this project, that produced an AgentCore–LangGraph workflow Markdown document. The next task can then begin with those instructions instead of rediscovering them.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Large repositories need discoverable boundaries
For an existing codebase, a new spec usually begins with research into the working tree. The agent must reconstruct enough of the system to make a change. Cohesive modules and clear separation of concerns reduce how many interacting pieces it must keep in context; reliable tests give it feedback while it works. Harris uses Kiro’s own rushed development and accumulated technical debt as the counterexample: tangled code makes an agent’s work harder in much the same way it makes a developer’s work harder.
Kiro supplies code search, workspace context providers and background indexing for semantic search. Indexing is disabled in the small demo repository because it is unnecessary there. Harris expects agent performance to become more difficult as repository size grows. Code OSS—the foundation Kiro shares with other editor forks such as Cursor and Windsurf—is his large-repository example: indexing can produce perceptible slowdown, and the team is working to keep it off the critical path so it does not impede rendering. He also reports successful spec-driven feature work in that unfamiliar upstream codebase, helped by its understandable structure. He gives no maximum supported repository size.
The index itself is not injected wholesale into the agent’s context. Harris distinguishes its use in code-search and file-selection UI from the information supplied directly to the model. He reports that anecdotal experience and internal benchmarks favor less initial context plus tools for discovering relevant material. Incremental disclosure lets the agent find the context for the task, instead of beginning with as much repository content as will fit. The populated picker shown here illustrates the UI side of that distinction.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Cacheable context and isolated task sessions
At the time of the workshop, Kiro accumulates session context without incremental pruning or summarization. Harris recalls an approximately 200K-token context limit in Auto mode, similar to Sonnet. Keeping the prefix stable is a deliberate latency trade-off: the team prioritizes prompt-cache reuse rather than continually rewriting conversation history.
Harris reports roughly 90–95% cached-token usage per turn in normal use. His comparison is a cold request sending 160K tokens to Bedrock. When the session reaches its cap, Kiro performs a one-off summary instead; Harris reports that this can take 30–45 seconds. He expects a faster experience within weeks, but the workshop shows the existing behavior, without a defined workload or timing methodology for those figures.
Asked whether specs primarily preserve state between sessions, Harris returns to the cost of human attention. A failed result after a ten-second prompt is easy to discard. After five to ten minutes refining requirements—or an hour designing and reviewing with a team—the developer reasonably expects more accurate synthesis. Latency still matters, but the central justification for specs is reproducibility and accuracy.
Task execution has a separate context boundary. An attendee reports subtasks being repeated after apparent completion. Harris explains that each Start action in the task UI creates a fresh session, seeded with the specification and the selected task; independent starts do not share conversational history. When there is enough context capacity, he personally prefers asking one session to complete all tasks. The repeated work sounds like a bug, not an intended handoff mechanism.
| Execution path | Context and behavior at the workshop |
|---|---|
| Start an individual desktop task | Fresh session, seeded with the spec and selected task |
| Ask one session to run all tasks | Retains that session’s conversational context |
| Desktop subagents | Not yet available |
| CLI custom agents | Available as separately runnable custom agents |
Desktop support for the CLI-style custom-agent capability is being explored; it should not be inferred from the existing task buttons.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Keep specs around features and recurring problems
A growing project does not become one enormous specification. Harris opens Kiro’s first-party extension, where the agent lives, to show separate specs for features and problem areas: a prompt registry, a registry file loader, chat telemetry and AGENTS.md support. Some are experiments that never reach production. Others can be deleted when there is little reason to revisit them; the AGENTS.md integration is his example of a potentially short-lived spec.
The message-history sanitizer is a better candidate for retention. Harris describes failures caused by invalid message sequences, including tool-response ordering constraints encountered in the Anthropic integration. As new validation rules emerge, the team adds acceptance criteria to the existing spec. One concrete rule requires each user input to contain either non-empty content or tool responses.
That last rule can be expressed directly in TypeScript and challenged with generated inputs. Here, the local UserInput type isolates the sanitizer rule; it is not a provider request schema. Empty text remains valid when tool responses are present, while input with neither is rejected.
typescript
import assert from 'node:assert/strict';
import fc from 'fast-check';
type UserInput = {
content: string;
toolResponses: string[];
};
function isValidUserInput(input: UserInput): boolean {
return input.content.length > 0 || input.toolResponses.length > 0;
}
fc.assert(
fc.property(fc.string(), fc.array(fc.string()), (content, responses) => {
const input: UserInput = { content, toolResponses: responses };
if (content.length > 0 || responses.length > 0) {
assert.equal(isValidUserInput(input), true);
}
}),
);
assert.equal(isValidUserInput({ content: '', toolResponses: [] }), false);
assert.equal(
isValidUserInput({ content: '', toolResponses: ['tool completed'] }),
true,
);
The critical review decision is the rule itself: whitespace, response validity and other message-sequence constraints would require their own acceptance criteria. A growing sanitizer spec gives those discoveries a durable home.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Find the existing spec before creating another
An audience member asks what happens when a new feature needs telemetry: will Kiro update the telemetry spec too? Harris starts a spec-mode request to add UI telemetry. The agent checks runbooks and explores the implementation before deciding where the change belongs. Existing-spec discovery is not guaranteed; if it misses the relevant document, Harris would explicitly direct it to amend that spec. At this point, the live result is still pending.
While that runs, another question asks whether Kiro is preconfigured to work better with AWS. Harris says the desktop product aims to be useful on GCP, Azure and on-premises systems as well. The AWS documentation MCP in this demonstration was added manually. Provider-specific documentation is an optional integration, avoiding bundled tools and context for customers who do not need them.
The telemetry operation then produces the desired result: Kiro finds the existing spec, reads its sections and adds requirements visible as a diff. This demonstrates amendment of an existing artifact rather than the creation of another independent spec for every request.
Cross-cutting changes still require an ownership decision. Consider redacting personally identifiable information in a way that affects the public API, security requirements and logging. Harris suggests either placing the requirements in one existing spec or creating a cross-functional spec, with the operator choosing the boundary. He does not demonstrate automatic coordination across several specs. An audience contributor adds that multi-root workspaces, introduced at general availability, can bring separately housed API, authentication and frontend projects into the same workspace; that helps establish working context without deciding spec ownership for the developer.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Inspect what the tasks actually produced
Returning to Gramps, Harris inspects the changes after the agent has run the persistence tasks sequentially in small pieces. The CDK code now includes an S3 bucket with encryption. The agent code includes an S3 checkpoint saver, connected to the LangGraph graph and responsible for reading and writing checkpoints. The result extends through infrastructure and application code, while retaining the original S3 architecture. Harris believes property tests were included, but does not inspect them in detail here.
A CLI-specific clarification qualifies the earlier AWS discussion. The recently rebranded Kiro CLI includes use_aws, described by an audience member as helping with AWS CLI work and by Harris as a wrapper over the AWS SDK. Other provider tools can be supplied through MCP. Native CLI tools can be disabled, whereas the desktop’s built-in native tools do not expose the same control in the version being discussed.
Asked for empirical comparisons of development with and without specs, Harris says the team has benchmarks and points toward Kiro’s blog for work on property testing and task accuracy. He does not supply a numerical result, a task definition or evaluation conditions. The related article Does your code match your spec? explains property testing, but it does not establish a controlled numerical with-spec versus without-spec accuracy result. The discussion supports examining the mechanism and evidence, rather than assigning an accuracy gain to this demonstration.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Specify the trade-offs, then check the result
A question about non-functional requirements initially leads to Kiro’s own latency: execution time, UI responsiveness and token delivery. The questioner clarifies that the concern is the generated software. For that, Harris recommends adding speed, runtime and lock-contention requirements to the design phase. Those constraints need to be visible while the architecture is being chosen.
The Node demonstration reflects Harris’s familiarity rather than a required implementation language. Rust and Java are raised as alternatives; he also mentions Python, JavaScript and TypeScript while discussing support. His broader point is that model capabilities and the supplied grounding documentation determine how well the workflow transfers to a language or framework. Tessl comes up as another example of documentation-based grounding. The spoken list is not an authoritative language-support matrix.
Steering can preserve recurring trade-offs: prioritize latency or cost, incorporate industry-specific constraints, and make those preferences influence design as well as implementation. Harris’s concrete final example is commit attribution. He wants to distinguish his own commits from those generated by the agent, so his steering requires a Kiro Agent co-author attribution. The resulting commit includes it.
The same mechanism can record code-style rules or coverage expectations. Harris gives a 90% coverage minimum for new specs or modules as an example steering requirement. It is a proposed policy, not a measured coverage result.
At the end, Harris reports that all tests appear to have passed and proposes deploying to the backend. The recording stops before deployment or a runtime check that Gramps now produces varied jokes within a session. The implementation still uses S3; the deferred move to AgentCore Memory is not shown. What the workshop reaches is a generated implementation, an attributed commit and apparent test success—the point at which the next engineering step is to inspect and validate the running system.
Suggest correction
This note stays in this page until you copy or download it. Nothing is submitted; reloading clears the draft.
Resources
From the talk
Alistair Mavin's guide to writing structured natural-language requirements with EARS.
AWS Labs documentation for connecting an agent to AWS documentation through MCP.
Current guidance for adding session history and persistent knowledge to AgentCore agents.
Further reading
- Introducing KiroArticle
The original preview announcement explains Kiro's specifications, hooks and agentic IDE workflow.
The launch announcement documents property tests, checkpointing, multi-root workspaces and CLI custom agents.
A traffic-light example connects requirements to executable properties, generated inputs and counterexamples.
Marc Brooker explains how specifications communicate intent between developers, stakeholders and coding agents.
Anthropic explains cache invalidation from tool changes and current options for preserving cached prefixes.
Read the transcript and explore slides
Loading transcript and slides…