DEV Community

Cover image for Spec-Driven Development with OpenSpec
Christopher Sidebottom
Christopher Sidebottom

Posted on • Originally published at algorithm.kitchen

Spec-Driven Development with OpenSpec

I'm one to stare at the screen blankly, not knowing where to start, or get distracted mid-flow by a shiny new idea. OpenSpec and Spec-Driven Development help automate many of the tedious aspects of the development flow so I can break away when necessary:

  • Blank pages and no starting point - /opsx:explore
  • Tedious documentation of technical details - /opsx:propose
  • Helping, not hindering writing the code - /opsx:apply
  • Finishing projects cleanly, ensuring consistency - /opsx:archive

So how do we get started? Let's start by installing it (NodeJS required):

npm install -g @fission-ai/openspec@latest
openspec init
Enter fullscreen mode Exit fullscreen mode

That'll install a bunch of skill files for your current coding assistant, for Claude Code this surfaces as /opsx: prefixed commands for the core OpenSpec workflow:

The OpenSpec Core Workflow

One reason I liked OpenSpec more than others, such as Kiro and SpecKit, is that OpenSpec is highly portable between coding assistants, codebases and stages of development. I've plugged OpenSpec into all sorts of projects, from infrastructure to Python libraries. I also work on diverse codebases, with a variety of AI friends that OpenSpec supports: OpenCode, Codex and Claude Code.

Explore

The initial explore phase is optional, but I often open a new terminal and try out new ideas. My brain gets stuck if I have too many things happening at once, and exploring ideas helps to dump them to disk and restore focus.

Say I'm tinkering with deathclaw-alpha, a little self-hosted AI assistant I run at home on OpenClaw and a local vLLM instance:

/opsx:explore can deathclaw-alpha use a smaller model for its background heartbeats?
Enter fullscreen mode Exit fullscreen mode

If you're new to OpenSpec, it can create specs as you go along, no need to ingest everything. For deathclaw-alpha, OpenSpec already has a bunch of specs in my repo which have encoded how to reach our models:

### Requirement: vLLM via Service DNS
OpenClaw's model provider SHALL reach vLLM via the in-cluster Service DNS, not the public Ingress.

#### Scenario: Inference round-trip uses cluster DNS
- **WHEN** a user sends a chat message
- **THEN** the pod resolves the in-cluster Service and completes the OpenAI-API request
Enter fullscreen mode Exit fullscreen mode

OpenSpec output is helpfully minimal and easy to understand, which reduces the amount of cognitive load required by both me and my AI friends. Using /opsx:explore raises questions to help eek out those details sitting in my mind:

A few things worth pinning down before you pick:

- The router exposes backend-neutral aliases. Should the spec name the tier (pro/fast) or the model sitting behind it?
- Heartbeats are frequent and cheap. Is it cost or latency you're saving?
Enter fullscreen mode Exit fullscreen mode

And when a question doesn't have an answer yet, /opsx:explore doesn't force one. It lays out the options, or suggests a spike to investigate, giving me and my AI friend something concrete to think about before anything gets written down.

Now I'm not staring blankly at the screen, and the idea is naturally aligned to the existing specs. I can have loads of ideas, and /opsx:explore helps me translate those into concrete proposals using /opsx:propose.

The blank screen problem has disappeared!

Propose

Writing a design document is such a good idea for developers, especially those with short memories or needing a bit of extra structure. You may have heard of RFCs or ADRs, which are the same sort of concept. For me, design docs help me to understand the work and review others' designs.

Unfortunately, writing design documents is often pretty dull. You may have seen the advice to ask your AI friend to write a better prompt for you, and that's really what /opsx:propose does, generating all the various markdown files for a design:

openspec/changes/deathclaw-alpha-router-models/
├── proposal.md  ← why repoint onto the multi-model router
├── design.md    ← provider/model-ref shape, any rejected alternatives
├── tasks.md     ← bump, repoint, routing split, verify
└── specs/       ← spec deltas
    └── deathclaw-alpha/
        └── spec.md
Enter fullscreen mode Exit fullscreen mode

When I add OpenSpec to existing projects, this is how I start to build up these documents as I go along, you'll eventually capture everything in specs, or find you don't need to. The openspec folder naturally builds up as you continue to develop and all those legacy codebases are suddenly not quite as scary anymore!

Now we have design docs, which were always a good idea. You can commit the entire openspec/changes/<feature> folder and raise a Pull Request, which means they are treated as first class citizens in version control.

This also means that early review can happen, whilst you move onto /opsx:apply.

Apply

During /opsx:apply our AI friends re-read what /opsx:propose wrote:

  • proposal.md for why
  • design.md for how
  • tasks.md for what's next

Spec-Driven Development is distinguished from Vibe Coding because these structured specifications help to guide an agent towards more consistent results. Our AI friends read all of these files before starting work which means they are more likely to stay with the agreed plan instead of improvising.

The proposal keeps the goal in view:

## Why
deathclaw-alpha points at a single-model endpoint. The enclave now serves capability-named aliases through a router — deathclaw/pro (quality) and deathclaw/fast (low-latency).

## What Changes
- Repoint the vLLM endpoint to the router Service
- Declare two models: deathclaw/pro and deathclaw/fast
- Route interactive turns to /pro, heartbeats to the cheaper /fast

## Capabilities

### Modified Capabilities
- `deathclaw-alpha`: single-model endpoint → router with a primary/heartbeat model split
Enter fullscreen mode Exit fullscreen mode

The design records the options I weighed, which helps me and my AI friend to remember why we did things:

## Context
deathclaw-alpha is live on a single model. The enclave now fronts several models behind one router that dispatches on the OpenAI `model` field.

## Decisions
The model ref is `<provider>/<id>`; the id is sent on the wire as the `model` field, so it MUST match a router alias verbatim:

- **Provider key `vllm`, id = the alias** (`deathclaw/pro`, `deathclaw/fast`).
- **Alternative (design B): provider key `deathclaw`, id `pro`/`fast`** — cleaner ref, but sends `model: pro`, forcing a cross-repo enclave change. Rejected.

## Risks / Trade-offs
OpenClaw's `heartbeat.model` override has a history of being silently ignored. Set it anyway, then verify against the router logs after deploy.
Enter fullscreen mode Exit fullscreen mode

And the task list is, surprisingly, a task list to work through step-by-step:

## 3. Provider + endpoint
- [x] 3.1 Rename provider key `vllm-gemma``vllm`
- [x] 3.2 Point baseUrl at the router Service
- [x] 3.3 Replace the single model with two: deathclaw/pro, deathclaw/fast

## 4. Agent routing
- [x] 4.1 primary → vllm/deathclaw/pro
- [ ] 4.2 heartbeat → vllm/deathclaw/fast
Enter fullscreen mode Exit fullscreen mode

One thing to try in your coding assistant is asking it to create tasks from /opsx:apply to check off the pre-agreed plan. OpenSpec is additive, working with your coding assistant, not replacing it.

It's not a fixed list though, as you write code you typically find issues or unforeseen complexities. When our AI friends are uncertain using /opsx:apply, they are told to stop and ask:

## Implementation Paused

**Change:** deathclaw-alpha-router-models
**Schema:** spec-driven
**Progress:** 5/8 tasks complete

### Issue Encountered
OpenClaw's `heartbeat.model` override has a history of being silently ignored, and the docs don't say whether this build honours it. So I can't tell if heartbeats will actually land on the cheaper model.

**Options:**
1. Set it anyway and verify against the router logs after deploy
2. Skip it and force the model with a cron-job override now
3. Other approach

What would you like to do?
Enter fullscreen mode Exit fullscreen mode

I've found OpenSpec to be permissive when it comes to updating specs in-flight, iterating until a viable solution is found. All of this is visible when you raise your pull request to land your feature, documentation naturally updating alongside the code.

Archive

The exciting implementation is over, my motivation has drifted to the next feature proposal. Now you have to revisit your design notes and make sure they are up to date. That's boring! /opsx:archive takes care of merging the new specs and archiving the design documents. OpenSpec handles synchronisation using spec deltas, ## MODIFIED Requirements and ## ADDED Requirements blocks that OpenSpec merges back into the capability's spec, such as these updates to deathclaw-alpha:

## MODIFIED Requirements

### Requirement: vLLM via Service DNS
OpenClaw's model provider SHALL reach vLLM via the router Service DNS. Each model under the provider's `models[]` SHALL carry an `id` matching a router alias exactly.

#### Scenario: Inference round-trip uses router DNS
- **WHEN** a user sends a chat message
- **THEN** the pod resolves the router Service and completes the OpenAI-API request

## ADDED Requirements

### Requirement: Primary and heartbeat model routing
Interactive turns SHALL route to `vllm/deathclaw/pro`; heartbeats to `vllm/deathclaw/fast`.

#### Scenario: Interactive turn uses the quality model
- **WHEN** a user message is processed by the default agent
- **THEN** the request carries `model: "deathclaw/pro"`
Enter fullscreen mode Exit fullscreen mode

Typically I'll /opsx:archive as the last commit when I finish implementing a spec; that means one fewer archive-only review and everything neatly wrapping up. Often I forget, and these updates end up in their own commit which is likely cleaner and more atomic.

That means the next time I run /opsx:explore with a new crazy idea, or start a new /opsx:propose, our specs have context for me and my AI friends supporting me.

Wrap up

I want to focus on the cool stuff, but I need the boring stuff to help my brain work. Hopefully you can see how Spec-Driven Development is helpful for both our AI friends and for us as creative engineers. If I have half a thought, I start to explore it, document it and then it's captured without interfering with my workflow.

If you're looking for complementary skills and plugins then have a look at Addy Osmani's Agent Skills or Superpowers, both provide essential coding assistant skills like Test-Driven Development (TDD). OpenSpec provides consistency, and your workflow can evolve around it.

Top comments (0)