What is OpenSpec? The specs-before-code workflow

OpenSpec turns every change into a written proposal you approve before coding. What it is, how propose, apply and archive work, and when it pays off.

What is OpenSpec? The specs-before-code workflow

OpenSpec is a spec-driven development tool that turns every change into a written proposal inside your repository and stops the agent until you approve it. If you have seen the name in a repo and it was not clear what it adds over writing your agent a long prompt, the short answer is that OpenSpec is not a document format, it is a state cycle for your changes. Here is how that cycle works from the inside, what files it leaves in your project, and when the ceremony is worth it.

How does the propose → apply → archive cycle work?

You use OpenSpec almost entirely from your agent’s chat, not from the terminal. The terminal shows up twice, once to install and once to initialise:

# Requires Node.js 20.19.0 or higher
npm install -g @fission-ai/openspec@latest
cd your-project
openspec init

From there you live in slash commands inside the assistant. The default profile, which the docs call core, ships six of them: propose, explore, apply, update, sync and archive [1].

/opsx:explore is the optional step out front. You describe an idea that is still fuzzy, it reads your code, compares options and sharpens the plan without committing you to anything. When the conversation settles, it offers to turn it into a change.

/opsx:propose add-dark-mode is where the formal part starts. The agent creates the change folder and writes four artifacts: proposal.md with the why and the what changes, the specs with requirements and scenarios, design.md with the technical approach, and a tasks.md that is a checkbox to-do list. And then it stops. That stopping point is the whole mechanism of OpenSpec: you read the plan before the code exists.

/opsx:apply implements the tasks in tasks.md and ticks the boxes off. /opsx:archive closes the change: it validates, merges the change’s delta specs into the main specs, and moves the folder to the archive one with the date in front, something like openspec/changes/archive/2025-01-23-add-dark-mode/ [4]. There is also /opsx:sync, which does that merge on its own, but the docs mark it optional because archive offers it when needed [1].

The canonical name is /opsx:propose, but each tool spells it according to how it loads the file OpenSpec leaves it: in Cursor it is /opsx-propose, in Amazon Q you invoke it with an at sign, and in Codex it is $openspec-propose [3]. openspec init prints the right form for whichever tools you picked.

What OpenSpec writes into your repo

Everything OpenSpec produces is Markdown inside an openspec/ folder at the root of your project, so all of it goes into git like any other file [5]:

openspec/
├── specs/              # what the system does today
│   └── <domain>/
│       └── spec.md
├── changes/            # proposed changes
│   └── <change-name>/
│       ├── proposal.md
│       ├── design.md
│       ├── tasks.md
│       └── specs/      # delta specs
│           └── <domain>/
│               └── spec.md
└── config.yaml         # project configuration (optional)

That separation between specs/ and changes/<name>/specs/ is the part that costs the most at first and pays the most afterwards. specs/ holds what the system does today. Inside a change lives only the delta, that is, which requirements get added, which get modified and which disappear. On archive, the delta merges into the main spec and the history stays in changes/archive/.

Specs have no syntax of their own to learn, they are Markdown with a heading convention. A requirement is written like this [2]:

## ADDED Requirements

### Requirement: Theme selection
The app SHALL let users switch between light and dark themes,
defaulting to the system preference.

#### Scenario: User toggles dark mode
- **WHEN** the user clicks the theme toggle
- **THEN** the app switches to dark mode and persists the choice

Requirement as a SHALL, scenario as a when and a then. Nothing else. It is rigid enough for a tool to validate and plain enough to read in a pull request review without opening anything special.

Beyond the folders, openspec init configures your assistant. For Claude Code it drops the instructions in .claude/skills/openspec-*/SKILL.md and the commands in .claude/commands/opsx/<id>.md; every tool has its equivalent path, and the full table lists fifty-one today [3]. If you update the global package, openspec update regenerates those files inside each project.

How it differs from just asking for the change in chat

The difference is where the plan lives and when it gets approved, not what it says. A well-written long prompt can describe the same change as a proposal.md, but it dies with the session, nobody reviews it, nothing versions it, and no one can compare it against what the agent actually did.

Long prompt in chatChange in OpenSpec
Where the agreement livesIn the conversation historyIn openspec/changes/<name>/, inside the repo
When you review itWhile the agent is already writing codeBefore, /opsx:propose stops and waits
What is left afterwardsNothing, other than the diffThe updated specs plus the dated archived change
Who else sees itYouAnyone who opens the pull request, human or agent
Machine-checkableNoYes, with openspec validate

That last row is what turns the ritual into something more than personal discipline. openspec validate checks that changes and specs are well formed, and it also cross-checks requirements marked MODIFIED against the main specs they are going to replace [4]. It has one detail that gives away a tool used on real projects: a change with no delta specs fails validation, unless its .openspec.yaml declares skip_specs: true, which is meant for refactors or tooling work that does not change behaviour.

And there is a mode worth putting in a pre-commit hook: openspec validate --archived walks the changes in changes/archive/ and fails if any of them was archived with tasks.md boxes left unticked [4].

When it pays off and when it gets in the way

In the content pipeline behind this site every generation phase has a written contract before it runs, and that is where my take comes from. The ceremony pays off when the cost of the agent building the wrong thing outweighs the cost of writing the plan. That happens sooner than you would think, as soon as the change touches more than one file or more than one person. Deciding where to put that contract and what goes inside it is one of the things you practise with exercises in the Design Patterns for AI Agents course.

It pays off when the change crosses modules and you want the agreement to outlive the session. It pays off a lot in brownfield, because the specs under openspec/specs/ end up being the description of what the system does today, which is exactly what an agent lacks when it lands in an old repository. And it pays off in a team, where the proposal gets discussed in the pull request before anyone has burned tokens implementing it.

It gets in the way when the change is a two-line fix, or when the project is an experiment you are throwing away on Friday. There the artifact folder is noise. That is what /opsx:explore is for, since it creates nothing until you ask.

There is one cost the docs do not hide and it is worth keeping in mind: OpenSpec works best with high-reasoning models and a clean context window, and the README itself recommends clearing the context before you start implementing [2]. If your agent reaches /opsx:apply with the conversation full of the earlier exploration, the written plan does it little good.

If what you are deciding is which spec framework to adopt rather than whether to adopt one, the comparison is in how OpenSpec compares with Spec Kit and BMAD. And if the underlying concept still sounds like a buzzword, start with what spec-driven development is, which explains the idea without tying it to any tool.

Sources

  1. OpenSpec — Commands — the exact names of the core profile commands and the expanded profile, and how each is activated.
  2. OpenSpec — README — installation, minimum Node version, the full cycle example, the spec format and the note on context hygiene.
  3. OpenSpec — Supported Tools — the paths it writes for each assistant and the different ways to invoke the commands.
  4. OpenSpec — CLI — reference for validate and archive with their options.
  5. OpenSpec — Getting Started — the directory structure openspec init creates and a description of a change’s lifecycle.
  6. openspec.dev — the project’s official site and how it presents itself.

Frequently Asked Questions

What is OpenSpec in one sentence?

OpenSpec is a spec-driven development tool for coding assistants that turns every change into a Markdown folder inside your repository, holding the proposal, the requirements, the design and the tasks, and stops the agent at that point so you approve the plan before it writes any code.

What is “openspec dev”?

It is the project’s official site, openspec.dev, which presents itself as a lightweight, configurable spec framework and says it helps teams and coding agents create, refine and manage living specifications [6]. The code lives on GitHub under the Fission-AI organization, which describes it as spec-driven development for AI coding assistants [2], and it ships on npm as @fission-ai/openspec under the MIT licence.

Does it work with Claude Code?

Yes. openspec init leaves it this, and you invoke the commands as they are, /opsx:propose [3]:

.claude/skills/openspec-*/SKILL.md
.claude/commands/opsx/<id>.md

Do I need OpenSpec to do spec-driven development?

No. You can write the spec by hand in a Markdown file and ask the agent to follow it, and for a small project that works. What OpenSpec adds is the boring part: the fixed place to put it, the delta kept separate from the current state, the dated archive, and a validator that catches a malformed change or one you archived with tasks still unticked.

Is it the same as Spec Kit?

No. OpenSpec’s own README compares itself with Spec Kit and positions itself as the lighter of the two [2]. The comparison in detail, BMAD included, is in the analysis of the three frameworks.