OpenSpec Explained: A Hands-On Guide for 2026
OpenSpec is the spec-driven development framework I reach for when I'm working on a codebase that already has a lot of history. It doesn't pretend the repo is greenfield. It doesn't ask you to write a constitution before you can ship a small change. It just isolates the change, writes a spec, validates it, applies it, and archives it. That's the whole loop.
This post is a practical guide to OpenSpec on its own terms — not a comparison. If you want the head-to-head against GSD and Spec Kit, I wrote that comparison separately. Here I want to explain what OpenSpec actually does, how the four-phase state machine feels in practice, and what I'd change about it if I could.
What Is OpenSpec?
OpenSpec is an open-source spec-driven development tool from Fission AI (Y Combinator). The thesis is one line from the README: "Generating code is now cheap. Correctness is still expensive."
The framework sits between you and your AI coding agent — Claude Code, Cursor, Copilot, Gemini CLI, or any of the 24+ supported tools. You propose a change, OpenSpec scaffolds a change folder with a proposal, specs, design notes, and tasks, your agent executes against that scaffold, and the resulting spec gets archived into a permanent specifications directory.
The core unit is the change, not the feature. A change is a bounded, reviewable delta with its own folder. That framing matters more than it sounds — it's what makes OpenSpec feel different from Spec Kit.
The Four-Phase State Machine
Every OpenSpec change moves through the same states:
- Propose — You describe what's changing. OpenSpec generates
proposal.md, seeds spec files, and drops task stubs. - Validate — OpenSpec checks the proposal for structural completeness. Missing acceptance criteria, orphaned specs, or unbounded scope get flagged.
- Apply — Your agent reads the change folder and implements. OpenSpec doesn't orchestrate — it hands the context to the agent and gets out of the way.
- Archive — Once the change merges,
/opsx:archivemoves the specs fromchanges/<id>/specs/into the permanentspecs/tree. The change folder gets zipped and preserved as an artifact.
The folder looks like this after a propose step:
openspec/
├── specs/ # permanent, archived specs
│ └── auth/
│ └── session-management.md
└── changes/
└── 2026-03-19-password-reset/
├── proposal.md
├── design.md
├── specs/
│ └── auth/
│ └── password-reset.md
└── tasks/
├── 01-email-template.md
└── 02-reset-endpoint.md
The naming convention (date-prefixed change ID) is a small detail that saved me hours. Chronological sort in a file tree = a usable history without any tooling.
Installing OpenSpec
Setup is deliberately boring. That's a feature.
npx @fission-ai/openspec@latest init
The init command creates the openspec/ directory, drops the default configuration, and registers slash commands with whichever AI agent you're using. For Claude Code that means adding the /opsx:* commands to your .claude/commands/ directory. For Cursor it drops rules into .cursor/rules/.
If you already have a codebase with undocumented logic — the usual case — run the onboarding command:
/opsx:onboard
This is the single feature that sold me on OpenSpec. It reverse-engineers your existing code into baseline specs. Not perfect specs — you'll edit them — but a starting point that most SDD tools assume doesn't exist. Spec Kit, by comparison, expects a clean slate.
Writing a Proposal
The proposal is the contract. Everything downstream — the generated specs, the task list, the agent's implementation — flows from whatever you put here.
A good proposal has three sections:
## Why
Users currently can't reset their password without contacting support.
Support tickets for this average 12 per week. We want to ship a
self-service reset flow that doesn't require engineering on every case.
## What Changes
- New `POST /auth/password-reset/request` endpoint
- New `POST /auth/password-reset/confirm` endpoint
- Transactional email template for the reset link
- Short-lived reset token stored in the sessions table
## Out of Scope
- Multi-factor auth on the reset flow
- Rate limiting (handled at the gateway)
- UI changes (separate change)
The Out of Scope section is where OpenSpec earns its keep. It's a structural reminder to scope aggressively. Every SDD framework preaches this. OpenSpec bakes it into the template so you can't skip it without noticing.
Validation: The Part Most Tools Skip
After the proposal is written, /opsx:validate walks the change folder and runs structural checks:
- Every spec file has acceptance criteria
- Every task references a spec it contributes to
- No specs are orphaned (referenced by nothing)
- The proposal's "What Changes" list matches the specs scaffolded
This sounds small. It isn't. Two hours into a change, when you're tired and about to hand it to the agent, this is the step that catches the missing piece. I've had validate flag that I scaffolded a reset-token spec but never wrote a task for the token cleanup job. Would the agent have caught it? Maybe. But I shouldn't need the agent to be the safety net for my own planning.
Strict mode is worth turning on from day one:
# openspec.config.yaml
validation:
strict: true
required_sections:
- why
- what-changes
- out-of-scope
Apply: Where the Agent Takes Over
Apply is where OpenSpec is philosophically different from GSD. GSD orchestrates — it spawns fresh subagents per task, prunes context, and manages git operations deterministically. OpenSpec hands the change folder to whatever agent you connected and trusts it to execute.
That's a trade-off. You lose the context isolation and parallel execution GSD provides. You gain agent portability — the same change folder can be applied by Claude Code today and by Cursor tomorrow without modification.
In practice the apply step for Claude Code looks like:
/opsx:apply 2026-03-19-password-reset
Claude Code then reads the proposal, specs, and tasks, and executes. The task files act as a checklist the agent can tick off. No orchestration layer, no verification ladder — just a structured context and a motivated agent.
For small-to-medium changes this works well. For changes with more than ~8 tasks, context rot starts to bite. I've watched Claude Code forget what task 2 did by the time it reached task 7. OpenSpec doesn't solve this. GSD does, via anchor-message context pruning.
Archive: Specs as Living Documentation
When a change merges, archive moves the specs into the permanent tree:
/opsx:archive 2026-03-19-password-reset
This is where OpenSpec's philosophy about specs as documentation shows up. The specs that survive to openspec/specs/ are the ones that describe the system as it is, not as it was proposed. Future changes that touch the same area load these specs as context. You're incrementally building a specification of your running system, one change at a time.
It's the closest thing I've seen to living documentation that actually stays current, because the update happens at merge time, not as a separate chore.
Where OpenSpec Wins
- Brownfield onboarding is unmatched.
/opsx:onboardis the only reverse-engineering story in the SDD space that actually works. Point it at a legacy Rails app and get back a starting set of specs that describe reality, not aspiration. - Change isolation. Every change lives in its own folder until archive. No cross-change contamination. Easy to pause a change, work on another, and come back.
- Lightweight output. A typical OpenSpec change is ~250 lines of markdown across proposal, specs, and tasks. Spec Kit features are 3–4x that. Less noise, less review burden, more likely to actually get read.
- Broadest agent support. 24+ tools. You're not locked into one vendor's agent.
- Low ceremony. Four commands. No constitution to write. No seven-phase pipeline. If you're shipping a small change, OpenSpec stays out of your way.
Where OpenSpec Falls Short
- No execution orchestration. Apply hands the change to the agent and hopes for the best. On longer changes, context rot degrades quality. You can split a change into multiple smaller changes, but that's a workaround, not a solution.
- Specs are static during apply. If the agent discovers a spec assumption is wrong mid-implementation, the spec doesn't auto-update. You fix it manually after the fact. Augment's Intent and GSD's goal-backward verification both do more here.
- Manual archive discipline. If you forget to archive, specs and reality diverge. I've walked into OpenSpec repos where half the "pending" changes had shipped months ago. This is a human problem OpenSpec doesn't automate around.
- No automatic git branching. You manage branches yourself. For solo work that's fine. In teams it's a surprise.
- Validation occasionally false-positives. A handful of GitHub issues describe validation errors on legitimately-structured specs. Usually fixed by a version bump, but worth knowing.
When I Reach for OpenSpec
I use GSD as my default on greenfield projects — the orchestration and context isolation matter too much to give up. But when a client hands me a 3-year-old NestJS codebase with undocumented business logic, OpenSpec's onboarding command is the first thing I run. Thirty minutes later I have a starting spec set, and from there the four-phase loop is light enough that I can ship small, reviewable changes without the ceremony tax.
Rule of thumb:
- Greenfield, solo, Claude Code primary → GSD
- Brownfield, fast iteration, any agent → OpenSpec
- Team environment, cross-agent, governance needs → Spec Kit
For the full decision tree, see the SDD tools comparison.
Give It 30 Minutes
If you've been curious about spec-driven development but put off by the ceremony, OpenSpec is the lowest-commitment way in. Pick the smallest change on your current project. Run /opsx:onboard on the affected module, /opsx:propose the change, and walk through the four phases once. You'll have a feel for whether the workflow earns its keep on your codebase within an hour.
Check out my tools and stack for the full development setup I pair with OpenSpec on client work.
Shipping with OpenSpec or evaluating SDD tools? Reach out — I'm always trading notes on what works.