Skip to content

Stabilarity Hub

Menu
  • Home
  • Research
    • Healthcare & Life Sciences
      • Medical ML Diagnosis
    • Enterprise & Economics
      • AI Economics
      • Cost-Effective AI
      • Spec-Driven AI
    • Geopolitics & Strategy
      • Anticipatory Intelligence
      • Future of AI
      • Geopolitical Risk Intelligence
    • AI & Future Signals
      • Capability–Adoption Gap
      • AI Observability
      • AI Intelligence Architecture
      • AI Memory
      • Trusted Open Source
    • Data Science & Methods
      • HPF-P Framework
      • Intellectual Data Analysis
      • Reference Evaluation
    • Publications
      • External Publications
    • Robotics & Engineering
      • Open Humanoid
      • Open Starship
    • Benchmarks & Measurement
      • Universal Intelligence Benchmark
      • Shadow Economy Dynamics
      • Article Quality Science
  • Tools
    • Healthcare & Life Sciences
      • ScanLab
      • AI Data Readiness Assessment
    • Enterprise Strategy
      • AI Use Case Classifier
      • ROI Calculator
      • Risk Calculator
      • Reference Trust Analyzer
    • Portfolio & Analytics
      • HPF Portfolio Optimizer
      • Adoption Gap Monitor
      • Data Mining Method Selector
    • Geopolitics & Prediction
      • War Prediction Model
      • Ukraine Crisis Prediction
      • Gap Analyzer
      • Geopolitical Stability Dashboard
    • Technical & Observability
      • OTel AI Inspector
    • Robotics & Engineering
      • Humanoid Simulation
    • Benchmarks
      • UIB Benchmark Tool
    • Article Evaluator
    • Open Starship Simulation
    • API Gateway
  • EKIT Department
  • About
    • Contributors
  • Contact
  • Join Community
  • Terms of Service
  • Login
  • Register
Menu

Spec-Driven Development with AI Agents: A Brownfield Walkthrough

Posted on August 27, 2026August 27, 2026 by Admin
Spec-Driven AI DevelopmentAcademic Research · Article 33 of 33
By Oleh Ivchenko
ORCID
5,458 words · 0% fresh refs · 7 references

Live session for the CoffeeJUG community (August 2026) — an end-to-end walkthrough of applying spec-driven development (SDD) to an existing, undocumented codebase with OpenSpec, including a real feature built live from proposal to archive. Presented by Oleh Ivchenko, Lead Software Engineer & PhD candidate, Department of Economic Cybernetics and Information Technologies, Odesa Polytechnic National University. Written up below as a full field guide covering everything the session touched.

Contents #

  • Preface — who this is for, how to read it
  • Part I. Framing the problem — why a legacy repo only tells the truth in code
  • Part II. Spec-driven development — a short history, and what SDD means today
  • Part III. OpenSpec — the tool, its assumptions, what lands on disk
  • Part IV. The end-to-end walkthrough — bootstrap once, then repeat the cycle
  • Part V. Practices, techniques, traps — recovery paths, conflicts, testing, when to skip it
  • Summary, Appendices — command reference, glossary, checklists, resources

Preface #

This piece grew out of one session, so it reads as a single pass rather than a reference you dip into on demand: from the reason anything in an existing repository needs to change at all, to the exact command cycle you can run tomorrow on your own project. The core claim is short. A spec in a brownfield repository is not written from scratch — it is recovered, one capability at a time. Everything else here is that sentence unpacked: why it’s true, how it differs from design docs and wikis, what tool supports it mechanically, and what to do when it goes wrong.

Who this is for: engineers and tech leads working in a codebase they didn’t write, who have already tried wiring an agent into it. If your repository is new, empty, and entirely in your head, most of the argument below doesn’t apply to you yet. If you have code that’s a few years old, documentation that’s a few years less true, and people who left the project along with the context — keep reading.

How to read it: Parts II–III give the method and the vocabulary. Part IV is a walkthrough you can run with a keyboard in hand. Part V is the most practically useful section — the things that only become visible after a few real changes.

The method matters more than the tool. OpenSpec here is a concrete implementation, not a vendor recommendation — swap the tool and Parts II and V stay true.

Conventions: openspec … is a terminal command. /opsx:… is a chat slash-command (written with a hyphen in Cursor, Windsurf, and Copilot — /opsx-apply). A change is a unit of work with a start and an end, backed by one folder. A delta describes a behavior difference as ADDED / MODIFIED / REMOVED.

Part I. Framing the problem #

1. Why the only living truth in a legacy repo is the code #

Take any project older than two years and ask it one question: where is it written down what the system is supposed to do? There are usually three answers, and all three are bad.

Documentation lags. It was accurate on the day it was written. From the next day it started diverging from the code. Nobody decided it would become false — it just happened, because updating the docs was never a condition of “done.” It was a request.

Intent was never written down at all. The worse part isn’t stale text, it’s what was never recorded in the first place: why this request executes in this exact order, why there’s a check here that looks redundant, why one field is nullable and its neighbor isn’t. That knowledge lives in people, and it leaves with them. A year after they’re gone, the only reliable answer to “what does the system do” is the code — and code answers how honestly, but never why.

An agent inherits every one of these gaps. A human reading unfamiliar code slows down. They go ask a colleague, dig through commit history, leave a TODO. That friction used to save us from mistakes. An agent doesn’t experience it. Handed an ambiguous context, it fills the gap with something plausible and keeps moving at full speed — and the result is confident, well-formed code that quietly does the wrong thing.

An agent amplifies whatever context it’s given. More output against an undocumented repository just means more code nobody can verify.

That is the actual problem spec-driven development solves in a brownfield codebase. Not “let’s write more documentation” — but: make the record of intent something the agent reads mechanically, on every change — the same artifact the code is written against.

2. What you’ll be able to do after this #

Four concrete outcomes, and the criteria for whether the method actually landed:

  1. Run the cycle on your own repository, unassisted — from CLI install to the first archived change.
  2. Choose a variant deliberately. Three different disciplines hide behind the one SDD abbreviation. You’ll learn to tell them apart and know what you’re paying for with each.
  3. Recover from a bad proposal. Four ways back, cheapest first — a normal part of the work, not an emergency mode.
  4. Know when to skip the method. A spec has a cost. Some classes of work don’t earn it back, and naming those is as much a part of the method as writing a delta.

Part II. Spec-driven development #

3. A short history: from spec sheets to agentic code #

The history matters here for one reason: every previous era left behind an objection you’ll hear from a colleague in the first five minutes of any discussion about this.

EraWhat happenedWhat it left behind
1970s
Spec-first
The technical spec was the entry point. Written up front, signed off, and already wrong by delivery — reality moved faster than the document.The belief that a spec is a heavy document, written once, that always ends up lying.
2001
Agile
A correct reaction: working software over comprehensive documentation. The industry over-corrected — instead of making the record of intent light, it mostly stopped keeping one at all.The reflex “documentation = waterfall,” which taints any proposal to write a spec as a step backward.
2003+
TDD / BDD
A durable compromise: the spec became executable, so it couldn’t quietly lie anymore. This is where Given–When–Then comes from.The most valuable artifact on this list — a scenario format that’s still the best known way to describe behavior so both a human and a machine can check it.
2024
Agentic coding
Agentic coding quietly brought the spec back, and almost nobody said so out loud: every prompt is a spec. You describe desired behavior in natural language, the agent turns it into code — but that description is written once, used, and discarded. It never enters the repo, nobody reviews it, and next week nobody can say why the code looks the way it does.The spec has a second reader now — not just a human.
2025–26
SDD tooling
A wave of tools now organizes this into a pipeline: Spec Kit, Kiro, OpenSpec, Tessl. Different emphases, one shared move: turning a disposable prompt into an artifact that lives in the repository. 

Here’s the sentence this whole section exists to set up:

The spec now has a reader who checks it on every single change.

In the seventies, the spec’s only reader was a person — and a person can be talked into ignoring it. Today it’s read by a person and an agent: mechanically, on every change, by the same agent that writes the code. That, not a documentation fashion, is what makes the method viable now.

4. What SDD means today: propose → build → archive #

The cycle has three steps, and every one of them is mandatory.

PROPOSE intent, reviewed as text BUILD code built against the spec ARCHIVE delta merges into truth rework, when it comes back wrong openspec/specs/ — grows by exactly one archived change at a time

PROPOSE — the change enters through the spec. Intent gets written and reviewed before any code exists. At this stage you’re operating on text: requirements, scenarios, the boundaries of the change. A mistake here costs exactly as much as fixing a sentence.

BUILD — code is built against it. The implementation is judged not by “looks reasonable” but by conformance to the agreed spec. This removes the single most expensive review-time argument — the one about what was even meant.

ARCHIVE — archiving folds it back in. The delta merges into the source of truth, and the change folder moves into a dated archive. This is the step that closes the work out.

The question that clarifies everything: when the spec and the code disagree, which one is wrong? In two of the three approaches in the next chapter, the answer is always “the spec” — which is exactly why nobody trusts it. In the third, the answer is “the code,” and that only works because archiving is a command, not a good intention.

I’m not asking you to maintain documentation. I’m making the spec update a step without which the work isn’t considered finished.

The gap between those two framings is the entire gap between a method that survives and one that quietly dies by the third sprint.

5. Three ways a spec can relate to code #

Most teams already live in variants 1 and 2 — and believe that’s SDD. Worth separating them explicitly, because that’s where most of the confusion starts.

Spec-first SPEC CODE drifts starting the next day Spec-anchored SPEC CODE accurate only while someone is diligent Spec-as-source SPEC CODE drift structurally impossible
VariantShapeWhat actually happens
1 — Spec-firstSPEC → CODEThe classic design doc. Written before implementation, then set aside. Accurate the day it’s written; drift begins immediately. A quarter later, the only reliable answer to “what does the system do” is the code again.
2 — Spec-anchoredSPEC ↔ CODEA wiki or architecture doc the team agrees to maintain — better, because there’s at least an intent to update it. But the update is an agreement, not a mechanism, so it drifts exactly as fast as the team is busy — fastest precisely when accuracy matters most: crunch, release, incident. Accurate for as long as someone stays diligent.
3 — Spec-as-sourceSPEC ⇒ CODE ⇒ SPECThe only variant where updating the spec is load-bearing, not a favor. A delta can’t be archived without folding back into the source of truth, and a change isn’t considered done until it’s archived. Drift is structurally impossible — not because the team is disciplined, but because the process doesn’t allow another path. OpenSpec implements this variant.

How to use this classification: next time someone says “we already do SDD,” ask one question — what happens to the spec at the moment a change is considered done? If the answer is “we have to remember to update it,” that’s variant 2, and it will drift. If the answer is “updating it is the completion,” that’s variant 3.

6. The price of spec-as-source: three obligations #

The “drift is structurally impossible” guarantee isn’t free. It’s bought with three obligations. Skip any one of them and you quietly slide back into variant 2.

  1. Archive every change. A change is a change-request unit with a clear start and end. At the end, its spec must be saved: the delta syncs into the source of truth, and the artifacts land in a dated folder. This is usually the first thing teams quietly stop doing — skip it, and the source of truth goes stale, except now you have a wiki with more folders.
  2. Review every artifact. The agent is very good at structure and very bad at guessing what you actually meant. Generating artifacts is normal — that’s what the whole system is built for. Skipping the review is not. The formula: AI drafts, the human owns intent. Accept a generated spec without reading it and you don’t have a source of truth — you have automatically generated noise with high confidence attached.
  3. No requirement without a scenario. Every requirement carries a Given–When–Then scenario, and that scenario becomes a test. The rule is strict: if it can’t be verified, it can’t be proposed. A requirement with no scenario is a requirement nobody can check — so it has no place in the spec. Write the scenario, or drop the requirement.

What you get in return: a repository where current behavior is described in text the agent reads before every change; every described behavior has a matching test; and the history of intent is dated, reviewed, and sits next to the code.

Part III. OpenSpec #

7. Design assumptions that match a brownfield codebase #

To be clear up front: this isn’t a vendor pitch. The method from Part II stays true regardless of what you install. But the tool needs to match the reality of a brownfield repo, or it adds work instead of removing it. OpenSpec is built on four assumptions.

  • One change, one folder. Every change is isolated like a branch. Parallel work doesn’t collide — two people can run two changes at once without rewriting the same spec files.
  • Deltas, not rewrites. ADDED / MODIFIED / REMOVED against existing behavior. This is the main requirement for brownfield, and the most important point in this chapter. Greenfield tools write a spec from nothing, because they have nothing to reconcile against. In an existing repo, we recover the spec from real behavior, one capability at a time — the delta format is what makes that gradual, and, more importantly, what makes it possible at all. No team reverse-engineers an entire legacy repo into specs in one pass — and none needs to: the result would be unreviewable, and therefore worthless.
  • Archiving is a command. Merging into the source of truth is mechanical — not “we agreed to update it,” not a definition-of-done bullet someone checks at review, but a command that either ran or didn’t.
  • The workflow is data. The artifact chain (proposal → specs → design → tasks) is a schema you can fork and adapt to your process. You aren’t locked into someone else’s idea of step order.

Honest alternatives:

ToolWhere it fits
GitHub Spec KitGood, but leans closer to greenfield.
AWS KiroTied to its IDE and the AWS ecosystem.
TesslGoes furthest into spec-as-source, up to regenerating code from spec. Too aggressive for most brownfield teams.
Cursor / Claude Code rules filesShape agent behavior, but hold no per-change state and have no archive step — so they don’t close the loop.

8. What lands on disk #

Worth l[REDACTED]g the directory shape up front — everything after this reads without friction once you know it.

openspec/
  changes/
    add-dark-mode/               ← work in progress
      proposal.md
      specs/**/spec.md
      design.md
      tasks.md
    archive/
      2026-08-07-add-dark-mode/  ← history
  specs/                          ← current truth
  config.yaml
FolderRole
changes/Work in progress: a change lives here while it’s open.
specs/Current truth: what the system does right now.
changes/archive/History: a dated record of every intent decision.

Archiving does two things at once: it folds the delta into specs/, and it moves the folder into archive/ with a date stamp.

Files inside a change:

  • proposal.md — why this change exists and what it touches. Also your control tool during implementation: when the agent wanders, you point at the proposal and say the broad refactor it just attempted isn’t part of this change.
  • specs/**/spec.md — the load-bearing file. Deltas in ADDED/MODIFIED/REMOVED form, every requirement carrying Given–When–Then scenarios. These scenarios are, literally, the acceptance tests.
  • design.md — the decisions worth keeping after release. The thing that usually disappears along with whoever made the call.
  • tasks.md — state of the work. Checkboxes, not a chat transcript.

openspec/specs/ grows by exactly one archived change at a time. It is never hand-edited.

Open specs/ one day and start editing it directly, and you’ve just stepped out of variant 3 back into variant 2.

9. Two surfaces: terminal and chat #

One thing worth remembering: openspec lives in the terminal, /opsx lives in the chat. The terminal is for setup and inspection. The chat is for doing the work.

Terminal commandPurpose
openspec init --tools claudeScaffold the structure in the project
openspec config profileChoose core or extended
openspec updateWrite command files to disk
openspec list · show · viewRead-only inspection
openspec status --change <name>done / ready / blocked
openspec validate <name> --strictRun before you build
Chat commandPurpose
/opsx:exploreSharpen the idea; writes no file
/opsx:new <change-name>Open a change
/opsx:continueNext artifact, one at a time
/opsx:ffFast-forward the rest
/opsx:applyBuild against the agreed spec
/opsx:verifyCheck it
/opsx:syncFold the delta into specs/
/opsx:archiveFile the change into a dated folder

In Cursor, Windsurf, and Copilot, slash-commands use a hyphen: /opsx-apply.

Profiles — where people trip. A standard install gives you the core profile: propose, apply, archive. The commands used throughout this guide — new, continue, ff, verify — belong to the extended profile. That’s exactly why the walkthrough opens with openspec config profile: skip it, and half these commands simply don’t exist, and you’ll burn twenty minutes chasing an error that isn’t one. The mechanism is fully visible: enable a workflow → run openspec update → its command file appears on disk. Disable it → the file disappears.

Two practical notes: re-run openspec update after every CLI upgrade, or the command files in your project drift out of sync with the installed version. And everything in the terminal except init, config, and update is read-only — safe to run in front of anyone, including on a demo.

Part IV. The end-to-end walkthrough #

Written as a sequence you can execute keyboard-in-hand. Two phases: bootstrap happens once per repository, the cycle repeats for every task.

10. Bootstrap: once per repository #

Step 1 — Survey the project, pick a task. Before typing anything, say out loud (or write down): what this repository does, how old it is, and that it was never designed with specs in mind. That’s the real brownfield case.

git log --oneline | head -20
npm test

A green test suite is your baseline. You can’t go further without it.

Step 2 — Install the CLI.

node -v                              # Node 20.19+
npm i -g @fission-ai/openspec@latest
openspec --version

One CLI serves every repository.

Step 3 — Profile. Worth slowing down here, because otherwise it’s invisible.

ls .claude/skills/        # BEFORE: show what's missing
openspec config profile   # choose extended, enable verify
openspec update
ls .claude/skills/        # AFTER: the new command file appears

Step 4 — Initialize.

openspec init --tools claude
ls -R openspec/

Creates the openspec/ structure and writes .claude/skills/. Then open openspec/config.yaml and fill in the stack, project conventions, and the test command.

Step 5 — /opsx:explore. Reads the codebase and sharpens the task. Writes no file — so it’s free. Use it every time the task is fuzzy.

Two things teams skip. Neither is a command — both are human work, and they’re what gets cut first:

  1. A filled-in config.yaml. The project context written here is inherited by every future artifact. It’s the cheapest place to fix a systematic agent mistake.
  2. A green test suite. Current behavior is an undocumented contract. Tests are what makes a regression visible immediately, not a quarter later.

11. The cycle: once per task #

Eight steps, repeated for every task.

#CommandWhat happens
6/opsx:newCreates the change folder, opening the flow
7/opsx:continueOne artifact at a time: read, comment, correct
8/opsx:ffFast-forward the rest, once the shape is right
9/opsx:applyBuilds against the spec; tasks.md checks off live
10/opsx:verifyAutomated check plus a manual read
11/opsx:syncFolds deltas into openspec/specs/
12/opsx:archiveFiles the change into a dated folder
13—Review what changed on disk, and what carries forward

The next task starts again from step 6.

Where the value actually is:

  • Step 7 — slow down here. Read the generated delta, find something imprecise in it, fix it. Open the file and look at it: it’s ordinary markdown you could have written by hand. That’s what removes most of the mystique around the method.
  • Step 9 — keep tasks.md open: checkboxes tick live. This is the clearest moment in the whole process — you watch a plan turn into code.
  • Step 10 — remember: verify reports critical, warning, and suggestion levels, but it doesn’t block archiving. The decision stays with the human. A critical finding means go back to /opsx:apply — never archive a known regression.

12. The full run, annotated #

A detailed timed pass, as run live in the session. The example task used throughout:

Add a “Clinic Services” CRUD section (Service entity: name, description, price) with a full list/create/edit/delete controller, Thymeleaf templates, a nav link, a Flyway migration, and tests, following the existing PetType/Specialty pattern.

SectionTimeWhat happens
0 · Orientation~1 mingit log + npm test; state what the repo does and that it was never designed for specs. “A green suite is our baseline — we can’t go further without it.”
1 · Install~1 minnode -v, npm i -g @fission-ai/openspec, openspec --version. Node 20.19+; one CLI for every repo.
2 · Profile~2 minopenspec config profile (extended, verify on), openspec init --tools claude, openspec update. “Enable the workflow → the command file appears. Disable it → it’s gone.”
3 · Init~2 minopenspec init --tools claude; fill in config.yaml — stack, conventions, test command.
4 · Pick a task~2 min/opsx:explore against the Clinic Services task above. “It writes no file, so it’s free.” Pick the smallest task with the clearest acceptance criteria — not an ambitious one, for a first pass.
5 · Proposal~5–6 minclaude → /init → /opsx:new "Add a Clinic Services CRUD section…" → /opsx:continue. Read the generated delta out loud; open specs/**/spec.md; point at one Given–When–Then scenario: “this is a test case, written before any code exists.”
6 · Deliberate correction~3 minFind something imprecise or too broad in the delta. Fix it by hand in the file first (it’s ordinary markdown), then again through chat, to show both paths. “The mistake is caught while it’s still text. No code exists yet. That’s the entire economics of the method.” Then /opsx:ff and openspec validate <change-name> --strict.
7 · Implementation~5 mintasks.md open on half the screen — boxes check live during /opsx:apply. If the agent wanders, stop and point at proposal.md: broad refactors aren’t part of this change. Run the full suite, not just the new tests — the baseline proves the old behavior is still intact.
8 · Verification~2 min/opsx:verify, openspec status --change <name>. Levels: critical / warning / suggestion. Doesn’t block archiving — the human decides. A critical finding sends you back to /opsx:apply, not to archive.
9 · Archive~3 min/opsx:sync, /opsx:archive, then ls openspec/changes/archive/ and openspec list --specs. “The source of truth just grew by exactly one capability. Dated, reviewed, sitting next to the code.” Never skip this section — the archive is the entire point of the method.
10 · Close-out~2 mingit status, git diff --stat — show what changed: code, tests, specs/, archive/. Time permitting, start a second task with /opsx:new to prove the cycle repeats.

Illustrative spec delta — reconstructing the shape of what /opsx:continue generates for the Clinic Services task, in OpenSpec’s ADDED/MODIFIED/REMOVED + Given–When–Then format:

## ADDED Requirements

### Requirement: Manage clinic services
The system SHALL let staff create, list, edit, and delete clinic
services (name, description, price), following the existing
PetType/Specialty CRUD pattern.

#### Scenario: Create a new service
- GIVEN an authenticated staff user on the Services list page
- WHEN they submit the "New Service" form with a valid name,
  description, and a non-negative price
- THEN the service is persisted via the Flyway-migrated
  `services` table
- AND the user is redirected to the Services list with the new
  entry visible

#### Scenario: Reject a negative price
- GIVEN an authenticated staff user on the "New Service" form
- WHEN the price field is negative
- THEN the form is redisplayed with a validation error
- AND no row is written to the `services` table

#### Scenario: Delete a service in use
- GIVEN a service referenced by at least one appointment
- WHEN staff attempt to delete it
- THEN deletion is blocked with an explanatory message
- AND the existing appointment reference is left untouched

If something goes wrong mid-demo:

SituationMove
The agent is thinking a long timeDon’t go silent — narrate what it’s currently reading
The network dropsSwitch to a pre-prepared repo with changes/ already populated
Running low on timeCut Section 10 and the config walkthrough. Never cut Section 9.

Part V. Practices, techniques, and traps #

The most practically useful part — everything below only becomes visible after a few real changes.

13. When a proposal comes out wrong #

Many people assume a bad AI proposal is the failure mode. It’s actually the opposite: this is exactly where the method proves its value. Four ways back, cheapest first.

PathWhenWhy
A — Edit the fileWording, scope, or a weak scenarioAlmost always fastest. It’s your markdown, and OpenSpec has no objection. Fixing a sentence costs seconds; talking the agent into fixing it costs several message round-trips.
B — Regenerate one artifactThe agent keeps missing the same thingThe documented fix for a repeating mistake: stop accepting bundles, go artifact by artifact through /opsx:continue.
C — Redo the proposalThe framing of the task itself was wrongDelete the change folder and start over. If you’re doing this repeatedly, the real fix is elsewhere: add project context to config.yaml so every future artifact inherits it.
D — Back up to exploreThe task was never clear to begin withCosts nothing — explore writes no files. No artifacts, no sunk cost.

The value isn’t that the AI guesses correctly. It’s that being wrong is cheap, and the mistake is visible while it’s still text and no code exists yet.

14. Resolving conflicts between changes #

Resolve intent first, then let the agent reconcile the code.

Three rules:

  1. Merge specs first. Conflicting intent is a product decision, and a human makes it.
  2. The agent reconciles code. One agreed target; a deterministic test suite decides whether the resolution is correct.
  3. Never touch the archive. It captured intent as of that moment.

Why this order: in a repo where the spec is the source of truth, the agent builds code against it. Resolving code first means resolving it against two specs, each written as if the other change didn’t exist — then bending the spec to match whatever the merge produced. That inverts the method at exactly the moment it’s needed most. So: merge intent, hand the agent the reconciled spec plus the conflict, let it propose code, let tests judge. Same division of labor as everywhere else in this guide.

Why the archive stays untouched: an archived proposal is a historical record of what was planned at that time. Reshaping it to match the merge outcome destroys the audit trail that the archive exists to preserve.

Three practical consequences: one change, one folder — isolation works like a branch, so parallel work doesn’t collide. Merge to main before archiving — archiving is a close-out step, not something done mid-implementation. And most merge conflicts are purely mechanical: two changes touched adjacent lines and neither disagreed about behavior. No spec needed there at all — reach for the spec only when the changes genuinely wanted different things.

15. Testing practice #

Agents write tests. Deterministic suites decide what passed.

That’s the core idea, so it goes first. Agents are good at writing tests and bad at judging whether they passed. A deterministic suite judges well and can’t write anything. Keep those roles separate and the pipeline stays trustworthy. Swap them and you get a system that confidently reports success.

  1. One scenario, one test. Given–When–Then maps directly, with no interpretation step — the actual reason the spec format looks like this.
  2. Order tasks.md test-first. The first task for each scenario is a failing test. Nearly free TDD. If you don’t want to work test-first, make “tests written and passing” its own line item — either way, tests belong in the plan, not tacked on at the end.
  3. Run the whole suite. The baseline proves old behavior still holds. New tests alone prove nothing.
  4. Characterize before you change. The classic brownfield insurance policy, and exactly what gets skipped under deadline pressure. Capture current behavior in tests before the change — you can’t recover a spec from behavior you never captured.
  5. Browser work goes through Playwright. The agent writes the test, the run judges it.
  6. Validate between phases. Deferred validation defeats the method. Check everything only at the end and you’re back to plain “generated it, hope it works.”

On covering legacy code: “so do we have to cover the whole repo with tests now?” comes up every time. No. We characterize only the surface the current change touches — one capability at a time, at the same pace the spec grows.

16. When not to write a spec #

A judgment call, not a doctrine — short, but not skippable: a method with no edges stops being a method and becomes a ritual.

A spec earns its keep when it reduces risk and outlives the session.

Skip itWrite it
A trivial, single-file changeBehavior crosses module boundaries
A one-off spike (formalize only what survives)The change touches an undocumented invariant
Review would cost more than the work itselfThe work will outlive this session
A genuine incident — ship the fix, spec afterRegulated or critical paths — the archived change is the record

On the incident row specifically: “write it after” is a duty, not a courtesy. Ship the hotfix, then write the spec retroactively — that after-the-fact archive entry matters exactly when the process got skipped under pressure, because that’s precisely the kind of change nobody remembers accurately later.

The strongest argument in the right-hand column is the undocumented invariant — it’s exactly where quiet regressions start in a legacy repo, the kind nobody notices for a quarter.

Summary #

Three things worth carrying away.

1. A spec is recovered, not invented #

It grows one archived change at a time. No command turns your legacy repo into a spec overnight — and you don’t need one.

2. It’s verifiable by construction #

Every requirement carries a scenario, every scenario is a test. A requirement that can’t be verified never enters the spec at all.

3. Agents write, test suites decide #

The most portable conclusion in this whole guide. This boundary holds regardless of which tool you pick, and it’s what makes the pipeline trustworthy.

One concrete ask: try this on one real repository, on the smallest task with the clearest acceptance criteria — not an ambitious one. And if you need to pick which repo to start with: a reliable first move is to take the one nobody wants to touch.

Appendices #

A. Command reference #

Terminal

node -v                                  # Node 20.19+
npm i -g @fission-ai/openspec@latest     # install
openspec --version

openspec init --tools claude             # scaffold the structure
openspec config profile                  # core | extended
openspec update                          # write command files

openspec list                            # read-only
openspec list --specs
openspec show
openspec view
openspec status --change <name>          # done | ready | blocked
openspec validate <name> --strict        # before you build

Chat

/opsx:explore          sharpen the idea; writes no files
/opsx:new <name>       open a change
/opsx:continue         next artifact, one at a time
/opsx:ff               fast-forward the rest
/opsx:apply            build against the agreed spec
/opsx:verify           critical | warning | suggestion
/opsx:sync             fold the delta into openspec/specs/
/opsx:archive          file the change into a dated folder

Cursor, Windsurf, Copilot — hyphenated: /opsx-apply.

B. Glossary #

  • Brownfield — an existing codebase with history, as opposed to greenfield (a new project).
  • Delta — a description of a behavior difference in ADDED / MODIFIED / REMOVED form, against current state.
  • Drift — the gap between what a spec says and what the code actually does.
  • Change — a unit of work with a start and an end, backed by one folder under changes/.
  • Invariant — a property that must always hold; an undocumented one is the main source of silent regressions.
  • Characterization test — a test that captures existing behavior before it changes.
  • Given–When–Then — the scenario format: precondition, action, expected outcome.
  • Spec-first / spec-anchored / spec-as-source — the three ways a spec can relate to code (Part II, Chapter 5).

C. Checklists #

Before the first change

  • ☐ Node 20.19+ installed
  • ☐ CLI installed globally
  • ☐ extended profile chosen, openspec update run
  • ☐ openspec init --tools claude run
  • ☐ config.yaml filled in: stack, conventions, test command
  • ☐ Test suite green — a baseline exists

Every change

  • ☐ Task went through /opsx:explore
  • ☐ The delta was read, not just accepted
  • ☐ Every requirement has a Given–When–Then scenario
  • ☐ openspec validate <name> --strict passed
  • ☐ The surface the change touches is characterized by tests
  • ☐ The full test suite ran, not just the new tests
  • ☐ /opsx:verify — no critical findings
  • ☐ /opsx:sync done
  • ☐ /opsx:archive done — the change isn’t finished without this

Signs you’ve slipped back into variant 2

  • ☐ openspec/specs/ is being hand-edited
  • ☐ Artifacts get accepted without being read
  • ☐ Requirements exist with no scenario
  • ☐ Changes get closed without archiving

D. Resources #

  • OpenSpec: github.com/Fission-AI/OpenSpec[1] — docs/getting-started.md, docs/commands.md, docs/workflows.md
  • Playwright: playwright.dev[2]
  • Install: npm i -g @fission-ai/openspec@latest (Node.js 20.19+)
  • Alternative tools: GitHub Spec Kit · AWS Kiro · Tessl · Cursor / Claude Code rules files

Thanks to the CoffeeJUG community for hosting the session.

Resources: OpenSpec on GitHub[1] · Oleh Ivchenko on LinkedIn[3] · ORCID 0000-0002-9540-1637

References (3) #

  1. Fission-AI. Fission-AI/OpenSpec (GitHub repository). github.com. tr
  2. playwright.dev. playwright.dev.
  3. Oleh Ivchenko on LinkedIn. linkedin.com.
← Previous
AI Regression Testing: Detecting Behavioral Drift Across Model Updates in Production
Next →
Next article coming soon
All Spec-Driven AI Development articles (33)33 / 33
Version History · 4 revisions
+
RevDateStatusActionBySize
v1Aug 27, 2026DRAFTInitial draft
First version created
(w) Author5,278 (+5278)
v2Aug 27, 2026PUBLISHEDPublished
Article published to research hub
(w) Author5,278 (~0)
v3Aug 27, 2026REVISEDMajor revision
Significant content expansion (+29,227 chars)
(w) Author34,505 (+29227)
v5Aug 27, 2026CURRENTContent update
Section additions or elaboration
(m) Admin34,910 (+405)

Versioning is automatic. Each revision reflects editorial updates, reference validation, or formatting changes.

Recent Posts

  • Cost Spillover Effects: How AI Projects Reconfigure Internal R&D Budget Allocation
  • Carbon Ledger of AI Inference: Accounting for Emissions Across Distributed Computing Nodes
  • Hybrid Warfare Signal Intelligence: AI for Detecting Coordinated Disinformation in Critical Infrastructure
  • Semantic Coherence vs Plagiarism Thresholds: Automated Detection of Overlaps in AI-Written Content
  • AI Alignment Progress Report 2025: RLHF Successors and Constitutional AI Evaluation

Research Index

Browse all articles — filter by score, badges, views, series →

Categories

  • ai
  • AI Economics
  • AI Memory
  • AI Observability & Monitoring
  • AI Portfolio Optimisation
  • Ancient IT History
  • Anticipatory Intelligence
  • Article Quality Science
  • Capability-Adoption Gap
  • Cost-Effective Enterprise AI
  • Future of AI
  • Geopolitical Risk Intelligence
  • hackathon
  • healthcare
  • HPF-P Framework
  • innovation
  • Intellectual Data Analysis
  • medai
  • Medical ML Diagnosis
  • Open Humanoid
  • Research
  • ScanLab
  • Shadow Economy Dynamics
  • Spec-Driven AI Development
  • Technology
  • Trusted Open Source
  • Uncategorized
  • Universal Intelligence Benchmark
  • War Prediction
  • Кафедра ЕКІТ

About

Stabilarity Research Hub is dedicated to advancing the frontiers of AI, from Medical ML to Anticipatory Intelligence. Our mission is to build robust and efficient AI systems for a safer future.

Language

  • Medical ML Diagnosis
  • AI Economics
  • Cost-Effective AI
  • Anticipatory Intelligence
  • Data Mining
  • 🔑 API for Researchers

Connect

Facebook Group: Join

Telegram: @Y0man

Email: contact@stabilarity.com

© 2026 Stabilarity Research Hub

© 2026 Stabilarity Hub | Powered by Superbs Personal Blog theme
Stabilarity Research Hub

Open research platform for AI, machine learning, and enterprise technology. All articles are preprints with DOI registration via Zenodo.

590+
Articles
20+
Series
DOI
Archived

Research Series

  • Medical ML Diagnosis
  • Cost-Effective Enterprise AI
  • Future of AI
  • Trusted Open Source
  • Geopolitical Risk Intelligence
  • Capability–Adoption Gap
  • Spec-Driven AI
  • Shadow Economy Dynamics

Community

  • EKIT Department
  • Join Community
  • MedAI Hack
  • Zenodo Collection
  • GitHub
  • contact@stabilarity.com

Legal

  • Terms of Service
  • About Us
  • Contact
  • CC BY 4.0 License
Operated by
Stabilarity OÜ
Registry: 17150040
Estonian Business Register →
© 2026 Stabilarity OÜ. Content licensed under CC BY 4.0
Terms About Contact
Language: 🇬🇧 EN 🇺🇦 UK 🇩🇪 DE 🇵🇱 PL 🇫🇷 FR
Display Settings
Theme
Light
Dark
Auto
Width
Default
Column
Wide
Text 100%

We use cookies to enhance your experience and analyze site traffic. By clicking "Accept All", you consent to our use of cookies. Read our Terms of Service for more information.