skip to content
coograph 17

OpenSpec

An OpenSpec change is a directory of four files, written before any code, that says what you are about to do and why. The agent writes it, you approve it, then the work happens against it. It is the artifact the workflow produces at its Propose step, and the record Retro reads back later.

The point is the interrupt. An agent that has already written 400 lines will argue for them. An agent holding a one-page proposal will take an edit without a fight, and you find out it misunderstood the task while that costs you a sentence instead of an afternoon.

The directory

openspec/changes/2026-09-20-saved-searches/
├── .openspec.yaml
├── proposal.md
├── specs/
│   └── saved-searches/
│       └── spec.md
└── tasks.md

The name is the date plus a slug, so the directory sorts chronologically and two changes never collide. Everything for one change lives in one place, and archiving is a move.

.openspec.yaml

Four lines of metadata. name, created, status, and the project it applies to in a multi-project repository.

name: saved-searches
created: 2026-09-20
status: approved
project: app

status is the gate: proposed until you say otherwise, approved once you do. An agent that finds a proposed change has not been cleared to write code.

proposal.md

The argument, in six sections.

sectionwhat belongs there
WhyThe problem, with evidence. Numbers from the codebase or production, not adjectives.
Goals / Non-GoalsWhat this change does, and explicitly what it does not, so scope creep has somewhere to bounce off.
DecisionsEach real choice, the alternative, and why this one. This is the section you read in six months.
ImpactFiles created and edited, plus anything outside the repo: rules, infrastructure, other services.
RisksWhat could go wrong and what limits the damage.

The Why section is the one worth insisting on. “Search is slow” is not evidence. “Search fetches every document of five collections into the browser on each query, about 500 reads and 1 to 3 seconds” is, and it tells the reviewer what success looks like.

specs/<capability>/spec.md

Requirements, one per behaviour, in the imperative.

# Saved searches

## Requirement: save and manage
A logged-in user on a result page SHALL be able to save the current query and
filters (max 10 per user); a logged-out user SHALL be sent to login and back.

## Requirement: daily digest
A scheduled function at 08:00 Europe/Berlin SHALL, for every saved search,
fetch new ads since `lastNotifiedAt`, and when there is at least one, email the
owner a digest, then set `lastNotifiedAt`. A failed send SHALL leave
`lastNotifiedAt` untouched so the next run retries without duplicates.

The SHALL is not ceremony. It forces a testable sentence: you can point at a running system and say yes or no. “Should handle errors gracefully” cannot be checked and so never is.

One directory per capability. A change that touches three capabilities has three spec files, and those files are what a later change edits when the behaviour changes.

tasks.md

Task groups, not a file checklist. Three to eight, each independently verifiable, with the last one always verification.

## 1. Engine  [ ]
- Files: `src/lib/server/search.ts`.
- Index, query parsing, scoring, suggestions.
- Acceptance: spec § ranked results.

## 2. Verify  [ ]
- Type-check, curl matrix, browser run with real clicks, review, prod check.

Grouping by unit rather than by file is what makes the list reviewable. “Edit six files” tells you nothing; “the engine, then the page, then verification” tells you the shape of the work, and each group can be checked off only when it actually works.

The gate

Any change that touches two or more files, alters a public interface, changes a spec, or adds behaviour needs an approved OpenSpec before code. The exemptions are four, and they are literal:

“Trivial”, “obvious”, “small” and “just one tweak” are not on that list, and they are the four things an agent says right before it rewrites your authentication. When in doubt the rule is to propose, because the cost of a proposal you did not need is one page, and the cost of skipping one you did need is a rewrite.

The lifecycle

  1. Propose. The agent writes the four files and stops. No code.
  2. Approve. You read it, send edits, or say proceed. Edits at this point are cheap.
  3. Apply. The agent works through the task groups in order, ticking them off as each one lands.
  4. Review. /coograph-review checks the result against the spec, not against the diff, which is how scope creep and quietly dropped requirements get caught.
  5. Archive. The directory moves to openspec/changes/archive/, where it becomes the record of what was decided.

Requirements change mid-flight. When they do, the spec is updated first and the work continues against the new version. A change whose code no longer matches its spec is a change nobody can review.

Why the archive matters

An archived change is not a filing cabinet. It is the only durable record of why, and it outlives every person and agent involved.

It is also data. Retro reads the archive and reports tasks per change, how many changes shipped with unchecked tasks, how often a review found something worth a fix section, and which paths keep appearing. A project where a third of archived changes have unchecked tasks has a workflow problem that no individual review would have surfaced.

A worked example

The search rewrite on a production classifieds site was one change directory. The proposal’s Why said client search fetched every document of five collections per query. Goals fixed the scope at ranking, query understanding, suggestions and zero-result handling, and Non-Goals ruled out an external search service, which is where that conversation would otherwise have gone. Decisions recorded the 60-second index memo and the reason results are computed on the server. The spec set five requirements, one of which was that every existing filter keeps working, and that requirement is what caught a dropped sort option during review. Tasks ran engine, page, suggestions, verification.

The change shipped in a day. The proposal took twenty minutes, and it is the reason the review could be a yes or no instead of an argument.

Where it lives

The skills that write and apply these are coograph-propose, coograph-apply, coograph-review and coograph-archive, available as /coograph-* commands in Claude Code and as agents in the other supported tools. The format is plain Markdown and YAML in your repository. Nothing about it is tied to a vendor, and a change directory stays readable long after any particular agent stops being the one that wrote it.