The best thing OpenSpec gave me was a place to stop.
I was on change E-10 of an iOS project. The implementation map said: build the story cover and the scene generation. Clear enough. I was about to run /opsx:propose and spend the usual ten minutes reading a draft and pushing back on it.
I ran three cheap checks first. ImageCreator has no unattended path, so cover generation can’t work the way the map assumed. The scene code had never been tested, not once. And keyScenes was arriving as Slovak plot-beats, unusable as image prompts without a rewrite nobody had planned.
Three measurements and the map was wrong. Not slightly off. Wrong in exactly the part I was about to build. So no proposal got written that day, which felt like failure for about an hour and then didn’t.
The rule went into openspec/config.yaml, permanently: in work that fixes a document, the document fixes are the first tasks. It’s happening again right now on E-13, the paywall change, where the interaction between withdrawal, purchase and the read counter isn’t decided yet. Nothing gets proposed until it is. Second time around it feels like routine rather than a crisis, which is roughly the point.

The problem is upstream of the model
Most bad AI output isn’t a model failure. It’s a brief failure.
Think about where your project’s actual requirements are stored right now. Not the ticket title. The real decisions: why you rejected the other approach, what “done” means for this feature, which constraint is non-negotiable. For most teams that lives in a chat window, spread across six sessions, half of it in someone’s DMs.
That’s why the same agent builds something great on Monday and something stupid on Friday. The model didn’t change. The context you handed it did, and you have no way to see the difference because it was never written anywhere. I made a version of this argument about phrasing in what survives of prompt engineering; this is the same problem one layer up, where the artifact in question is the project’s requirements rather than a single message.
A spec fixes that by being a contract about behavior. Not an implementation plan, not documentation written after the fact. An agreement about what the system should do, closed before code gets written. And because it’s a file, it survives a model swap and a person swap. That last part sells better to seniors than any AI argument, because it’s really about onboarding and bus factor.
What OpenSpec actually is
Two folders in your repo. specs/ is the truth about how the system works today. changes/ holds proposals that haven’t touched anything yet. You can have three changes in flight and none of them lie about the current state of the system, because a change only merges its deltas into specs/ when you archive it.
Install is npm install -g @fission-ai/openspec and then openspec init. The loop is four commands: /opsx:explore, /opsx:propose, /opsx:apply, /opsx:archive.
Explore is the one everybody skips, and skipping it is why spec-driven development “doesn’t work” for them. It creates no artifact and commits nothing. It reads the codebase, compares options, asks you questions. The failure mode without it is familiar: you run propose on a foggy sentence, the agent cheerfully generates something that looks convincing, and you spend half an hour rewriting a plan for a thing you didn’t want. Explore is a cheaper place to be wrong.
Delta specs use ADDED, MODIFIED and REMOVED as literal section headings. It’s a git diff for requirements. Nobody sends you a whole file for review, they send you the diff, and MODIFIED replaces a specific requirement rather than merging approximately, which is why two parallel changes don’t collide unless they touch the same requirement.

Six rules I’d keep
These came out of fifteen changes, E-1 through E-15, on a real project. They’re not in the docs.
The “Current state” section is a decision journal, not a status board. In config.yaml there’s a context block injected into every generated artifact, and the longest part of it is a prose, dated record of what was decided and why, written in the same register as an ADR. Rule at archive time: rewrite the date too. A fresh session, or me in three months, doesn’t have to guess anything.
A proposal cites a line in the implementation map. Every proposal opens with a reference to its E-N row, its dependencies and its “Done when” column. It doesn’t get to invent scope.
Archiving with unfinished tasks is a deliberate pattern. E-7, E-8, E-9 and E-12 were all archived with device-walk tasks unchecked. Every one of them carries a blockquote saying why: two strings don’t have final wording yet, so the tasks are blocked, not improvised. The difference between “I rushed it” and “I knowingly left it open and wrote down why” is exactly what makes the document trustworthy six months later.
A bad decision found during implementation gets struck through with a date, never deleted. E-12 task 3.1 reads ~~original task~~ **Revised 2026-09-09 while implementing: see design D3.** Delete it and you lose the history of why the original plan was wrong, which is usually the most valuable line in the file.
Permanent decisions go to docs/, never only to design.md. Design docs get archived along with the change and stop being read. E-10 did this to itself: the chosen path went into an ADR and the decision log before implementation started.
Measured beats derived, and the log says which one it is. The phrases that keep repeating are “measured, not assumed” and “verified by installing over the author’s real store rather than by reasoning”. When a measurement contradicts a document, that goes in the decision log before anything else continues. A document that lies is worse than no document.
Green tests are not a gate
This is where I disagree with almost every workflow I’ve read.
I don’t trust a green test suite as permission to archive. That log has bugs in it that sailed through a fully green run: a coordinator that was never assigned, a heading rendered above an empty body, a try? that got missed because the grep only covered one directory. A green suite tells you nothing about the sentence the screen actually renders.
The other thing worth stealing: ADR supersession lives in the OpenSpec context, not only in the decision log. config.yaml states flatly that 0004, 0005 and 0006 are VOID, plus a list of dead concepts nobody should reference. An agent that never reads the full decision log still won’t touch them.
Costs, plainly
A lite spec runs ten to fifteen minutes and saves you one or two rewrite cycles. That’s a trade, not free money. Nine changes out of ten deserve half a page; if you’re writing three pages to add a toggle, you’re doing it wrong. Full specs are for the cases where being wrong is expensive and hard to reverse.
The number is permanent even when the scope isn’t. E-10 is still called e-10-story-cover even though the original scope (scenes) died completely and something else took its place. Renumbering would break every reference in the log for no gain.

Try it on one feature
Next time your agent builds the wrong thing, don’t ask which model to switch to. Ask where it was written down.
Pick one feature this week. Half an hour. Run /opsx:explore on the foggiest sentence you have and see how much you stop re-explaining after that. You don’t need a team pilot or a new process, and if you try to roll it out as one it’ll be dead in two weeks.
Sources: OpenSpec (opens in a new tab)
