Spec-Driven Development in Practice: A Walkthrough with Spec Kit

Spec-Driven Development in Practice: A Walkthrough with Spec Kit

Introduction

As organizations and engineering teams adopt AI coding agents to accelerate output, spec-driven development (SDD) has emerged as a way to code more responsibly, steering the models in the direction you actually want them to go.

As attractive as Vibe Coding might sound, it's only viable for quick MVPs and prototypes. When you're building critical systems and enterprise solutions, engineers still need to guarantee code quality, meet security requirements, keep documentation up to date, and keep all the stakeholders in sync with the project status and health.

SDD takes a step back and tries to involve the AI coding agents in every phase of the software development lifecycle (SDLC), not only coding. That way the model ends up with all the required context to build a story or feature. If you want to understand the difference between Vibe Coding and SDD more deeply, check my previous article: Vibe Coding vs. Spec-Driven Development.

The SDLC phases covered by SDD:

Why I Tried Spec Kit

I had been building features on this blog by just prompting Claude directly. Describe the feature, iterate on the output, ship. It worked well enough for small changes, but for anything non-trivial I kept running into the same problems: scope creep mid-session, ambiguous requirements only noticed after implementation, and no artifact left behind to explain why a decision was made.

I wanted to try SpecKit to get hands-on experience with a more disciplined approach. Given the growing trend of AI-assisted development, I figured now was the right time to learn SDD properly rather than continue vibe coding.

How It Works (High Level)

SpecKit (or SDD) is used to:

  1. Define a feature before coding
  2. Clarify ambiguous requirements early
  3. Generate planning and tasks artifacts
  4. Feed the implementation learnings back into the spec and constitution (project memory)

SDD is more than a code generation workflow. The useful part is this iteration loop:

  1. Capture the intent (Requirements)
  2. Remove Ambiguity (Analyze & Clarify Gaps)
  3. Create a Plan (Project Phases, Sprints, Epics, Tasks)
  4. Implement (Actually code)
  5. Update the spec with what was learned
  6. Update the task and project status
  7. Update the constitution (memory) if a rule should become permanent across the entire project

One-Time Setup

1. Install and initialize Spec Kit

Install SpecKit in an existing project.

brew install uv
uvx --from git+https://github.com/github/spec-kit.git specify init --here

During setup, I selected the following options, but do experiment with different AI models:

  • AI assistant: claude
  • script type: sh

After the speckit initial setup is completed, this is the expected result.

# claude specific commands you can now use to do SDD development
.claude/
└── commands/
    ├── speckit.analyze.md
    ├── speckit.checklist.md
    ├── speckit.clarify.md
    ├── speckit.constitution.md
    ├── speckit.implement.md
    ├── speckit.plan.md
    ├── speckit.specify.md
    ├── speckit.tasks.md
    └── speckit.taskstoissues.md
 
.specify/
├── memory/
   └── constitution.md # project memory (rules, guidelines, constraints)
├── scripts/ # these scripts are what speckit uses to help automate the SDD process
   └── bash/
       ├── check-prerequisites.sh
       ├── common.sh
       ├── create-new-feature.sh
       ├── setup-plan.sh
       └── update-agent-context.sh
└── templates/ # these are the default speckit templates used to create MD files. I did not touch these for the experiment, but plan to refine these for my own customizations
    ├── agent-file-template.md
    ├── checklist-template.md
    ├── constitution-template.md
    ├── plan-template.md
    ├── spec-template.md
    └── tasks-template.md

The Workflow I Followed

2. Define the constitution first

Before writing the first spec, encode the project rules that should guide all future work.

/speckit.constitution This is a Next.js blog for a software developer. The layout is in /src/layouts. The React components in react are in /src/components. Any business logic or server side logic is in src/services. Web pages and APIs are in /pages. The blog content, in MDX format, lives in /src/content. The UIUX design system is in docs/knowledge-base/ui/design-system.md. Additional documentation about the project is in /docs/knowledge-base. We are trying to not introduce any new dependencies unless needed.

Then review and edit .specify/memory/constitution.md

3. Create the feature spec

Start a new feature with a detailed feature prompt using the command /speckit.specify

/speckit.specify I want to build a classic instagram mural on my website. The new page should be in /moments route. The moments page should match the themes (light/dark) defined on my website. It should contain a instagram like grid of photos. The grid should be mobile responsive. When you click in a photo, a modal (80% width of the screen) should open to display the image on the left side, and on the right there is some information about that photo (location, description, date). The /moments page should load data from a yml file moments.yml

Expected outputs:

  1. a feature branch such as 001-moments-photo-grid
  2. The following files are created
specs/
└── commands/
    ├── 001-moments-photo-grid/
        ├── spec.md
        ├── checklists/requirements.md

Important habit:

  • be overly specific in the initial prompt
  • immediately review spec.md
  • add missing functional requirements before moving on

4. Clarify ambiguity before planning

Use the /clarify command to force decisions on UX, behaviour, data shape, and boundaries.

/speckit.clarify Review specs/001-moments-photo-grid/spec.md and identify gaps, ambiguity, and missing decisions.

Typical output:

  • guided questions with recommended options
  • decisions that materially change complexity
  • direct spec updates after answers are given

Example:

  Question 1 o 5                                                                                                                                                            
  
  Category: Interaction & UX Flow Modal navigation scope                                                                                                                   
                                                                  
  The spec defines opening a photo modal but doesn't address whether visitors can move between photos without closing and reopening. This is a significant scope decision —
  it materially changes the complexity of the modal component.
 
  Recommended: Option B — Prev/next navigation buttons in the modal. This is the expected Instagram-style pattern and avoids friction of closing/reopening. The incremental
  complexity is low and delivers a noticeably better browsing experience.
 
  ┌────────┬──────────────────────────────────────────────────────────────────────────┐
  │ Option │                               Description                                │
  ├────────┼──────────────────────────────────────────────────────────────────────────┤
  │ A      │ No navigation — visitor must close modal and click the next photo        │
  ├────────┼──────────────────────────────────────────────────────────────────────────┤
  │ B      │ Prev/next arrow buttons inside the modal to move between photos          │
  ├────────┼──────────────────────────────────────────────────────────────────────────┤
  │ C      │ Keyboard-only navigation (left/right arrow keys) without visible buttons │
  └────────┴──────────────────────────────────────────────────────────────────────────┘
 
  You can reply with the option letter (e.g., "A"), accept the recommendation by saying "yes" or "recommended", or provide your own short answer.

/clarify resolved things like:

  • modal prev/next navigation
  • hover behaviour on thumbnails
  • alt text fallback rules
  • load-more behaviour
  • pagination and scroll behaviour
  • whether modal navigation spans all moments or only currently loaded ones

Rule:

  • do not go to planning while the spec still contains meaningful ambiguity

5. Generate the implementation plan

Once the spec is stable enough, create the plan.

/speckit.plan Consult constitution.md, README.md, and specs/001-moments-photo-grid/spec.md.

Expected outputs:

specs/
└── 001-moments-photo-grid/
    ├── contracts/
    │   └── moments-yml-schema.md
    ├── data-model.md
    ├── plan.md
    ├── quickstart.md
    ├── research.md
    ├── spec.md
    └── tasks.md

The plan did two useful things:

  • translated the spec into concrete architecture for this codebase
  • ran a constitution check before implementation

6. Generate task breakdown

After planning, create executable tasks.

/speckit.tasks Generate tasks from specs/001-moments-photo-grid/plan.md.

Expected output:

specs/
└── 01-moments-photo-grid/
    ├── tasks.md

What to look for:

  • tasks grouped by user story
  • dependency order
  • parallelizable work marked clearly
  • testing and validation tasks included

7. Run analyze before coding

Use /analyze as a guardrail check before implementation.

/speckit.analyze Review the spec, plan, and tasks for constitution violations, hidden complexity, or weak assumptions.

Expected result:

  • refinements to spec.md, plan.md, and tasks.md
  • confirmation that the planned solution still respects repo constraints

/analyze updated the following files

specs/
└── 001-moments-photo-grid/
    ├── spec.md
    ├── plan.md
    ├── tasks.md

8. Implement from the task list

Once the task list is credible, implement against it using the /implement command.

/speckit.implement Implement the tasks from the file specs/001-moments-photo-grid/tasks.md.

The first implementation pass created or updated the following code:

├── meta/
   └── moments.yml
├── src/
   ├── __tests__/
   └── moments.test.ts
   ├── components/
   ├── MomentModal.tsx
   └── MomentsGrid.tsx
   └── Navigation.tsx # updated
   ├── pages/
   └── moments.tsx
   └── service/
       └── moments.ts
└── e2e/
    └── moments.spec.ts
├── specs/
   ├── 001-moments-photo-grid/
       └── tasks.md # marked tasks as complete

The Important Part: Iterate After the First Pass

The biggest practical lesson is that the first implementation is never the final spec. Some requirements only surface after seeing the feature working.

9. Human-test the feature

After implementation:

  • run the UI
  • test the main flow manually
  • identify what feels missing, awkward, or too rigid

From the human tests, these new requirements surfaced:

  1. the /moments page also needed the site background animation
  2. a moment should support multiple photos like a carousel
  3. multi-photo moments needed a visual indicator in the grid
  4. the modal needed carousel navigation
  5. the data model needed to change from one photo to a list of photos

Rule:

  • treat the first implementation as a learning pass, not the last word

10. Update the spec with what you learned

After the feature exists, go back and update the spec to reflect product learnings.

Based on the conversation, encode the learning and the experience pieces (NOT THE TECHNICAL DETAILS) into specs/001-moments-photo-grid/spec.md for the current feature. Then convert those learnings into functional requirements.
  • post-implementation learnings were added to spec.md
  • new functional requirements captured the carousel behavior and related UX rules

This step matters because it turns implicit product judgment into explicit documentation.

11. Update the constitution if the story teaches a reusable rule

Some learnings belong in the feature spec only. Others should become project-level rules.

/speckit.constitution From specs/001-moments-photo-grid/spec.md, is there anything that should be added to the constitution?

The new rule/constraint was added to the constitution.md file:

  • reusable SVG icons should live in src/components/icons/

Rule:

  • only update the constitution when a lesson should apply to future stories
  • do not fill the constitution with story-specific details

Minimal Command Sequence

If you take nothing else from this post, this six-command loop is the core of the workflow:

/speckit.specify   # create a new story/feature (requirements)
/speckit.clarify   # analyze and identify gaps
/speckit.plan      # create the solutions design and plan
/speckit.tasks     # break down plan into tasks
/speckit.analyze   # double check for any gaps, do constitution checks
/speckit.implement # allow your agent to finally start coding

Then do the manual loop: human test, refine, update the spec, and update the constitution if a durable rule emerged.

Practical Rules For Future Stories

  • start with the constitution, not the spec (provide context first)
  • make the initial prompt concrete enough that the generated spec is testable
  • review and edit spec.md manually before clarify
  • use clarify to force product decisions early
  • do not skip analyze
  • implement from tasks.md, not from memory
  • after shipping the first pass, update the spec with product learnings
  • only promote durable lessons into the constitution
  • keep commits aligned to workflow phases so the story stays reviewable

Suggested Commit Cadence

Another step that worked well for me is to commit at every step of the SDD workflow. This way, we have a traceable change history from ideation and requirement gathering all the way to implementation and refinement.

  1. init spec-kit
  2. create constitution
  3. create initial spec 001
  4. update spec after manual review
  5. clarify round (as many rounds as needed)
  6. generate plan
  7. generate tasks
  8. run analyze
  9. implement first pass
  10. implement improvements found in testing
  11. update spec with learnings
  12. update constitution if needed
  13. write or update supporting documentation

What Spec Kit Produced For Spec 001

The 001-moments-photo-grid story generated the following artifact set:

specs/
└── 001-moments-photo-grid/
    ├── checklists/
    │   └── requirements.md
    ├── contracts/
    │   └── moments-yml-schema.md
    ├── data-model.md
    ├── plan.md
    ├── quickstart.md
    ├── research.md
    ├── spec.md
    └── tasks.md

How This Scales Beyond Solo Work

This experiment worked well as a solo developer, but the workflow maps naturally onto team roles too. The entire documentation and decision trail lives in Git, which means it can become a shared source of truth. Product Owners can review and approve requirement changes through pull requests. Developers work from a spec that has already been agreed upon, rather than interpreting a Slack message. Architects can validate the plan before any code is written.

The key insight is that the artifacts SpecKit generates are not just inputs to the AI, they are the project's paper trail. That matters as much in a team setting as it does when you are working alone.

Final Takeaway

The best use of Spec Kit is to make feature intent explicit, pressure-test ambiguity before coding, and then capture what implementation taught you so the next story starts from a better baseline.

That is the core value of the workflow: the feature is no longer just code. It also has a decision trail. It's documented.

Changelog (1)
  • Fix typos and grammar errors throughout the post.