OpenSpec: Spec-Driven Development for AI Agents
A practical guide to writing OpenSpec requirements that give AI coding agents stable context about system intent, from first install to working proposals.
Content Table
- Purpose
- Audience
- Prerequisites
- Background
- Schemas
- Core Concepts
- Repository Structure
- Writing a Spec
- Proposing Changes
- Greenfield vs Brownfield
- Parallel Feature Development
- Using OpenSpec with AI Agents
- Tips and Pitfalls
- References
Purpose
AI coding agents write code well. They don't know why the code should exist or what constraints it must satisfy. Ask an agent to "add a session timeout" and it will write code, but it has to guess the rules. Every guess is a hidden decision you'll find in a diff rather than a conversation.
OpenSpec is a tool for practicing Spec-Driven Development (SDD) within the Intent-Driven Development philosophy. See Background for a full explanation of both.
By the end of this guide you will have:
- A working OpenSpec installation in your repository
- A first spec capturing real requirements
- A generated change proposal ready for review
- A clear adoption approach for both new and existing projects
Audience
Software developers using AI coding agents who want better output through structured requirements. Comfortable with git and markdown. No prior experience with SDD needed.
Prerequisites
- Node.js LTS or later
- npm (included with Node.js)
- An AI coding agent, for example, GitHub Copilot
- A git repository (new or existing)
Install the OpenSpec CLI:
npm install -g @fission-ai/openspec@latestVerify the installation:
npx @fission-ai/openspec --versionOpenSpec requires no API keys, no external services, and no lock-in. It is markdown files and a CLI.
First time? Run
/opsx:onboardin your AI coding agent after installing and it will walk you through the full setup in about 15 minutes and help you create your first spec interactively. You can follow this guide alongside it or use it as a reference once you're up and running.
Background
What Is a Spec?
A spec is a markdown file describing what a feature must do but not how to build it. It captures observable behavior using GIVEN/WHEN/THEN scenarios, lives in version control alongside your code, and changes only through a reviewed proposal process.
What Is Spec-Driven Development?
Spec-Driven Development (SDD) puts requirements before code. You write the spec, the agent builds against it, and the implementation is validated before merge. The design conversation happens before the diff exists, so your team reviews intent as a document, not guesses it from code.
What Is Intent-Driven Development?
Intent-Driven Development is the broader philosophy SDD sits inside. Beyond capturing what the system does, it captures why decisions were made, through specs (functional intent), proposals (change intent), and ADRs (architectural intent). The goal is making the developer's full reasoning legible to AI agents across the development lifecycle.
How They Relate
| Spec-Driven Development | Intent-Driven Development | |
|---|---|---|
| What it is | A methodology | The philosophy SDD implements |
| Primary question | What must this feature do? | Why was it built this way? |
| Core artifact | Spec | Specs + Proposals + ADRs |
| Lifecycle | Define → Implement → Validate | Propose → Apply → Verify → Archive |
Schemas
A schema tells OpenSpec which artifact types your project uses and how to validate them. It controls what folders the CLI recognises, what gets generated, and what the validator checks. The schema is declared in openspec/config.yaml at the root of your repository.
OpenSpec ships with several schemas:
| Schema | Artifacts | Best for |
|---|---|---|
default | Specs + proposals (design, tasks, spec delta) | Starting point - covers the full core workflow |
minimalist | Specs + tasks only | Solo devs or fast iteration without a team review gate |
behaviour-driven | Specs with GIVEN/WHEN/THEN requirements and scenarios | Teams already practising BDD who want spec-driven structure |
intent-driven | Proposals + specs + design + ADRs + tasks | Teams who want the full workflow including durable architectural decisions from day one |
spec-driven-with-adr | Default + ADRs | Teams adding ADR persistence on top of an established default workflow |
event-driven | Event Storming + AsyncAPI specs | Systems built around events and async messaging |
linearized | Default specs mirrored to Linear Project Documents | Teams using Linear who want specs synced with their issue tracker |
The default schema
The default schema is what most teams use throughout their OpenSpec lifecycle. It recognises openspec/specs/ and `openspec/changes/. See Repository Structure for the full directory layout.
Each artifact has a defined role and lifetime:
| Artifact | Role | Lifetime |
|---|---|---|
openspec/specs/<name>/spec.md | Source of truth for what the system does | Permanent - grows with the codebase |
openspec/changes/<id>/proposal.md | Intent document reviewed before code is written | Temporary - archived after merge |
openspec/changes/<id>/design.md | Behavioral decisions and alternatives considered | Temporary - archived after merge |
openspec/changes/<id>/tasks.md | Implementation breakdown for the agent | Temporary - archived after merge |
openspec/changes/<id>/specs/<name>/spec.md | Spec delta exact lines being added or removed | Temporary - folded into source-of-truth on archive |
The validator checks that every change folder contains all four required files and that spec deltas use the correct +/- line marker format. Missing files or malformed deltas are flagged before apply runs.
Start with default. You can change the schema later in openspec/config.yaml. Switch only when the team has run several full cycles and has a specific reason to expand.
# openspec/config.yaml
schema: defaultSchemas and what each one adds are documented in full at intent-driven-dev/openspec-schemas. Run
openspec schema validateto check that your project's artifacts match the active schema.
Core Concepts
Reference: openspec.dev Official documentation, getting started, and command reference
| Concept | What it is |
|---|---|
| Spec | A markdown file describing what a feature must do. Lives at openspec/specs/<name>/spec.md. |
| Requirement | A single observable behavior the system must guarantee, written as "The system SHALL..." |
| Scenario | A concrete example proving a requirement works, using GIVEN / WHEN / THEN structure. |
| Proposal | A package of documents describing a change to requirements before any code is written. Lives at openspec/changes/<id>/. |
| Spec Delta | The part of a proposal showing exactly which requirement lines change (a diff, but for requirements). |
| Explore | AI-assisted spec drafting /opsx:explore [description] investigates the codebase and drafts the spec grounded in real code, before any proposal is written. |
OpenSpec organizes every change through a Propose → Apply → Archive lifecycle:
| Phase | Command | What happens |
|---|---|---|
| Propose | /opsx:propose | Agent reads the source-of-truth specs and generates a proposal package: spec delta, design, tasks |
| Review intent | (manual) | Team reviews what changes and why before any code is written - this is the critical gate |
| Apply | /opsx:apply | Agent implements the change in an isolated branch, using the spec as the build target |
| Verify | /opsx:verify | Agent checks that the implementation matches the proposal artifacts; flags any drift |
| Archive | /opsx:archive | Spec delta is merged into the source-of-truth spec; the change folder is archived |
The source-of-truth spec in openspec/specs/ is the canonical record of what the system does. Spec deltas in openspec/changes/ are temporary, they exist only for the duration of a change, then get folded in on archive.
Repository Structure
OpenSpec adds two directories to your repository:
your-repo/
└── openspec/
├── specs/ ← feature specifications
│ ├── auth-session/
│ │ └── spec.md
│ ├── checkout-cart/
│ │ └── spec.md
│ └── user-profile/
│ └── spec.md
└── changes/ ← change proposals (written before code)
└── add-remember-me-sessions/
├── proposal.md
├── design.md
├── tasks.md
└── specs/
└── auth-session/
└── spec.md ← spec deltaNaming convention: spec directories use <domain>-<feature> in kebab-case. Use domain prefixes to group related specs:
| Domain prefix | Examples |
|---|---|
auth- | auth-session, auth-login, auth-password-reset |
checkout- | checkout-cart, checkout-payment, checkout-shipping |
user- | user-profile, user-notifications, user-settings |
api- | api-rate-limiting, api-versioning |
Commit both specs/ and changes/ to your repository. Specs evolve alongside code via normal PRs.
Writing a Spec
This section is for understanding. In practice you rarely write specs from scratch,
/opsx:explore [description]has an AI agent draft one for you, which you then review and edit before committing. The format below is what that output looks like, and what the agent reads when running/opsx:propose. See Using OpenSpec with AI Agents for how this fits the full workflow.
Reference: OpenSpec Documentation
The Spec Format
# Auth Session Specification
## Purpose
Users need to stay authenticated across page loads without logging in repeatedly.
Sessions must expire automatically to protect accounts on shared or unattended devices.
## Requirements
### Requirement: Session Persistence
The system SHALL maintain a user's authenticated state across page loads for the
duration of an active session.
#### Scenario: User navigates between pages
- GIVEN a user has successfully authenticated
- WHEN they navigate to a different page in the application
- THEN the system SHALL display the page in their authenticated context without
prompting for credentials
#### Scenario: Expired session rejected on navigation
- GIVEN a user's session has expired
- WHEN they attempt to navigate to a protected page
- THEN the system SHALL redirect them to the login page
- AND display a message indicating their session has expired
### Requirement: Idle Session Expiration
The system SHALL expire sessions after a configurable period of user inactivity.
#### Scenario: Session expires after idle timeout
- GIVEN a user has been authenticated and idle for longer than the configured timeout
- WHEN the idle timeout period is reached
- THEN the system SHALL invalidate the session
- AND redirect the user to the login page on their next interaction
#### Scenario: Activity resets the idle timer
- GIVEN a user has an active session
- WHEN the user performs any interaction in the application
- THEN the system SHALL reset the idle timeout counterFormat rules at a glance:
| Element | Format |
|---|---|
| File title | # [Feature Name] Specification |
| Purpose | ## Purpose 1–3 sentences explaining why this feature exists |
| Requirement heading | ### Requirement: [Name] |
| Requirement body | The system SHALL [observable behavior]. |
| Scenario heading | #### Scenario: [Name] |
| Scenario body | - GIVEN / - WHEN / - THEN / - AND |
Writing Good Requirements
Requirements describe what the system does from the outside, observable behavior, not implementation.
| ✓ Behavior - belongs in a spec | ✗ Implementation - does not belong |
|---|---|
| "The system SHALL expire sessions after a configurable idle timeout." | "The system SHALL use Redis TTL to expire sessions." |
| "The system SHALL return an error for files over 10 MB." | "The system SHALL use multipart chunking for large files." |
| "The system SHALL maintain cart contents across page reloads." | "The system SHALL store cart state in localStorage." |
Use SHALL non-negotiable, not optional. One behavior per requirement; if you need "and", split it into two.
Writing Good Scenarios
Each scenario proves a requirement can pass or fail:
| Keyword | Role |
|---|---|
| GIVEN | Starting state - who is the user, what state is the system in? |
| WHEN | One triggering event (if you need two, write two scenarios) |
| THEN | Observable result - what does the user see or the system guarantee? |
| AND | Additional results from the same WHEN |
Always include at least one failure or edge case per requirement, because happy-path-only specs leave agents without guidance where it matters most.
Before you commit: review the spec
Before committing a new spec, run /openspec-review(available in the current repository, for how to add it see the Skill Brief) in OpenCode/Copilot/ Claude Code. It checks that every requirement is independently testable, flags any requirement that describes implementation rather than behavior, and identifies missing failure scenarios, returning findings as Critical / Important / Suggestions with an offer to apply fixes directly.
This is especially useful when you are new to writing requirements: the review catches the most common mistakes (vague SHALL statements, bundled behaviors, happy-path-only scenarios) before the spec becomes source of truth.
Proposing Changes
When requirements need to change, write a proposal first. A proposal documents what is changing and why before any code is touched, letting your team review the decision, not just the implementation.
The Proposal Package
These files are generated by
/opsx:propose. The examples below are for understanding what each file contains and what to look for when reviewing and are not a template you have to fill in yourself.
openspec/changes/add-remember-me-sessions/
├── proposal.md ← what and why
├── design.md ← how it will be done
├── tasks.md ← implementation breakdown
└── specs/
└── auth-session/
└── spec.md ← spec deltaproposal.md the entry point for review:
# Proposal: Add Remember Me Sessions
## Summary
Add an opt-in persistent session lasting 30 days, allowing users to stay
authenticated across browser restarts on personal devices.
## Motivation
Users frequently re-authenticate on personal devices, creating friction for
daily users. This is the most-requested missing feature in support tickets.
## Scope
- Specs affected: auth-session
- Estimated size: mediumdesign.md technical decisions (behavior-focused, not code):
# Design: Add Remember Me Sessions
## Approach
Introduce a persistent session type that survives browser restarts. The user
opts in explicitly at login. Persistent sessions are renewed on activity.
## Alternatives Considered
- Always-on persistence: rejected for security risk on shared devices.
- Configurable duration: deferred as it adds complexity not needed for v1.
## Open Questions
- Should persistent sessions appear in a session management page?tasks.md actionable breakdown:
# Tasks: Add Remember Me Sessions
## Phase 1: Session model
- [ ] Add persistent session type
- [ ] Update session creation to accept opt-in flag
## Phase 2: Login UI
- [ ] Add "Remember me" checkbox to login form
- [ ] Pass opt-in flag on submitSpec Deltas
The specs/ folder in a proposal shows exactly which requirement lines change. Lines with no prefix are unchanged. + marks additions, - marks removals.
# Auth Session Specification
## Purpose
[unchanged]
## Requirements
### Requirement: Idle Session Expiration
- The system SHALL expire sessions after a configurable period of user inactivity.
+ The system SHALL expire sessions after a configurable idle timeout (default: 30 minutes).
+ Standard sessions are subject to idle expiration. Persistent sessions (see below) are not.
### Requirement: Remember Me
+ The system SHALL allow users to opt into a persistent 30-day session at login.
+
+ #### Scenario: User enables remember me
+ - GIVEN a user is on the login page
+ - WHEN they check "Remember me" and submit valid credentials
+ - THEN the system SHALL create a session persisting for 30 days
+ - AND maintain that session across browser restartsThis format makes it obvious what changed so that reviewers do not need to diff two versions of a spec manually.
Choosing Your Propose Command
Two approaches can create a proposal. Which to use depends on how much control you need over artifact generation:
| Approach | Commands | What it does | When to use |
|---|---|---|---|
| Core | /opsx:propose | Generates the full proposal package (proposal.md, design.md, tasks.md, spec delta) in one step | Default for most work; fastest end-to-end path |
| Extended | /opsx:new → /opsx:continue → /opsx:ff | Initializes a scaffold, then creates artifacts one at a time or fast-forwards through remaining ones | Complex or high-stakes changes where you want to inspect and adjust each artifact before the agent moves to the next |
Default to /opsx:propose. It produces the full review package in one step. It is the fastest end-to-end path and the command the core workflow is built around.
Use the extended approach (/opsx:new + /opsx:continue) when the change is complex enough that you want to read and refine the design.md or tasks.md before generation continues. Use /opsx:ff to finish any remaining artifacts once you are satisfied with the direction.
Greenfield vs Brownfield
Greenfield means starting a new project from scratch with no existing code, so specs can be written before any implementation begins. Brownfield means adopting OpenSpec on a codebase that already exists, where behavior and constraints are already baked into the code rather than written down anywhere. If you are on an existing project proposal-first is the better fit as it requires no upfront complete spec coverage and pays off immediately on the next change.
Greenfield - spec-first, new project
Write specs before writing code. The spec becomes the source of truth the AI agent builds against.
Recommended flow:
- For each feature, write a spec in
openspec/specs/<name>/spec.md- Not sure how to structure it? Run
/opsx:explore [description]first so that the agent drafts a spec from your description, which you then review and edit before committing - Already know what the feature must do? Write the spec directly and skip explore
- Not sure how to structure it? Run
- Commit the spec
- Run
/opsx:propose [description]to generate the proposal package against the committed spec - Review code against the spec, not just against your mental model
Start with the most foundational features: think auth, core data models, primary user flows. You do not need specs for everything on day one.
Brownfield - existing code, adopting later
Existing systems have undocumented constraints and decisions baked into the code. Agents working without that context silently re-open settled choices. Don't try to spec the whole system, but rather spec the area you're about to change, then enforce proposals from that point on.
| Phase | What to do |
|---|---|
| Explore | Run /opsx:explore on the target area and share the relevant source files with your AI agent so the spec reflects actual behavior, not a hallucination |
| Review | Validate the output with someone who knows the code so that gaps reveal undocumented behavior or bugs |
| Continue | Write the spec for current behavior, enforce proposals for all future changes, repeat for the next area |
Two rules for brownfield specs:
- Document what the system does, not what you wish it did as aspirational specs mislead the agent
- If the code is buggy, the spec reflects the bug, think of fixing it as a separate proposal
Architectural Decision Records (ADRs) (optional)
Once your team is comfortable with specs and proposals, ADRs let you capture why architectural decisions were made, and in doing so, preserve reasoning that would otherwise disappear when design.md is archived. See the companion guide: OpenSpec ADRs.
Parallel Feature Development
Advanced. This section assumes you are comfortable with git worktrees and multi-agent workflows. If you are new to OpenSpec, skip this section and return once the core Propose → Apply → Archive cycle feels natural.
Reference: OpenSpec, Git WorkTrees and OpenCode - Full walkthrough of the parallel development workflow
OpenSpec supports parallel feature development through Git WorkTrees combined with SubAgents. Each proposal runs in its own isolated branch; multiple proposals can be applied simultaneously without interference.
The rule is: propose on main → apply inside worktrees → merge → archive.
Why proposals must be created on main before branching:
OpenSpec's proposal step reads the source-of-truth specs to detect conflicts and gaps between the proposed change and what already exists. If you propose inside a worktree, you miss changes from sibling branches. Creating all proposals on main first ensures each agent gets a consistent view of the current state before it starts implementing.
How it works in practice:
| Step | Where | What |
|---|---|---|
| 1. Create proposal A | main | /opsx:propose [description-A] |
| 2. Create proposal B | main | /opsx:propose [description-B] |
| 3. Apply A in isolation | Worktree branch feat/A | SubAgent implements against spec |
| 4. Apply B in isolation | Worktree branch feat/B | SubAgent implements against spec |
| 5. Verify A | Worktree feat/A | Check implementation matches proposal |
| 6. Verify B | Worktree feat/B | Check implementation matches proposal |
| 7. Merge A, then B | main | Normal PR flow |
| 8. Archive | main | Delta specs merged into source-of-truth |
Commit discipline: Commit at every logical boundary: after proposal creation, after each artifact, after implementation, after archive. WorkTree branches can be discarded and recreated from the proposal on main; frequent commits on main protect against losing proposal state.
WorkTrees share the same git object store so there is no repository duplication. The isolation is branch-level, not filesystem-level.
Using OpenSpec with AI Agents
Reference: openspec.dev - Full CLI reference and command documentation
Once specs are committed, AI agents reference them automatically via /opsx:* slash commands. The core commands, in the order you will use them:
| Phase | Command | Purpose |
|---|---|---|
| Setup | /opsx:onboard | Guided 15-minute setup walkthrough - run this first on a new project |
| Explore | /opsx:explore | AI investigates the codebase and drafts the spec before any proposal is written |
| Propose | /opsx:propose | Generate the full proposal package in one go - the core propose command |
| Implement | /opsx:apply | Implement the change in an isolated branch against the spec |
| Finish | /opsx:sync | Merge delta specs into source-of-truth specs without archiving the change |
| Finish | /opsx:archive | Merge spec delta into source-of-truth and close the change |
| (extended) | /opsx:new | Initialize a change scaffold - starting point for step-by-step artifact creation |
| (extended) | /opsx:continue | Create the next artifact in dependency order |
| (extended) | /opsx:ff | Fast-forward through all remaining proposal artifacts at once |
| (extended) | /opsx:verify | Validate implementation against specifications - checks completeness, correctness, and coherence |
| (extended) | /opsx:bulk-archive | Archive multiple completed changes at once |
For the Propose phase: use
/opsx:proposeto generate everything at once (core workflow). For step-by-step control, use the extended approach:/opsx:newto initialize,/opsx:continueto build artifacts one at a time, or/opsx:ffto fast-forward through remaining ones.
Example workflow:
# 1. Investigate the codebase and draft a spec
/opsx:explore Add remember-me checkbox with 30-day sessions
# 2. Generate the full proposal package (spec delta, design, tasks)
/opsx:propose
# 3. Review proposal.md and the spec delta with your team
# This is the critical gate must agree on intent before any code is written
# 4. Implement the change in an isolated branch against the spec
/opsx:apply
# 5. Verify the implementation matches the proposal
/opsx:verify
# 6. Merge spec delta into source-of-truth and close the change
/opsx:archiveSupported tools (v1.3.1): Claude Code, Cursor, GitHub Copilot, Windsurf, Gemini CLI, Amazon Q, Kiro, Junie, Cline, RooCode, and 30+ others. All use native slash commands.
Tips and Pitfalls
Do
- Start with the features your agent touches most adopting OpenSpec incrementally, beginning with high-traffic areas, gives the fastest return on investment without requiring you to spec everything upfront.
- Commit specs alongside code in the same PR specs that live in a wiki or separate repo drift out of sync within weeks. Co-location in git keeps them honest.
- Review spec deltas the same way you review code the proposal review is where misalignment surfaces cheaply. Treat it as seriously as a PR review.
- Push for at least one failure scenario per requirement the edge cases you write scenarios for are the ones your agent will handle correctly. Everything else is a guess.
- In brownfield, document current behavior first even if it's wrong. Accurately capturing what the system does makes it safe to reason about what to change.
- If using ADRs, write them for constraints that look arbitrary if a spec has a requirement that seems odd or unnecessarily restrictive, an ADR explaining the reason prevents agents (and future devs) from "cleaning it up" and breaking something.
Avoid
- Writing requirements that describe implementation "The system SHALL use Redis TTL to expire sessions" makes your spec stale the moment you switch caching libraries. Describe the observable behavior instead.
- Bundling multiple behaviors in one SHALL statement if you need "and", split it into two requirements. Each requirement should be independently testable and changeable.
- Vague SHALL statements "The system SHALL handle it properly" passes by default because it cannot be falsified. Make it specific: "The system SHALL return a 401 response for requests with expired session tokens."
- Writing aspirational specs in brownfield projects documenting what you wish the system did misleads the agent about what the code actually does. Capture reality first, then propose changes.
- Skipping proposals for "small" changes the discipline of writing a proposal before touching code pays off most on changes that seem simple but turn out to have edge cases. The proposal takes five minutes; undoing a wrong implementation takes longer.
- Nesting requirements inside fenced code blocks OpenSpec's validator will detect and flag them. Keep all
The system SHALLstatements as plain text, never inside code fences.
References
OpenSpec
- openspec.dev Official documentation and command reference
- Fission-AI/OpenSpec Source code, issues, and community contributions
Intent-Driven Development
- intent-driven.dev/knowledge/openspec Workflow deep-dives, diagrams, video tutorials, and blog posts
Related AI Labs Guides
- OpenSpec ADRs Companion guide for capturing architectural decisions alongside specs
- OpenCode Training OpenCode agents, skills, and the WorkTree-based parallel workflow used in this guide
- Claude Code Training Claude Code sessions, memory, and skills