OpenSpec
7 min read
OpenSpec is an open-source spec framework for AI-assisted development: a lightweight layer of Markdown specs that you and your coding agent agree on before any code is written. It is MIT-licensed, distributed on npm as @fission-ai/openspec, and built by Fission AI.
The problem it targets is that requirements normally live only in chat history, so the agent's output is unpredictable and unreviewable. OpenSpec moves them into version-controlled files that sit next to the code.
sh
npm install -g @fission-ai/openspec@latest # needs Node ≥ 20.19.0
cd your-project && openspec init
Its stated philosophy: fluid not rigid, iterative not waterfall, easy not complex, brownfield-first, scalable from personal projects to enterprises.
Layout
openspec init creates:
openspec/
├── specs/ # source of truth — how the system behaves today
├── changes/ # proposed modifications, one folder each
│ └── archive/ # completed changes, full context preserved
└── config.yaml # project configuration
plus per-tool integration directories (.claude/skills/, .cursor/skills/, .agents/skills/, …).
The specs/ ↔ changes/ split is the core idea: several changes can be in flight in parallel without conflicting, each is reviewable on its own, and its deltas merge into the source of truth only when archived.
Specs
Specs are organised by domain (specs/auth/spec.md, specs/payments/spec.md, …) and contain requirements, each with concrete scenarios:
markdown
# Auth Specification
## Purpose
Authentication and session management for the application.
## Requirements
### Requirement: User Authentication
The system SHALL issue a JWT token upon successful login.
#### Scenario: Valid credentials
- GIVEN a user with valid credentials
- WHEN the user submits login form
- THEN a JWT token is returned
- AND the user is redirected to dashboard
Requirements are the what, scenarios the when — testable, covering happy path and edge cases. RFC 2119 keywords carry the strength: MUST/SHALL absolute, SHOULD recommended, MAY optional.
A spec is a behaviour contract, not an implementation plan. Class names, library choices and step-by-step plans belong in design.md or tasks.md. The rule of thumb given: if the implementation can change without changing externally visible behaviour, it doesn't belong in the spec.
Rigor is meant to be progressive — a "lite" spec (short behaviour-first requirements, scope and non-goals, a few acceptance checks) is the default, with full specs reserved for cross-team changes, API/contract changes, migrations and security concerns.
Changes
A change is a self-contained folder:
openspec/changes/add-dark-mode/
├── proposal.md # why and what — intent, scope, approach
├── design.md # how — technical approach and decisions
├── tasks.md # implementation checklist with checkboxes
├── .openspec.yaml # optional metadata: schema, created, skip_specs, retire_capabilities
└── specs/ # delta specs
└── ui/spec.md
The proposal pins down three things — intent (what problem), scope (what's in and out), approach (how). Those three are also the test for whether to revise a change or start a new one: same intent and >50% scope overlap means update; a different problem, exploded scope, or an original that could be marked "done" on its own means a new change. Update preserves context; a new change provides clarity.
Delta specs
The mechanism that makes OpenSpec work on existing codebases. A delta states what is changing rather than restating the whole spec:
markdown
## ADDED Requirements
### Requirement: Two-Factor Authentication
The system MUST support TOTP-based two-factor authentication.
#### Scenario: 2FA enrollment
- GIVEN a user without 2FA enabled
- WHEN the user enables 2FA in settings
- THEN a QR code is displayed for authenticator app setup
## MODIFIED Requirements
### Requirement: Session Expiration
The system MUST expire sessions after 15 minutes of inactivity.
(Previously: 30 minutes)
## REMOVED Requirements
### Requirement: Remember Me
(Deprecated in favor of 2FA.)
| Section | On archive |
|---|---|
## ADDED Requirements | appended to the main spec |
## MODIFIED Requirements | replaces the existing requirement |
## REMOVED Requirements | deleted from the main spec; removing the last requirement retires the capability and deletes its spec file when the change sets retire_capabilities: true |
## Purpose | seeds the Purpose of a newly created spec; ignored if the spec exists |
Deltas keep review focused on what changed, and let two changes touch the same spec file without conflicting as long as they hit different requirements.
The OPSX workflow
OPSX is the current workflow, replacing the legacy hardcoded one. The point of the rewrite was to move instructions out of TypeScript and into editable schema.yaml + templates/*.md files, so prompts can be tweaked and tested without waiting for a release.
The model is actions, not phases — anything can be done at any time:
proposal ──→ specs ──→ design ──→ tasks ──→ implement
Dependencies here are enablers, not gates: they show what is possible to create next, not what is mandatory. design can be skipped; specs and design both depend only on proposal and can be made in either order.
Commands in the default core profile:
| Command | Does |
|---|---|
/opsx:explore | No-stakes thinking partner — reads the code, weighs options, shapes a plan |
/opsx:propose | Create a change and generate its planning artifacts in one step |
/opsx:apply | Work through tasks, checking them off, updating artifacts as needed |
/opsx:update | Revise planning artifacts coherently — never touches code, confirms each edit |
/opsx:sync | Merge delta specs into the main specs without archiving |
/opsx:archive | Move the finished change to changes/archive/ (prompts to sync first) |
An expanded profile adds /opsx:new (scaffold only), /opsx:continue (one artifact at a time), /opsx:ff (all planning artifacts at once), /opsx:verify, /opsx:bulk-archive and /opsx:onboard; select it with openspec config profile and apply with openspec update.
/opsx:propose is the canonical spelling — tools vary (/opsx-propose in Cursor and GitHub Copilot, @opsx-propose in Amazon Q, $openspec-propose in Codex). 30+ tools are supported, including Claude Code, Codex, Cursor, opencode, Pi, Gemini, Cline, Zed, Kiro and Roo Code; openspec init --tools claude,cursor configures them non-interactively.
Configuration
openspec/config.yaml injects project context into every artifact's instructions:
yaml
schema: spec-driven
context: |
Tech stack: TypeScript, React, Node.js
API conventions: RESTful, JSON responses
Testing: Vitest for unit tests, Playwright for e2e
rules:
proposal:
- Include rollback plan
specs:
- Use Given/When/Then format for scenarios
context is prepended to all artifact instructions wrapped in <context> tags (50 KB limit); rules are keyed by artifact ID and injected as <rules> only for the matching artifact. Schema precedence, highest first: --schema flag → the change's .openspec.yaml → config.yaml → the spec-driven default.
Schemas
A schema defines the artifact types and their dependency graph:
yaml
# openspec/schemas/spec-driven/schema.yaml
name: spec-driven
artifacts:
- id: proposal
generates: proposal.md
requires: []
- id: specs
generates: specs/**/*.md
requires: [proposal]
- id: design
generates: design.md
requires: [proposal]
- id: tasks
generates: tasks.md
requires: [specs, design]
openspec schema init <name> creates one from scratch, openspec schema fork spec-driven <name> derives one. Third-party schema bundles are distributed as standalone repos ("community schemas").
CLI
The openspec CLI complements the slash commands — the agent drives the workflow, the CLI handles setup, inspection and validation. Most inspection commands take --json for agent/script use.
| Group | Commands |
|---|---|
| Setup | init, update |
| Browsing | list, view (interactive dashboard), show |
| Validation | validate (--all --json for bulk) |
| Lifecycle | archive |
| Workflow | new change, status, instructions, templates, schemas |
| Schemas | schema init, schema fork, schema validate, schema which |
| Stores | store setup, register, unregister, remove, list, doctor |
| Worksets | workset create, list, open, remove |
| Other | doctor, context, config, feedback, completion |
openspec update regenerates the agent instruction files and must be run after upgrading the package — it is the installed CLI that generates them, so running it against a stale install reports everything up to date.
Stores (beta)
Stores put the openspec/ directory in a repo of its own, shared by git push like any other. This handles the team cases the single-repo layout doesn't: a feature whose code lands in three repos but has one plan; requirements owned by a platform team and referenced read-only by product teams; planning that starts before the code exists.
Notes
The docs recommend high-reasoning models for both planning and implementation, and stress context hygiene — clear the context window before starting implementation.
Comparisons the project draws itself: Spec Kit (GitHub) is thorough but heavyweight — rigid phase gates, a lot of Markdown, Python setup; Kiro (AWS) is powerful but locks you into its IDE and Claude models. OpenSpec is dogfooded — its own specs and in-flight changes are in the repo.
Anonymous telemetry (command names and version only, no arguments, paths or content) is collected and disabled automatically in CI.