Setting Up OpenSpec with OpenCode: A Practical Guide
In the companion article comparing AI-assisted development methodologies, OpenSpec stood out for one reason: it is the most practical framework to adopt incrementally. You do not restructure your team or install a pipeline. You add two files and change how you write prompts.
This guide takes that claim and tests it on a real codebase — the very Next.js site you are reading this on. Every example is taken from actual work done on this project: adding articles, modifying components, and fixing issues. You can follow along and end up with a working OpenSpec setup in your own OpenCode project.
What We Are Building
By the end of this guide, you will have:
- OpenSpec installed and configured in your project
- An
openspec/changes/directory with at least one complete change artifact - A workflow that uses OpenSpec's OPSX protocol before every significant
task()delegation - An archive of decisions you can search months later
The examples are specific to OpenCode, but the workflow works with any of the 20+ tools OpenSpec supports.
Install OpenSpec
OpenSpec is an npm package. Install it globally or per-project:
npm install --save-dev @fission-ai/openspec
Or globally if you want it available across all your projects:
npm install -g @fission-ai/openspec
Create the directory structure:
mkdir -p openspec/changes openspec/archive
OpenSpec does not require a configuration file. The entire convention is directory-based: openspec/changes/ for active work, openspec/archive/ for completed changes. You can add a .openspec.json if you want to configure telemetry or custom paths, but the defaults work for most projects.
your-project/
├── openspec/
│ ├── changes/
│ │ └── add-dark-mode/
│ │ ├── proposal.md
│ │ ├── specs.md
│ │ ├── design.md
│ │ └── tasks.md
│ └── archive/
│ └── add-dark-mode/ # Moved here after completion
└── (rest of your project)
The OPSX Protocol in OpenCode
OpenSpec's OPSX (Open-Prompt Specification Exchange) protocol defines three commands. Here is how each maps to an OpenCode action:
/opsx:propose — Create the Spec
This is the most important command. Instead of telling OpenCode what to implement, you tell it to ask you questions first and produce a structured spec.
In your OpenCode chat:
You: /opsx:propose Add a dark mode toggle to the site header. The toggle
should persist the user's preference and work across page navigations.
OpenCode: I'll draft a proposal. A few questions:
1. Where should the toggle icon live? (header, sidebar, both?)
2. Should the preference be stored in localStorage or a cookie?
3. Should dark mode be the default for users who prefer it via
prefers-color-scheme?
4. Do we need a system theme option in addition to light/dark?
After you answer, OpenCode generates two files:
openspec/changes/add-dark-mode/proposal.md
# Proposal: Add Dark Mode Toggle
## Motivation
Users reading technical content at night need a dark theme to reduce eye
strain. This is a standard feature for content-heavy sites and is the most
requested UX improvement.
## Scope
Add a toggle in the site header that switches between light and dark themes.
Persist the choice in localStorage. Respect the user's system preference on
first visit.
## Key Constraints
- Must work with Tailwind CSS v4 dark mode variant
- Must not cause a flash of wrong theme on page load
- Must be accessible (keyboard operable, high contrast)
openspec/changes/add-dark-mode/specs.md
# add-dark-mode: Specs
## ADDED
- `src/components/ThemeToggle.tsx` — accessible toggle button component
- Renders sun/moon icon based on current theme
- Emits theme change event on toggle
- Keyboard operable (Enter/Space to toggle)
- `src/lib/theme.ts` — theme persistence utility
- `getTheme(): 'light' | 'dark' — reads from localStorage or system pref
- `setTheme(theme)` — writes to localStorage and updates `<html>` class
- `<script>` in `src/app/layout.tsx` — inline script to prevent flash of
wrong theme (runs before React hydrates)
## MODIFIED
- `src/app/layout.tsx` — add `<html>` class based on initial theme, wrap
app in ThemeProvider context
- `src/components/Header.tsx` — render ThemeToggle in the header bar
## REMOVED
- (none)
/opsx:apply — Implement the Spec
Once the spec is written, tell OpenCode to implement it:
You: /opsx:apply
OpenCode: Reading spec from openspec/changes/add-dark-mode/specs.md...
Implementing:
1. Created src/components/ThemeToggle.tsx — accessible toggle with
sun/moon icons, keyboard support, and ARIA labels
2. Created src/lib/theme.ts — localStorage-backed persistence with
system preference detection
3. Modified src/app/layout.tsx — added inline script for flash prevention
and theme class on <html>
4. Modified src/components/Header.tsx — added ThemeToggle to the header
bar
Verifying: checking for flash on page load... pass.
checking keyboard navigation... pass.
checking localStorage persistence... pass.
In OpenCode terms, /opsx:apply is equivalent to delegating via task() with the spec as your prompt. The difference is that the spec was written before implementation, not as part of the prompt. This separation forces you to clarify scope upfront instead of negotiating it mid-implementation.
/opsx:archive — Preserve the Decision
After you approve the implementation, archive it:
You: /opsx:archive
This moves openspec/changes/add-dark-mode/ to openspec/archive/add-dark-mode/. The proposal, spec, and design artifacts are now a permanent record. If someone asks in six months why dark mode uses a localStorage cookie instead of server-side detection, the archived proposal has the answer.
Real Example: Adding an Article to This Site
Let me walk through an OpenSpec change applied to this actual project. Here is the spec used to add the article you are reading now.
Step 1: Write the Proposal
# Proposal: OpenSpec OpenCode Workflow Guide
## Motivation
The main article compared OpenSpec, BMAD, and GSD Core. A companion piece
that shows readers how to actually set up OpenSpec with OpenCode will convert
theory into practice and increase engagement with the methodology.
## Scope
A standalone guide article at content/openspec-opencode-workflow-guide.md
with real examples from this codebase.
## Key Constraints
- Must pass npm run validate:content (frontmatter rules)
- British English spelling consistent with site style
- Same frontmatter format as other articles (title, date, description,
tags, category)
Step 2: Write the Delta Spec
# Article: OpenSpec OpenCode Workflow Guide — Specs
## ADDED
- `content/openspec-opencode-workflow-guide.md` — practical setup guide
- Minimum 800 words
- Installation instructions for @fission-ai/openspec
- OPSX protocol walkthrough with OpenCode-specific dialogue examples
- Real example using this project (article workflow)
- Team patterns and archive usage
- British English, GFM markdown, code blocks with language tags
## MODIFIED
- `content/ai-assisted-development-methodologies.md` — add "see practical
guide" reference in the OpenSpec section (optional, if editor approves)
## REMOVED
- (none)
Step 3: Apply and Archive
After implementing and verifying (npm run validate:content passes, npm run build succeeds), archive the change. The complete decision record — why the article was needed, what it covers, and where it lives — is preserved in openspec/archive/.
Extending OpenSpec for OpenCode
OpenSpec's default artifact structure supports four files. For OpenCode users, two additions are worth considering:
1. Add a review.md File
OpenCode has a review-work skill that runs multiple parallel reviews. You can add a review step to your change artifacts:
# review.md
## Momus Review
- [x] Acceptance criteria are verifiable
- [x] Scope boundaries are clear
- [x] No ambiguous language
## Oracle Review
- [x] Architecture approach is sound
- [x] No security concerns
## QA Review
- [x] Spec is implementable as written
- [x] Edge cases documented
This formalises what OpenCode's skill(name="review-work") already does, but ties it to a specific change rather than running it ad-hoc.
2. Add a tasks.md File
For complex changes, OpenCode's task decomposition can be documented alongside the spec:
# tasks.md
## Wave 1 (Independent)
- [ ] Create ThemeToggle component
- [ ] Create theme persistence utility
## Wave 2 (Depends on Wave 1)
- [ ] Integrate into Header
- [ ] Add flash-prevention script to layout
## Wave 3 (Verification)
- [ ] Verify no flash on page load
- [ ] Verify keyboard navigation
- [ ] Verify localStorage persistence
## Dependencies
- Tailwind CSS v4 dark mode variant must be enabled in tailwind.config
This maps to GSD Core's wave execution model but within OpenSpec's file structure. You get both frameworks' concepts without adopting either wholesale.
Team Patterns
OpenSpec becomes more valuable in team settings. Here are three patterns that work well when multiple people use OpenCode on the same project.
Change Ownership
Each developer works in their own change directory:
openspec/changes/
├── alice/add-pagination/
├── bob/dark-mode-toggle/
└── carol/fix-header-responsive/
No locks, no checkouts. If two changes modify the same file, the delta specs make conflicts visible before implementation starts — you can see in specs.md that both Alice and Bob want to modify Header.tsx.
Mandatory Archive Before Merge
Enforce a team rule: no PR merges without an archived OpenSpec change. The spec in openspec/archive/ serves as the code review attachment — reviewers read the proposal and spec before looking at the diff.
# Pre-merge check
if [ ! -d "openspec/archive/$(git branch --show-current)" ]; then
echo "Error: No archived OpenSpec change for this branch."
echo "Run /opsx:archive before merging."
exit 1
fi
Decision Archaeology
The archive becomes searchable over time:
# Find why a decision was made
grep -r "pagination" openspec/archive/*/proposal.md
# Find all changes that touched a file
grep -r "Header.tsx" openspec/archive/*/specs.md
# Show what was removed recently
grep -r "## REMOVED" openspec/archive/*/specs.md
This is the feature that most OpenCode users lack and do not realise they lack until they need it. OpenCode remembers nothing between sessions. The archive fills that gap with zero tooling — just flat files you can grep.
Common Pitfalls
Specs Too Vague
The most common mistake is writing specs at the wrong granularity:
# BAD — too vague
## ADDED
- Dark mode toggle
# GOOD — implementation-ready
## ADDED
- `src/components/ThemeToggle.tsx` — accessible toggle with sun/moon icons
- Props: none (self-contained)
- Keyboard: Enter/Space to toggle
- ARIA: role="switch", aria-checked reflects current theme
If a subagent could implement the spec without asking clarifying questions, the spec is specific enough. If the agent would need to ask "where should the toggle go?" or "what icon should it use?", the spec needs more detail.
Skipping /opsx:archive
The archive is what gives OpenSpec its long-term value. Skipping it because you are busy is the same failure mode as skipping documentation because you are busy — it feels fine today and causes pain six months later.
Make archiving part of your completion checklist. In OpenCode terms: before marking a todo item completed, run /opsx:archive.
Over-Engineering the Artifacts
Not every change needs all four files. A one-line bug fix might only need specs.md:
## MODIFIED
- `src/lib/content.ts` line 42 — fix off-by-one in pagination totalPages calc
OpenSpec's philosophy is "fluid not rigid". If an artifact adds no value for a given change, skip it. The framework works best when you use the minimum structure needed for clarity.
Summary
OpenSpec fills a specific gap in OpenCode: it provides a standard format for specifying work before delegating it. You can adopt it incrementally — start with just specs.md for your most complex task() delegations, add proposals for changes that involve trade-off decisions, and add the full archive once you have a few changes completed.
The delta spec format is the key insight. Writing ## ADDED / ## MODIFIED / ## REMOVED before implementation forces you to define scope boundaries that a free-form prompt leaves fuzzy. For a project like this one — a content site with frequent article additions, occasional component changes, and multiple contributors — that clarity alone justifies the overhead.
Further Reading
- OpenSpec GitHub — OPSX protocol spec and examples
- Three Methodologies Compared — The companion article positioning OpenSpec against BMAD and GSD Core
- OpenCode Documentation — Task system, subagents, skills reference
- GSD Core Wave Model — For the
tasks.mdwave decomposition pattern shown above