Spec-Driven Development: The Future of AI Coding

Our Approach
The engineering practices at Digital Speed have evolved over the years. But one thing that hasn't changed is our focus on writing high quality, maintainable code. And since the advent of AI and vibe coding, it's become far more important to ensure clean and maintainable code is being written. What is vibe coding I hear you say? Below is a quote directly from Merriam Webster:
"Vibe coding is a recently-coined term for the practice of writing code, making web pages, or creating apps, by just telling an AI program what you want, and letting it create the product for you. In vibe coding the coder does not need to understand how or why the code works, and often will have to accept that a certain number of bugs and glitches will be present."
Vibe coding is inherently risky because, unless there's a significant amount of time invested in reviewing the AI-generated code, it's very likely to introduce issues. Not only that, but the code is harder to maintain and the transfer of knowledge is challenging at best. For those reasons, our team only used AI to write tedious refactors or edit inline code segments, as opposed to vibe coding full features. But times are changing....
This is where GitHub's Spec Kit comes in. This is an open-source tool that allows any developer to swap vibe coding with Spec-Driven Development (SDD). Now why is this better than vibe coding? It's because it forces everyone in a team to establish shared context before any implementation begins, which means AI agents and teams build exactly what was intended. By separating intent from code, we can avoid the chaos of assumptions and ensure every decision is explicit, reviewable, and easier to evolve. Dive into more detail about SDD in this blog post by Den Delimarsky, Principal Product Engineer at Microsoft's CoreAI division.
This open-source tool is a game-changer. And it makes sense. We have learned a lot after building many products for our clients over the years here at Digital Speed. There's an industry best-practice behind every successful product launch - and it starts with creating detailed specification documents. This is what Spec Kit was designed to do.
Spec-Driven Development with Spec Kit is a feature-based approach to writing code, and it all starts with generating details documentation. The core concept is to produce enough accurate detail about intent so that the AI has the contextual foundation to build a happy-path for the feature. The idea is to produce a set of files based on pre-determined commands, along with prompts to steer the agent. Those files are generated as markdown files. It's important they're generated in the following order as each prior step gives context to the next:
- Constitution: defines the project constitutional guardrails. These are the non-negotiable principles that must be adhered to at all times.
- Specification: build a specification document and requirements checklist based on your prompt.
- Clarify: asks 3-5 clarification questions on the spec to help prevent ambiguities. For this, I will prompt it with "Are you 100% confident that you've asked all clarification questions and covered all potential edge cases? If not, find all possible edge cases or loopholes, ask the necessary clarification questions and run this loop until you are factually 100% confident that you have covered everything."
- Plan: create a technical plan for the specification.
- Tasks: break down the technical plan and the spec into a set of individual tasks.
- Analyse: analyses the spec, plan, and task breakdown for any inconsistencies.
- Checklist: create “unit tests for English” for your specification, enabling you to quickly find blind spots in your domain thinking.
- Implement: implement the project based on all of the combined artefacts.
- Converge (new): assess the codebase against spec.md / plan.md / tasks.md files and append remaining work as new tasks
Clarify, Analyse and Checklist are intermediary commands we can run between each doc generation step which helps us to clarify, analyse and update the generated artefacts. This is outlined in the below diagram:
For the planning, we would use the latest frontier models (currently, Fable 5 or GPT 5.6 Sol), and then delegate the implementation of the plan to more cost-effective models, as all the heavy lifting is done at the planning stage. Ultimately, you end up with a directory structure like this alongside the rest of the files and directories in your codebase that are unrelated to Spec Kit:
.specify/
├── extensions.yml
├── feature.json
├── init-options.json
├── integration.json
├── extensions/
│ ├── .registry
│ ├── .cache/
│ │ ├── catalog-ebf165086500aab1-metadata.json
│ │ ├── catalog-ebf165086500aab1.json
│ │ ├── catalog-metadata.json
│ │ └── catalog.json
│ └── git/
│ ├── README.md
│ ├── extension.yml
│ ├── config-template.yml
│ ├── git-config.yml
│ ├── commands/
│ │ ├── speckit.git.commit.md
│ │ ├── speckit.git.feature.md
│ │ ├── speckit.git.initialize.md
│ │ ├── speckit.git.remote.md
│ │ └── speckit.git.validate.md
│ └── scripts/
│ ├── bash/
│ │ ├── auto-commit.sh
│ │ ├── create-new-feature-branch.sh
│ │ ├── git-common.sh
│ │ └── initialize-repo.sh
│ └── powershell/
│ ├── auto-commit.ps1
│ ├── create-new-feature-branch.ps1
│ ├── git-common.ps1
│ └── initialize-repo.ps1
├── integrations/
│ ├── claude.manifest.json
│ └── speckit.manifest.json
├── memory/
│ ├── constitution.md
│ └── .claude/
│ └── settings.local.json
├── scripts/
│ └── bash/
│ ├── check-prerequisites.sh
│ ├── common.sh
│ ├── create-new-feature.sh
│ ├── setup-plan.sh
│ └── setup-tasks.sh
├── templates/
│ ├── checklist-template.md
│ ├── constitution-template.md
│ ├── plan-template.md
│ ├── spec-template.md
│ └── tasks-template.md
└── workflows/
├── workflow-registry.json
└── speckit/
└── workflow.yml
specs/
├── 001-example-feature/
├── 002-example-feature/
└── 003-example-feature/And within the individual feature directories (which by the way, are also the name of the feature branch you are now working on) shown in the specs directory above, you'll have your generated files which will look like this:
specs/
├── 001-example-feature/
│ ├── spec.md
│ ├── plan.md
│ ├── tasks.md
│ ├── research.md
│ ├── data-model.md
│ ├── quickstart.md
│ ├── checklists/
│ │ └── requirements.md
│ └── contracts/
│ └── http-api.md (example)
├── 002-example-feature/
│ ├── spec.md
│ ├── plan.md
│ ├── tasks.md
│ ├── research.md
│ ├── data-model.md
│ ├── quickstart.md
│ ├── checklists/
│ │ └── requirements.md
│ └── contracts/
│ └── design-tokens.md (example)
└── 003-example-feature/
├── spec.md
├── plan.md
├── tasks.md
├── research.md
├── data-model.md
├── quickstart.md
├── checklists/
│ └── requirements.md
└── contracts/
└── figma-ref.md (example)The final step is to run the implement command and let the LLM go to work implementing the tasks created in the tasks.md file. But before that, we get our AI Agent of choice (we use Claude Code and Codex at Digital Speed), to use GitHub's CLI tool to create a Pull Request from our current branch 001-example-feature-one to main with a detailed description, to make sure that the effort is properly tracked and our entire team can view the spec documentation before implementation. It's worth spending an hour or two planning, clarifying and manually reviewing the files ahead of implementing.
Then, when we run the implement command, we typically prompt it with this excellent prompt that ensures it completes all tasks end-to-end:
"/speckit.implement I have one complete tasks.md to push end to end. Treat it as one end-to-end goal: take the whole plan to done, until architecture, implementation, tests, review and the final result all clear the bar. Break the tasks.md into independent parts, spawn as many parallel subagents as it takes, and give each one its own goal with a clear deliverable, a verification method, and done criteria and ensure it marks its task complete once it is done with the implementation. Ensure the relevant skills or MCP serves are utilised or loaded on demand where a task can use one so context is engineered into the task. When deploying parallel subagents, ensure that everything that can be deterministic, is done with a deterministic tool. Don't try to get the poor subagents to follow a deterministic process without a tool.
Then run it like an operator: schedule the agents in parallel, track progress, synthesise what comes back, resolve conflicts, keep implementing, verify live after every important step, review when it matters, commit when it's ready, and close with a final summary. Verification must cover the real end-to-end path: browser and computer use, clicks, keyboard, whatever it takes. don't stop at partial progress. If you're blocked by missing credentials, destructive ambiguity, or conflicting requirements, move onto the next task and keep the task marked as incomplete.
Where human intervention is absolutely necessary, defer or keep tasks as incomplete but do not block end-to-end completion."
Here you may also like to include references to skills such as /agent-browser or /playwright-cli for full end-to-end testing during the implementation, so long as these tools or workflows are defined in the constitution. Once implemented, we can now run the converge command to assess the codebase against the generated implementation files (note: it only makes sense to run this command in the case that you're working in a project with pre-existing files), and it will append any remaining work as new tasks.
Finally, we're able to release this as a feature branch 001-example-feature-one via our CI/CD pipeline to manually QA the results. This entire workflow has led to astounding results!
If you are looking to bring Spec-Driven Development to life in your own organisation, our engineering team can help you move from idea to production with clarity, pace and confidence. Reach out to us and explore how we can accelerate your next build or check out our custom web development services to find out more.