AI coding agents are improving rapidly. Tools like Copilot, Codex, and Claude can generate large chunks of code, but without proper structure, this can quickly lead to messy and inconsistent implementations.
That’s where spec-driven development comes in.
By using the GitHub Spec-kit, you can move from "hoping for the best" to a controlled, logical development cycle where the AI works for you, not the other way around.
What is Spec-Kit?
Spec-kit is an AI prompting framework designed to integrate various coding agents (like Copilot, Claude Code, or Codex) into a structured workflow.
The core philosophy is simple: Start with a spec.
- The Spec: A high-level description of what you want to build, focusing on the "what" and "why" without technical implementation details.
- The Plan: A technical blueprint derived from the spec.
- The Tasks: A logical list of coding steps.
- The Code: The final implementation carried out by the agent.
Why use it?
If you’ve tried “vibe coding” with AI, you’ve probably seen this:
- The agent goes off track
- Code becomes inconsistent
- Bugs appear in unexpected places
- Everything feels loosely stitched together
Spec-Kit solves this by introducing structure.
Benefits
More control over AI output
You clearly define what the agent should do before it writes code.Consistency across teams
Specs act as shared rules, especially valuable in team environments.Traceability
Specs are stored in your repository, so the AI has historical context.Better alignment
You can review plans and tasks before any code is generated.
Getting Started with Spec-Kit
The easiest way to get started is from the official repository:
👉 https://github.com/github/spec-kit
Spec-Kit uses uv, a fast Python package manager. You can initialize it within an existing project or scaffold a new one.
Create a new project
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init <PROJECT_NAME>
Use it in an existing project
uvx --from git+https://github.com/github/spec-kit.git@vX.Y.Z specify init --here
The uvx command runs a package without installing it, similar to npx for Node packages.
During setup, you’ll choose:
- Coding agent (e.g., Copilot)
- Script type (e.g., PowerShell)
The command creates two folders:
├── 📁 .github/ # Prepared prompts for your coding agent
└── 📁 .specify/ # Memory (constitution), scripts, and templates
-
.github/contains prompts for different development stages, available in your Copilot chat -
.specify/memory/holds yourconstitution.mdfile with ground rules -
.specify/scripts/contains PowerShell scripts that the agent runs -
.specify/templates/provides templates for specs, plans, and tasks
The Development Cycle
Here's the typical Spec-Kit workflow:
| Command | Purpose |
|---|---|
/constitution |
Set core binding principles for the entire application |
/specify |
Create a high-level spec for a feature (creates new branch) |
/clarify (optional) |
Agent asks questions about underspecified areas |
/plan |
Add technical preferences (frameworks, libraries, etc.) |
/tasks |
Turn the plan into a logical list of coding tasks |
/analyze (optional) |
Check alignment across all artifacts |
/implement |
Execute the tasks and build the feature |
At the end of the cycle, you have a working feature based entirely on your initial spec. For each new feature, you walk through this process again, minus the constitution command, which you typically run once.
Real-World Demo: Refactoring an Azure Container App
I scaffolded a demo app called ACSdemo using GitHub Copilot CLI - an Azure Container App with this structure:
ACSdemo/
├── 📄 ACSdemo.slnx
├── 📄 README.md
├── 📄 docker-compose.yml
├── 📄 .dockerignore
│
├── 📁 src/
│ └── 📁 ACSdemo.Api/
│ ├── 📄 Program.cs
│ ├── 📄 WeatherForecast.cs
│ ├── 📄 appsettings.json
│ ├── 📄 appsettings.Development.json
│ ├── 📄 Dockerfile
│ ├── 📁 Controllers/
│ │ ├── EventsController.cs
│ │ ├── MessagesController.cs
│ │ └── WeatherForecastController.cs
│ ├── 📁 Models/
│ │ ├── SendEmailRequest.cs
│ │ └── SendSmsRequest.cs
│ ├── 📁 Services/
│ │ ├── ICommunicationService.cs
│ │ └── CommunicationService.cs
│ └── 📁 Properties/
│ └── launchSettings.json
│
├── 📁 dapr/
│ └── 📁 components/
│ ├── pubsub.yaml
│ └── statestore.yaml
│
└── 📁 deploy/
├── main.bicep
└── containerapp.bicep
The goal:
- Remove old REST controllers
- Process Azure Service Bus events
- Store data in Cosmos DB
- Expose data via GraphQL
👉 Important constraint:
No manual coding, everything done by the AI agent.
Step 1: The Constitution Command
The constitution (constitution.md) outlines governing principles for your project, required frameworks, UX guidelines, testing expectations, etc.
Here's the prompt I used:
/speckit.constitution Create a project constitution for a microservice called "ACSdemo" with:
## Architecture & Design Patterns
- CQRS pattern with MediatR for all business operations
- Single-project structure with Domain/, Application/, Infrastructure/, Web/ folders
- GraphQL primary API using HotChocolate v15 with Apollo Federation
## Testing Requirements (NON-NEGOTIABLE)
- No unit tests, integration tests, or acceptance tests (demo app simplification)
## Communication & Integration
- Dapr pub/sub with Azure Service Bus, [Dapr.Topic()] attributes
## Technology Stack (exact versions)
- Runtime: .NET 10.0
- CQRS: MediatR 12.x
- GraphQL: HotChocolate 15.x
- Persistence: Azure Cosmos DB
- Messaging: Azure Service Bus via Dapr pub/sub
- Persistence: Azure Cosmos DB (Microsoft.Azure.Cosmos)
- Configuration: Azure App Configuration + Azure Key Vault
- Containerization: Docker (Linux), Azure Container Apps
## Infrastructure
- All Azure resources in Bicep templates under .infrastructure/. No manual portal changes.
- Configuration via Azure App Configuration with Key Vault for secrets.
- Environment values parameterized, never hardcoded.
Output: A constitution with 6 core principles.
Pro tip: I deliberately pulled back on testing because this is a demo. In a real project, you'd add testing requirements to the constitutional prompt.
Step 2: The Specify Command
Instead of describing implementation, we define intent. We should focus on the what and the why, not the how:
/speckit.specify acsdemo-refactoring - This application needs refactoring.
Delete EventsController, MessagesController, and WeatherForecastController.
Create a new EmailNotification controller that receives the
Microsoft.Communication.EmailDeliveryReportReceived event from Azure Service Bus
and saves it to Azure Cosmos DB. Users can then retrieve data via GraphQL queries.
Output: A spec with 3 user stories (P1: data capture, P2: GraphQL queries, P3: cleanup) and 8 functional requirements.
Step 3: The Clarify Command (Optional but Valuable)
The clarify command instructs the agent to read the spec and find ambiguities, edge cases, or areas needing clarification. It asks you questions, and your answers get baked into the spec.
I ran it without any additional input:
/speckit.clarify
The agent asked 5 questions, each with recommendations:
-
How to store delivery status history? → Append a
statusHistoryarray (Cosmos DB idiomatic approach) -
What partition key for Cosmos DB? →
email address(optimizes the main query path) - Should GraphQL support pagination? → Offset/limit with default page size of 20
-
Closed enum or open string for status values? → Open string (
EmailDeliveryReportReceivedis an external contract owned by Microsoft and can change) - Maximum retry limit or defer to infrastructure? → Defer to Dapr/Service Bus config (YAGNI)
All questions answered, the spec was updated, and coverage was confirmed across all categories.
Key insight: This is where Spec-Kit shines. The agent thinks through edge cases you might have missed and documents the decisions.
Step 4: The Plan Command
Now we define the how.
Before planning, read your spec and make sure it's correct. All planning, research, task generation, and implementation will be based on this spec. Fix it now, not later.
/speckit.plan
## 1. Cleanup & Deletion
- Delete Controllers/EventsController.cs, MessagesController.cs, WeatherForecastController.cs
- Remove associated DTOs
## 2. Domain Layer
- Create Domain/Entities/EmailDeliveryReport.cs with GuardClauses
## 3. Application Layer (CQRS & MediatR)
- Create SaveEmailDeliveryReport command (co-locate with handler + validator)
- Create GetEmailDeliveryReports query (co-locate with handler + validator)
## 4. Infrastructure Layer
- Update Cosmos DB configuration
- Update Bicep templates
- Configure Dapr pub/sub
## 5. Web Layer
- Create Dapr pub/sub endpoint in EmailNotificationController
- Create GraphQL queries with HotChocolate
## 6. Configuration & Wire-up
- DI registration via Configuration/ folder extension methods
Output: A complete plan with research decisions, data models, GraphQL contracts, Dapr subscription specs, and a quickstart guide. All constitution checks passed.
Step 5: The Tasks Command
This command takes the plan and turns it into a series of tasks for the AI to follow. No additional input needed, just run it:
/speckit.tasks
Output: 33 tasks across 6 phases, with clear parallelization opportunities:
| Phase | Tasks | Focus |
|---|---|---|
| Phase 1: Setup | T001–T003 | .csproj upgrade, folder scaffold |
| Phase 2: Foundational | T004–T006 | Repository port, validation stub |
| Phase 3: US1 (MVP) | T007–T015 | Entity, command, controller |
| Phase 4: US2 | T016–T020 | GraphQL queries |
| Phase 5: US3 | T021–T025 | Legacy code cleanup |
| Polish | T026–T033 | Bicep, configuration |
Step 6: The Analyze Command (Optional but Recommended)
The analyze command reviews all artifacts for inconsistencies, ambiguities, or coverage gaps. It's read-only, the agent won't make changes.
/speckit.analyze
The analysis found 9 issues, including:
- CRITICAL: Missing FluentValidation validators in query files (violates Constitution Principle I)
-
HIGH:
TotalCountfield in GraphQL schema couldn't be populated - HIGH: DI registration removal happening before dependent controllers were deleted
I asked for concrete remediation:
Suggest concrete remediation edits for the top issues
The agent provided specific edits for each issue, which I applied directly to tasks.md.
Always run analyze before implementation. It catches constitutional violations and logical gaps that would cause runtime failures.
Step 7: The Implement Command
Finally, the agent runs through the task list and writes the code. You end up with a fully implemented feature that actually matches your initial vision.
/speckit.implement
Result: Implementation complete — 33/33 tasks ✅
- Build succeeded with 0 errors, 0 warnings
- All legacy files deleted
- Full infrastructure defined in Bicep
- GraphQL endpoint working
- Dapr pub/sub configured
Add a new feature
We can reuse our spec with a different plan, task list, and implementation. For example, if I want to implement a similar kind of feature using a different stack or database, I can use that spec file again because it does not contain any implementation details, only the required features from a user’s perspective. I could walk through the whole process again if I wanted to add another feature to the application.
I am going to start with a new spec. I do not need to change the constitution file because there have been no changes to the grounding principles of the app. We can jump straight to the specify command. We have a new branch and a new spec file inside the folder.
When Should You Use Spec Kit?
Use it when:
- You want structured AI development
- You work in a team environment
- You need traceability and consistency
Avoid it when:
- You’re building quick throwaway prototypes
- The feature is too small (overhead isn’t worth it)
The Future of Spec-Kit
Spec-Kit is new and constantly evolving. New features are being added regularly, so keep up by checking the GitHub repo.
You can find the source code for the demo app here: ACSdemo

Top comments (0)