A hands-on workshop demonstrating Spec-Driven Development (SDD) using OpenSpec and an AI-enabled IDE (Devin). Participants build a Bug Tracker app feature-by-feature using a propose → review → apply → verify → archive cycle.
A minimal Bug Tracker web application with:
- Create Bug — form with title, description, and optional severity
- List Bugs — sortable table showing all bugs newest-first
- Triage Bug — set severity and transition status from
New→Triaged
| Layer | Technology |
|---|---|
| Frontend | React + TypeScript + Vite + Tailwind CSS |
| Backend | Node.js + Express + TypeScript |
| Storage | In-memory (no database) |
| Tests | Vitest + React Testing Library + Supertest |
- Node.js v18+ installed
- Devin (or another AI-enabled IDE)
- Clone the Workshop repository:
git clone https://github.com/improving/ai-sdd-openspec-workshop
- Install the OpenSpec CLI globally:
npm install -g @fission-ai/openspec@latest
- Open
initial-prompt.md— the product requirements for the Bug Tracker app.
Follow along with the instructor for this section.
In a PowerShell terminal at the repo root, run:
openspec initThis scaffolds the openspec/ directory structure and skills/workflows used by all subsequent commands.
Open the openspec/config.yaml file and replace its contents with the following:
schema: spec-driven
model: SWE 1.7
context: |
Domain: Bug Tracker web application — a demo POC for a workshop teaching Spec-Driven Development (SDD) using OpenSpec.
Tech stack:
- Frontend: React + TypeScript (Vite) + Tailwind CSS
- Backend: Node.js + Express + TypeScript
- Storage: in-memory only (no database)
- Tests: Vitest + Supertest for API tests
- Dev runtime: frontend and backend run together via a single `npm run dev` command
TDD discipline (non-negotiable):
- Follow Red–Green–Refactor strictly.
- For every behavior in the specs, write failing tests FIRST, then implement.
Project conventions:
- UI: one create form and one list view, minimal Tailwind styling, no extra dependencies.
- Tests: backend endpoint tests with Supertest and frontend component tests with React Testing Library; run with `npm run test`.
rules:
default:
tasks:
- "Group tasks under `## N. Group Name` headings."
- "Every task must be a checkbox in the form `- [ ] N.M Task description`."
- "Each task must be small, focused, reference the relevant spec scenario, and sequence: tests → implementation → refactor."
- "Check off tasks as you complete them one-by-one or a section at a time."
swe-1.7:
propose:
- "If you are running on model SWE 1.7 do not add 'npm run dev' to the task list."
apply:
- "SWE 1.7: do not run 'npm run dev' during the apply phase."
- "SWE 1.7: prefer small, focused diffs; keep each implementation change under ~30 lines when possible."
archive:
- "SWE 1.7: verify the spec and implementation are complete and aligned before archiving."
tasks:
- "SWE 1.7: keep tasks concrete and avoid multi-file refactors in a single step."
The swe-1.7 rules are specifically tuned for the SWE 1.7 model, which is significantly cheaper than other models. The goal is to add precision and guardrails so the cheaper model stays reliable in this lab:
- No
npm run devin proposals and nonpm run devduring apply — prevents the Cascade window from hanging. - Small, focused diffs (~30 lines max per change) — keeps each apply step minimal, reducing the amount of code and reasoning the model must handle at once.
- Concrete tasks, no multi-file refactors — avoids the broad, sweeping rewrites that consume large context windows and can trigger rework.
- Verify before archiving — ensures a single clean completion step rather than repeated back-and-forth corrections.
Open a new Devin Cascade Session to start with a fresh context window.
In the Cascade chat panel, type the following slash command:
/opsx-propose @initial-prompt.md create-bug feature only, include greenfield scaffolding
Cascade will generate the following artifacts inside openspec/changes/create-bug/:
| File | Purpose |
|---|---|
proposal.md |
High-level change summary and goals |
design.md |
Technical design decisions |
spec.md |
Given/When/Then acceptance criteria |
tasks.md |
Ordered, TDD-sequenced task list |
Open and read each generated file. Discuss with the class:
- Does the spec match the requirements in
initial-prompt.md? - Are the acceptance criteria clear and testable?
- Does the task list follow Red–Green–Refactor order?
Request any changes from Cascade before moving on.
Open a new Devin Cascade Session to start with a fresh context window.
Once satisfied with the artifacts, run in Cascade:
/opsx-apply create-bug
Cascade will implement the feature — writing failing tests first, then making them pass, following the task list in tasks.md.
- Install dependencies and start the dev servers:
npm install npm run dev
- Open the app in your browser and demo the Create Bug feature.
- Run the test suite to confirm all tests pass:
npm test
- Discuss with the class: What did Cascade do well? What would you change?
Open a new Devin Cascade Session to start with a fresh context window.
When the feature is complete and verified, archive it in Cascade:
/opsx-archive create-bug
This moves the artifacts to openspec/changes/archive/ to keep the workspace clean.
Split into small groups (2–3 people). Each group will complete the remaining features independently, following the same propose → review → apply → demo → archive cycle.
Step 1 — Propose
Open a new Devin Cascade Session to start with a fresh context window.
/opsx-propose @initial-prompt.md list-bugs feature only
Step 2 — Review the generated artifacts in openspec/changes/list-bugs/. Verify the spec covers:
- Bugs displayed sorted newest-first.
- Title truncated to 50 chars with
…. - Severity shown as "Untriaged" when not set.
Step 3 — Apply
Open a new Devin Cascade Session to start with a fresh context window.
/opsx-apply list-bugs
Step 4 — Verify and Demo
npm test
npm run devOpen the browser and confirm the bug list renders correctly.
Step 5 — Archive
Open a new Devin Cascade Session to start with a fresh context window.
/opsx-archive list-bugs
Step 1 — Propose
Open a new Devin Cascade Session to start with a fresh context window.
/opsx-propose @initial-prompt.md triage-bug feature only
Step 2 — Review the generated artifacts in openspec/changes/triage-bug/. Verify the spec covers:
- Triage sets Severity (P1/P2/P3) and transitions Status from
New→Triaged. - Once
Triaged, Severity cannot be changed (error returned).
Step 3 — Apply
Open a new Devin Cascade Session to start with a fresh context window.
/opsx-apply triage-bug
Step 4 — Verify and Demo
npm test
npm run devOpen the browser and demonstrate the triage workflow end-to-end.
Step 5 — Archive
Open a new Devin Cascade Session to start with a fresh context window.
/opsx-archive triage-bug
After completing the lab, discuss these questions with your group or the class:
- Vibe Coding is powerful but important context is lost in chat conversations.
- How did the OpenSpec workflow feel different from traditional coding? From Vibe Coding?
- How did having a spec before implementation change the way code was written?
- Where do you see OpenSpec fitting into your real-world workflow?
| Command | Purpose |
|---|---|
/opsx:explore |
Think through ideas before committing to a change |
/opsx:propose |
Create a change and generate planning artifacts in one step |
/opsx:apply |
Implement tasks from the change |
/opsx:archive |
Archive a completed change |
| Command | Purpose |
|---|---|
/opsx:new |
Start a new change scaffold |
/opsx:continue |
Create the next artifact based on dependencies |
/opsx:ff |
Fast-forward: create all planning artifacts at once |
/opsx:verify |
Validate implementation matches artifacts |
/opsx:sync |
Merge delta specs into main specs |
/opsx:bulk-archive |
Archive multiple changes at once |
/opsx:onboard |
Guided tutorial through the complete workflow |
It is recommended to open a new Devin Cascade Session before running each agent command (/opsx-propose, /opsx-apply, /opsx-archive, etc.). Here's why:
- Context Window Management: Each Cascade session starts with a clean context window, preventing token accumulation from previous conversations that could limit the AI's ability to reason about the current task.
- Reduced Hallucination: A fresh context reduces the risk of the AI referencing or conflating details from prior features or changes.
- Clearer Focus: Each session is dedicated to a single feature or change, making it easier to track what the AI is working on and verify correctness.
- Better Artifact Quality: With a focused context, the generated specs, designs, and task lists are more precise and less likely to contain cross-feature contamination.
This practice is especially important in a workshop setting where multiple features are being developed in sequence.
A common objection to TDD in agentic development: "The agent writes both the tests and the code, so why not let it write the code first and the tests second? It uses fewer tokens."
Tests-Second (the pushback)
- Slightly lower token cost on the happy path.
- Tests are written with the implementation in view — they describe what the code does, not what the spec demanded.
- The agent has no objective oracle during implementation, so drift from the spec is harder to detect.
- One round of rework wipes out any token savings.
Tests-First (recommended)
- The first artifact produced is a machine-checkable encoding of the spec — intent drift is caught in seconds.
- Gives the agent a tight feedback loop: write → run → observe → fix, terminating cleanly when tests go green.
- Slightly higher best-case token cost, dramatically lower worst-case cost.
- Optimizes for enforceable intent, not generation efficiency.
Key Takeaway
Tests-second optimizes for tokens. Tests-first optimizes for intent. Pick which one you want to be wrong about in production. The agent will happily write tests that pass — only tests written before the code can prove the code did what the spec asked.