Spec-Driven Development
Overview
Write a structured specification before writing any code. The spec is the shared source of truth between you and the human engineer — it defines what we're building, why, and how we'll know it's done. Code without a spec is guessing.
When to Use
- Starting a new .NET solution or feature
- Requirements are ambiguous or incomplete
- The change touches multiple projects or assemblies in the solution
- You're about to make an architectural decision (hosting model, persistence layer, UI framework)
- The task would take more than 30 minutes to implement
When NOT to use: Single-line fixes, typo corrections, or changes where requirements are unambiguous and self-contained.
The Gated Workflow
Spec-driven development has four phases. Do not advance to the next phase until the current one is validated.
SPECIFY ──→ PLAN ──→ TASKS ──→ IMPLEMENT
│ │ │ │
▼ ▼ ▼ ▼
Human Human Human Human
reviews reviews reviews reviews
Phase 1: Specify
Start with a high-level vision. Ask the human clarifying questions until requirements are concrete.
Surface assumptions immediately. Before writing any spec content, list what you're assuming:
ASSUMPTIONS I'M MAKING:
1. This is an Avalonia 11 desktop app (not MAUI or WPF)
2. Target framework is .NET 8 (LTS), C# 12 language features
3. Persistence is EF Core 8 against SQLite for dev, PostgreSQL for prod
4. Testing with xUnit v3 + native `Xunit.Assert` (MSTest with its native `Assert` is acceptable per team standard)
5. MVVM via CommunityToolkit.Mvvm source generators
→ Correct me now or I'll proceed with these.
Don't silently fill in ambiguous requirements. The spec's entire purpose is to surface misunderstandings before code gets written — assumptions are the most dangerous form of misunderstanding.
Write a spec document covering these six core areas:
Objective — What are we building and why? Who is the user? What does success look like?
Commands — Full executable commands with flags, not just tool names.
Restore: dotnet restore
Build: dotnet build --configuration Release
Test: dotnet test --collect:"XPlat Code Coverage"
Format: dotnet format --verify-no-changes
Run: dotnet run --project src/MyApp
Publish: dotnet publish src/MyApp -c Release -r win-x64 --self-contained false
Project Structure — Where source code lives, where tests go, where docs belong.
MyApp.sln
src/
MyApp/ → Main application (Avalonia / ASP.NET Core / Blazor / MAUI host)
MyApp.Core/ → Domain types, use cases, pure logic
MyApp.Infrastructure/ → EF Core DbContext, external integrations
MyApp.Contracts/ → DTOs and API contracts (shared by server + clients)
tests/
MyApp.Core.Tests/ → Unit tests (xUnit)
MyApp.Infrastructure.Tests/→ Integration tests (EF Core in-memory or Testcontainers)
MyApp.EndToEnd.Tests/ → E2E (Playwright.NET for web, Avalonia.Headless for desktop)
docs/ → ADRs, specs, contributor guides
Code Style — One real code snippet showing your style beats three paragraphs describing it. Include naming conventions, formatting rules, and examples of good output.
Testing Strategy — What framework, where tests live, coverage expectations, which test levels for which concerns. Call out xUnit vs MSTest explicitly; list analyzers (Microsoft.CodeAnalysis.NetAnalyzers, StyleCop.Analyzers) and whether <TreatWarningsAsErrors>true</TreatWarningsAsErrors> is on.
Boundaries — Three-tier system:
- Always do: Run
dotnet test before commits, follow the project's .editorconfig, validate inputs at public API boundaries, nullable reference types on
- Ask first: EF Core migrations, adding NuGet dependencies, changing target framework, changing CI config
- Never do: Commit secrets (
user-secrets for dev, Key Vault / environment variables for prod), edit vendor/ directories, remove failing tests without approval, disable nullable warnings globally
Spec template:
# Spec: [Project/Feature Name]
## Objective
[What we're building and why. User stories or acceptance criteria.]
## Tech Stack
[.NET version (e.g. .NET 8), language (C# 12), key NuGet packages with versions,
UI framework (Avalonia 11 / Blazor / ASP.NET Core / MAUI), data layer (EF Core 8),
testing framework (xUnit or MSTest)]
## Commands
[Restore, build, test, format, run, publish — full dotnet CLI commands]
## Project Structure
[Solution layout with project responsibilities]
## Code Style
[Example snippet + .editorconfig highlights + analyzer set]
## Testing Strategy
[Framework, test project locations, coverage targets, which level covers what]
## Boundaries
- Always: [...]
- Ask first: [...]
- Never: [...]
## Success Criteria
[How we'll know this is done — specific, testable conditions]
## Open Questions
[Anything unresolved that needs human input]
Reframe instructions as success criteria. When receiving vague requirements, translate them into concrete conditions:
REQUIREMENT: "Make the app faster"
REFRAMED SUCCESS CRITERIA (Avalonia desktop app):
- Cold-start time from launch to main window visible < 1.2s on Windows 11 / Ryzen 5
- List view with 10k items scrolls at 60 FPS (measured via PerfView ETW trace)
- Background data refresh completes in < 500ms at the 95th percentile
REFRAMED SUCCESS CRITERIA (ASP.NET Core API):
- p95 request latency < 120ms for GET /api/orders under 200 RPS
- No Gen2 GC collections observed during 10-minute soak at target load
→ Are these the right targets?
This lets you loop, retry, and problem-solve toward a clear goal rather than guessing what "faster" means.
Phase 2: Plan
With the validated spec, generate a technical implementation plan:
- Identify the major components and their dependencies (which projects gain new code, which
DbContext changes, which DI registrations move)
- Determine the implementation order (contracts and migrations first, then infrastructure, then UI)
- Note risks and mitigation strategies (breaking migration, async deadlocks, package version conflicts)
- Identify what can be built in parallel vs. what must be sequential
- Define verification checkpoints between phases (each milestone green on
dotnet test)
The plan should be reviewable: the human should be able to read it and say "yes, that's the right approach" or "no, change X."
Phase 3: Tasks
Break the plan into discrete, implementable tasks:
- Each task should be completable in a single focused session
- Each task has explicit acceptance criteria
- Each task includes a verification step (test, build, manual check)
- Tasks are ordered by dependency, not by perceived importance
- No task should require changing more than ~5 files
Task template:
- [ ] Task: [Description]
- Acceptance: [What must be true when done]
- Verify: [How to confirm — e.g. `dotnet test tests/MyApp.Core.Tests`, `dotnet build -warnaserror`, manual smoke]
- Files: [Which files will be touched]
Phase 4: Implement
Execute tasks one at a time following incremental-implementation and test-driven-development skills. Use context-engineering to load the right spec sections and source files at each step rather than flooding the agent with the entire spec.
Keeping the Spec Alive
The spec is a living document, not a one-time artifact:
- Update when decisions change — If you discover the domain model needs to change, update the spec first, then generate the EF Core migration.
- Update when scope changes — Features added or cut should be reflected in the spec.
- Commit the spec — The spec belongs in version control alongside the code (
docs/specs/ is a common home).
- Reference the spec in PRs — Link back to the spec section that each PR implements.
Common Rationalizations
| Rationalization |
Reality |
| "This is simple, I don't need a spec" |
Simple tasks don't need long specs, but they still need acceptance criteria. A two-line spec is fine. |
| "I'll write the spec after I code it" |
That's documentation, not specification. The spec's value is in forcing clarity before code. |
| "The spec will slow us down" |
A 15-minute spec prevents hours of rework. Waterfall in 15 minutes beats debugging in 15 hours. |
| "Requirements will change anyway" |
That's why the spec is a living document. An outdated spec is still better than no spec. |
| "The user knows what they want" |
Even clear requests have implicit assumptions. The spec surfaces those assumptions. |
Red Flags
- Starting to write code without any written requirements
- Asking "should I just start building?" before clarifying what "done" means
- Implementing features not mentioned in any spec or task list
- Making architectural decisions without documenting them (no ADR under
docs/adr/)
- Skipping the spec because "it's obvious what to build"
Verification
Before proceeding to implementation, confirm:
Source & Modifications
- Upstream: https://github.com/addyosmani/agent-skills/blob/44dac80216da709913fb410f632a65547866346f/skills/spec-driven-development/SKILL.md
- Pinned commit:
44dac80216da709913fb410f632a65547866346f (synced 2026-04-19)
- Status:
modified
- Changes:
- Assumption examples retargeted from web app / session cookies / Prisma to Avalonia / .NET 8 / EF Core / xUnit / CommunityToolkit.Mvvm
Commands block replaced npm run ... with full dotnet CLI invocations (restore, build, test, format, run, publish)
Project Structure replaced src/components → React components layout with a MyApp.sln multi-project solution (Core / Infrastructure / Contracts + matching test projects)
Testing Strategy guidance calls out xUnit vs MSTest and mentions <TreatWarningsAsErrors>true</TreatWarningsAsErrors> and the standard analyzer pack
Boundaries swapped npm/generic web guidance for user-secrets, Key Vault, nullable reference types, and EF Core migration caution
Reframe block replaced the web Core Web Vitals example with two .NET-flavored success-criteria examples (Avalonia cold start, ASP.NET Core p95 latency + GC)
Tech Stack section in the spec template explicitly enumerates UI framework choices (Avalonia 11 / Blazor / ASP.NET Core / MAUI) and the EF Core data layer
Task template verify command updated to dotnet test/dotnet build -warnaserror
Keeping the Spec Alive references EF Core migration in the "decisions change" bullet; recommends docs/specs/ and docs/adr/ as canonical locations
- All structural sections, phase gates, workflow, rationalization table, and red-flag list preserved from upstream verbatim
- License: MIT © 2025 Addy Osmani — see
../../LICENSES/agent-skills-MIT.txt
1---2name: spec-driven-development3description: Creates specs before coding a .NET/C# project. Use when starting a new .NET 8+ solution, feature, or significant change and no specification exists yet. Use when requirements are unclear, ambiguous, or only exist as a vague idea. Frames examples for Avalonia, ASP.NET Core, Blazor, .NET MAUI, EF Core, xUnit, and MSTest.4---56<!-- Adapted from addyosmani/agent-skills (MIT © 2025 Addy Osmani). See the "Source & Modifications" footer at the bottom of this file for the exact changes applied to the upstream body. -->78# Spec-Driven Development910## Overview1112Write a structured specification before writing any code. The spec is the shared source of truth between you and the human engineer — it defines what we're building, why, and how we'll know it's done. Code without a spec is guessing.1314## When to Use1516- Starting a new .NET solution or feature17- Requirements are ambiguous or incomplete18- The change touches multiple projects or assemblies in the solution19- You're about to make an architectural decision (hosting model, persistence layer, UI framework)20- The task would take more than 30 minutes to implement2122**When NOT to use:** Single-line fixes, typo corrections, or changes where requirements are unambiguous and self-contained.2324## The Gated Workflow2526Spec-driven development has four phases. Do not advance to the next phase until the current one is validated.2728```29SPECIFY ──→ PLAN ──→ TASKS ──→ IMPLEMENT30 │ │ │ │31 ▼ ▼ ▼ ▼32 Human Human Human Human33 reviews reviews reviews reviews34```3536### Phase 1: Specify3738Start with a high-level vision. Ask the human clarifying questions until requirements are concrete.3940**Surface assumptions immediately.** Before writing any spec content, list what you're assuming:4142```43ASSUMPTIONS I'M MAKING:441. This is an Avalonia 11 desktop app (not MAUI or WPF)452. Target framework is .NET 8 (LTS), C# 12 language features463. Persistence is EF Core 8 against SQLite for dev, PostgreSQL for prod474. Testing with xUnit v3 + native `Xunit.Assert` (MSTest with its native `Assert` is acceptable per team standard)485. MVVM via CommunityToolkit.Mvvm source generators49→ Correct me now or I'll proceed with these.50```5152Don't silently fill in ambiguous requirements. The spec's entire purpose is to surface misunderstandings *before* code gets written — assumptions are the most dangerous form of misunderstanding.5354**Write a spec document covering these six core areas:**55561. **Objective** — What are we building and why? Who is the user? What does success look like?57582. **Commands** — Full executable commands with flags, not just tool names.59 ```60 Restore: dotnet restore61 Build: dotnet build --configuration Release62 Test: dotnet test --collect:"XPlat Code Coverage"63 Format: dotnet format --verify-no-changes64 Run: dotnet run --project src/MyApp65 Publish: dotnet publish src/MyApp -c Release -r win-x64 --self-contained false66 ```67683. **Project Structure** — Where source code lives, where tests go, where docs belong.69 ```70 MyApp.sln71 src/72 MyApp/ → Main application (Avalonia / ASP.NET Core / Blazor / MAUI host)73 MyApp.Core/ → Domain types, use cases, pure logic74 MyApp.Infrastructure/ → EF Core DbContext, external integrations75 MyApp.Contracts/ → DTOs and API contracts (shared by server + clients)76 tests/77 MyApp.Core.Tests/ → Unit tests (xUnit)78 MyApp.Infrastructure.Tests/→ Integration tests (EF Core in-memory or Testcontainers)79 MyApp.EndToEnd.Tests/ → E2E (Playwright.NET for web, Avalonia.Headless for desktop)80 docs/ → ADRs, specs, contributor guides81 ```82834. **Code Style** — One real code snippet showing your style beats three paragraphs describing it. Include naming conventions, formatting rules, and examples of good output.84855. **Testing Strategy** — What framework, where tests live, coverage expectations, which test levels for which concerns. Call out xUnit vs MSTest explicitly; list analyzers (`Microsoft.CodeAnalysis.NetAnalyzers`, `StyleCop.Analyzers`) and whether `<TreatWarningsAsErrors>true</TreatWarningsAsErrors>` is on.86876. **Boundaries** — Three-tier system:88 - **Always do:** Run `dotnet test` before commits, follow the project's `.editorconfig`, validate inputs at public API boundaries, nullable reference types on89 - **Ask first:** EF Core migrations, adding NuGet dependencies, changing target framework, changing CI config90 - **Never do:** Commit secrets (`user-secrets` for dev, Key Vault / environment variables for prod), edit `vendor/` directories, remove failing tests without approval, disable nullable warnings globally9192**Spec template:**9394```markdown95# Spec: [Project/Feature Name]9697## Objective98[What we're building and why. User stories or acceptance criteria.]99100## Tech Stack101[.NET version (e.g. .NET 8), language (C# 12), key NuGet packages with versions,102 UI framework (Avalonia 11 / Blazor / ASP.NET Core / MAUI), data layer (EF Core 8),103 testing framework (xUnit or MSTest)]104105## Commands106[Restore, build, test, format, run, publish — full dotnet CLI commands]107108## Project Structure109[Solution layout with project responsibilities]110111## Code Style112[Example snippet + .editorconfig highlights + analyzer set]113114## Testing Strategy115[Framework, test project locations, coverage targets, which level covers what]116117## Boundaries118- Always: [...]119- Ask first: [...]120- Never: [...]121122## Success Criteria123[How we'll know this is done — specific, testable conditions]124125## Open Questions126[Anything unresolved that needs human input]127```128129**Reframe instructions as success criteria.** When receiving vague requirements, translate them into concrete conditions:130131```132REQUIREMENT: "Make the app faster"133134REFRAMED SUCCESS CRITERIA (Avalonia desktop app):135- Cold-start time from launch to main window visible < 1.2s on Windows 11 / Ryzen 5136- List view with 10k items scrolls at 60 FPS (measured via PerfView ETW trace)137- Background data refresh completes in < 500ms at the 95th percentile138139REFRAMED SUCCESS CRITERIA (ASP.NET Core API):140- p95 request latency < 120ms for GET /api/orders under 200 RPS141- No Gen2 GC collections observed during 10-minute soak at target load142→ Are these the right targets?143```144145This lets you loop, retry, and problem-solve toward a clear goal rather than guessing what "faster" means.146147### Phase 2: Plan148149With the validated spec, generate a technical implementation plan:1501511. Identify the major components and their dependencies (which projects gain new code, which `DbContext` changes, which DI registrations move)1522. Determine the implementation order (contracts and migrations first, then infrastructure, then UI)1533. Note risks and mitigation strategies (breaking migration, async deadlocks, package version conflicts)1544. Identify what can be built in parallel vs. what must be sequential1555. Define verification checkpoints between phases (each milestone green on `dotnet test`)156157The plan should be reviewable: the human should be able to read it and say "yes, that's the right approach" or "no, change X."158159### Phase 3: Tasks160161Break the plan into discrete, implementable tasks:162163- Each task should be completable in a single focused session164- Each task has explicit acceptance criteria165- Each task includes a verification step (test, build, manual check)166- Tasks are ordered by dependency, not by perceived importance167- No task should require changing more than ~5 files168169**Task template:**170```markdown171- [ ] Task: [Description]172 - Acceptance: [What must be true when done]173 - Verify: [How to confirm — e.g. `dotnet test tests/MyApp.Core.Tests`, `dotnet build -warnaserror`, manual smoke]174 - Files: [Which files will be touched]175```176177### Phase 4: Implement178179Execute tasks one at a time following `incremental-implementation` and `test-driven-development` skills. Use `context-engineering` to load the right spec sections and source files at each step rather than flooding the agent with the entire spec.180181## Keeping the Spec Alive182183The spec is a living document, not a one-time artifact:184185- **Update when decisions change** — If you discover the domain model needs to change, update the spec first, then generate the EF Core migration.186- **Update when scope changes** — Features added or cut should be reflected in the spec.187- **Commit the spec** — The spec belongs in version control alongside the code (`docs/specs/` is a common home).188- **Reference the spec in PRs** — Link back to the spec section that each PR implements.189190## Common Rationalizations191192| Rationalization | Reality |193|---|---|194| "This is simple, I don't need a spec" | Simple tasks don't need *long* specs, but they still need acceptance criteria. A two-line spec is fine. |195| "I'll write the spec after I code it" | That's documentation, not specification. The spec's value is in forcing clarity *before* code. |196| "The spec will slow us down" | A 15-minute spec prevents hours of rework. Waterfall in 15 minutes beats debugging in 15 hours. |197| "Requirements will change anyway" | That's why the spec is a living document. An outdated spec is still better than no spec. |198| "The user knows what they want" | Even clear requests have implicit assumptions. The spec surfaces those assumptions. |199200## Red Flags201202- Starting to write code without any written requirements203- Asking "should I just start building?" before clarifying what "done" means204- Implementing features not mentioned in any spec or task list205- Making architectural decisions without documenting them (no ADR under `docs/adr/`)206- Skipping the spec because "it's obvious what to build"207208## Verification209210Before proceeding to implementation, confirm:211212- [ ] The spec covers all six core areas213- [ ] The human has reviewed and approved the spec214- [ ] Success criteria are specific and testable215- [ ] Boundaries (Always/Ask First/Never) are defined216- [ ] The spec is saved to a file in the repository (`docs/specs/<name>.md` recommended)217218---219220## Source & Modifications221222- **Upstream**: https://github.com/addyosmani/agent-skills/blob/44dac80216da709913fb410f632a65547866346f/skills/spec-driven-development/SKILL.md223- **Pinned commit**: `44dac80216da709913fb410f632a65547866346f` (synced 2026-04-19)224- **Status**: `modified`225- **Changes**:226 - Assumption examples retargeted from web app / session cookies / Prisma to Avalonia / .NET 8 / EF Core / xUnit / CommunityToolkit.Mvvm227 - `Commands` block replaced `npm run ...` with full `dotnet` CLI invocations (restore, build, test, format, run, publish)228 - `Project Structure` replaced `src/components → React components` layout with a `MyApp.sln` multi-project solution (Core / Infrastructure / Contracts + matching test projects)229 - `Testing Strategy` guidance calls out xUnit vs MSTest and mentions `<TreatWarningsAsErrors>true</TreatWarningsAsErrors>` and the standard analyzer pack230 - `Boundaries` swapped `npm`/generic web guidance for `user-secrets`, Key Vault, nullable reference types, and EF Core migration caution231 - `Reframe` block replaced the web Core Web Vitals example with two .NET-flavored success-criteria examples (Avalonia cold start, ASP.NET Core p95 latency + GC)232 - `Tech Stack` section in the spec template explicitly enumerates UI framework choices (Avalonia 11 / Blazor / ASP.NET Core / MAUI) and the EF Core data layer233 - `Task template` verify command updated to `dotnet test`/`dotnet build -warnaserror`234 - `Keeping the Spec Alive` references EF Core migration in the "decisions change" bullet; recommends `docs/specs/` and `docs/adr/` as canonical locations235 - All structural sections, phase gates, workflow, rationalization table, and red-flag list preserved from upstream verbatim236- **License**: MIT © 2025 Addy Osmani — see [`../../LICENSES/agent-skills-MIT.txt`](../../LICENSES/agent-skills-MIT.txt)