Home
Blog
Tools

Introduction to Spec-Driven AI Development with OpenSpec

OpenSpec turns your codebase into a living spec AI agents actually use. My take on why spec-driven development is the right way to work with AI — and where it costs you.

“Always design a thing by considering it in its next larger context.”

— Eliel Saarinen

AI coding assistants are powerful. But they suffer from a fundamental problem: they have no long-term memory of your project. Every new chat, you describe your stack, your conventions, your constraints — again. The AI makes decisions without understanding the full picture, produces code that technically works but doesn’t fit, and confidently ignores architectural decisions you spent days making.

OpenSpec is the answer I’ve been looking for.

This is my honest take: spec-driven development with OpenSpec is the right way to work with AI on a codebase. It’s not perfect, and it costs you something — but the upside is real.

What is OpenSpec?

OpenSpec is a lightweight, spec-driven framework that lives inside your repository. Instead of describing your project to an AI agent at the start of every session, you maintain living specifications that the agent reads before doing anything.

These specs are plain Markdown files, versioned with your code, organized by capability. Every major change starts with a proposal that gets reviewed before a single line of code is written. When implementation is done, the spec is updated and archived — keeping the living spec accurate and trustworthy over time.

It works with Claude Code, Cursor, GitHub Copilot, Codex, Windsurf, Gemini CLI, and 16+ other tools out of the box.

Install it once globally:

npm install -g @fission-ai/openspec@latest

Then initialize it inside any project:

cd your-project
openspec init

Why Clean Context is Everything

The single biggest factor in AI code quality is context quality. Not the model version, not the prompt length — the context.

When an AI agent has a clear, accurate specification of what your system is and how it behaves, the answers become significantly more precise. It stops guessing your stack. It stops suggesting patterns that conflict with the ones you already use. It understands the why behind existing decisions.

This is especially visible in explore mode — when you’re asking questions and investigating before making changes. With OpenSpec specs loaded, the responses are in a different league. The AI already knows your architecture, your conventions, your edge cases. The back-and-forth shortens dramatically.

Without specs, you’re giving the AI a compiled binary and asking it to reverse-engineer intent. With specs, you’re handing over the source and the design doc.

The Workflow

OpenSpec structures work into five phases. They don’t all apply to every change, but together they form a loop that keeps specs and code in sync.

OpenSpec workflow: Explore → Propose → Apply → Sync → Archive

1. Explore

Before changing anything in an unfamiliar codebase — or when picking up a feature after weeks away — explore mode helps you build a working mental model. You’re not writing code yet. You’re reading specs, asking questions, understanding how pieces connect.

This is where the precision difference shows most clearly. The AI works from spec context rather than scanning raw code, so its answers are grounded in intent, not just what the files happen to look like right now.

/opsx:explore "How does the authentication flow connect to session management?"

The command loads your full spec context and puts the AI into investigation mode — focused on understanding and answering, not proposing changes.

2. Propose

Once you know what you want to change, you create a proposal:

/opsx:propose "Add dark mode support with user preference persistence"

OpenSpec reads your existing specs and generates a structured change folder:

openspec/changes/dark-mode-support/
├── proposal.md     ← rationale and scope
├── specs/          ← requirements and scenarios
├── design.md       ← technical approach and decisions
└── tasks.md        ← concrete implementation checklist

You review this before any code is written. This is where you catch misalignment early — not after a 200-line diff lands in review. The proposal phase forces clarity about what is changing, what isn’t, and why.

3. Apply

With the proposal approved, you hand the tasks over:

/opsx:apply

The AI implements the tasks from tasks.md with the full spec context loaded. Because the design is already documented, it makes fewer wrong turns and asks fewer clarifying questions. It knows what you mean by “user preference persistence” — because the design doc says so.

4. Sync

After implementation, you verify that the specs reflect what was actually built. Sometimes the implementation diverges from the proposal — a dependency changes, a simpler approach emerges. Sync is the step where you acknowledge that delta explicitly, keeping the source of truth honest.

This step is what stops specs from decaying. Without it, specs drift from reality and stop being useful.

/opsx:sync

The command merges the delta specs from your change folder back into the main specifications, keeping the source of truth honest and up to date.

5. Archive

Done. The change folder gets archived, the source-of-truth spec gets updated, and you have a clean record of what was proposed, what was built, and what changed in the spec.

/opsx:archive

The archive isn’t waste — it’s your project’s decision log. Why did we drop server-side session storage? Check the archive. What did the dark mode spec look like before we added OS-level detection? It’s there.

Getting Started: openspec/config.yml

After openspec init, the most important step is configuring openspec/config.yml with your project context. This is what every AI agent reads before it does anything. Get it right and you never explain your stack again.

Here’s what the config looks like for this very site — danielraab.at:

schema: spec-driven

context: |
  This is danielraab.at — the personal website and blog of Daniel Raab.

  Tech stack:
  - Astro 6 static site with TypeScript
  - React islands (client:load) for interactive tool components
  - Tailwind CSS v4 via @tailwindcss/vite plugin (no tailwind.config file)
  - Biome for linting and formatting
  - pnpm as the package manager (Node >=22.12.0)
  - Deployed automatically to danielraab.at via FTP on push to master

  Project structure:
  - src/pages/ — file-based routing; blog posts use [code].astro dynamic routes
  - src/content/blog/ — Markdown blog posts via Astro Content Collections
  - src/content.config.ts — blog schema with Zod; `code` field is the URL slug
  - src/pages/tools/ — interactive tools with co-located CSS Modules
  - src/data/tools.ts — tool metadata registry (title, description, icon, href)
  - src/pages/og/[code].png.ts — OG image generation at build time via Satori + Resvg

  Conventions:
  - Formatting: 4-space indent, single quotes, 120-char line width (Biome-enforced)
  - Run `pnpm check` (Biome + astro check) before every commit
  - Blog posts are written in first-person, opinionated, practical Markdown
  - New tools must be registered in src/data/tools.ts to appear in navigation

rules:
  proposal:
    - Keep each proposal scoped to one capability or blog post
    - Reference existing components before proposing new abstractions
    - Consider OG image generation impact for any content schema changes
  specs:
    - Use the blog frontmatter schema exactly as defined in src/content.config.ts
    - Note Astro island hydration strategy (client:load vs client:visible) explicitly

The context block is injected into every AI prompt. The rules block constrains what the AI produces per artifact type. Between these two, you encode the things you’d otherwise explain in every session.

The key insight is that the more specific you are, the better the output. Saying “Astro 6 with TypeScript” is better than “JavaScript framework.” Saying “4-space indent, single quotes, enforced by Biome” means the AI never formats code wrong in a proposal.

My Experience

The quality of specs in a codebase lives or dies by their actuality. Outdated specs are worse than no specs — they mislead. The reason most spec efforts fail is the maintenance cost: keeping docs current alongside code is friction enough that people stop doing it.

This is where OpenSpec’s loop changes things. Because every proposed change starts with updating the spec, and every completed change archives to the source of truth, the maintenance happens naturally as part of the workflow. You’re not maintaining docs as a separate task — you’re refining specs as part of implementation.

AI lowers that effort further. Generating a proposal from a description costs a few seconds and a few tokens. Updating the archive at the end of a feature costs roughly the same. What used to be a documentation sprint at the end of a quarter becomes a background cost of each change cycle.

The result: specs stay current, context stays clean, and AI assistance stays precise. That flywheel is the real value.

When to Use It

This is the honest part.

Definitely use it for:

  • Starting a new project — initialize with OpenSpec from day one, not as a retrofit
  • Large features that touch multiple parts of the system
  • Architectural changes where you need a design record
  • Onboarding a new team member or AI agent to an existing codebase (explore mode)

Probably worth it for:

  • Medium-sized features with non-obvious design decisions
  • Anything where you’d otherwise write a PR description longer than five lines

Questionable value for:

  • Small, isolated bug fixes with a clear cause and minimal scope
  • Trivial changes (copy, config tweaks, dependency bumps)

Probably skip for:

  • Hotfixes where you need to ship in 10 minutes
  • Changes so small that writing the proposal takes longer than the fix

The honest answer to “should I create a spec for this?” is usually: if you’d write more than a paragraph explaining it in a PR, OpenSpec is worth the overhead. If it’s a one-liner, it isn’t.

The Tradeoffs

No honest review skips the costs.

Time. Creating a good proposal takes time. Reviewing it takes time. Archiving takes time. For a developer used to jumping straight to code, this feels slow at first. The payoff comes later — in faster implementation, fewer wrong turns, and onboarding that doesn’t require a week of knowledge transfer. Future you benefits. Present you pays.

Tokens. Generating proposals, loading spec context, running archive summaries — all of this costs tokens. On a project where every small change gets a formal proposal, the token cost adds up quickly. At scale, with many small features per sprint, this becomes a real budget consideration. The tradeoff is most favorable for features where the design complexity justifies the proposal overhead.

Discipline. OpenSpec doesn’t enforce its own workflow. If the team stops archiving, specs drift. If proposals get skipped for “quick changes,” the source of truth decays. The framework only works if the loop is respected consistently.


Despite those costs, I think this is the right direction. AI assistance is only as good as the context it operates on, and OpenSpec is the most practical approach I’ve seen for maintaining that context without turning documentation into a full-time job.

The explore → propose → apply → sync → archive loop isn’t overhead. It’s the discipline that makes AI collaboration sustainable at the feature level, not just the line-of-code level.

More at openspec.dev and intent-driven.dev/knowledge/openspec.