Types and artifacts
cospec ships eleven schemas, one per conventional-commit type. A change's type is its schema — cospec new <type> <slug> stamps it into the change's .openspec.yaml as schema: <type>. There are no name prefixes, no parallel taxonomy to keep in sync.
Every schema is composed from the same six hand-authored artifacts. Types differ only in which artifacts they declare, which of those are mechanically required, and which instruction variant (full or lite) they use.
| artifact | file | role |
|---|---|---|
proposal | proposal.md | Why / What Changes / (Capabilities) / (Surfaces) / Impact |
blocking-changes | blocking-changes.md | cross-change dependency ledger |
specs | specs/**/*.md | delta specs — see OpenSpec's delta format |
design | design.md | Context / Goals / Decisions / Risks |
verification | verification.md | per-behavior acceptance-evidence ledger |
tasks | tasks.md | numbered checkbox groups tracked during apply |
verification is covered in full — its row grammar, layer vocabulary, and per-type required-row rules — on Verification. This page owns the matrix that decides whether a type has one.
The artifact matrix
Each type declares each artifact in one of four states:
- R (required) — declared, and named in
apply.requires;applymechanically gates on it. - O (optional) — declared, and its instructions/templates are available, but
applydoes not gate on it. - O(trig) (optional, soft-promoted) — declared, not in
apply.requires, but a checked## Surfacesflag turns its absence into an exit-code-3 soft blocker atapply(clear it with--allow-soft) and a WARNING atvalidate(ERROR under--strict). It never becomes a hard requirement — the matrix's shape never changes at gate time, only whatapplyis willing to wave through. - F (forbidden) — not declared for this type at all;
cospec validateraisesmeta/forbidden-artifactif the file exists anyway.
| type | proposal | blocking-changes | specs | design | verification | tasks |
|---|---|---|---|---|---|---|
feat | R (full) | R (full) | R | O | R | R |
fix | R (full) | R (full) | O | O | R | R |
perf | R (full) | R (full) | O | O | R | R |
refactor | R (full) | R (full) | O | R | R | R |
revert | R (full) | R (full) | O | F | O(trig) | R |
build | R (lite) | R (lite) | F | F | O(trig) | R |
ci | R (lite) | R (lite) | F | F | O(trig) | R |
chore | R (lite) | R (lite) | F | F | F | R |
docs | R (lite) | R (lite) | F | F | F | R |
style | R (lite) | R (lite) | F | F | F | R |
test | R (lite) | R (lite) | F | F | F | R |
tasks is required everywhere and always tracked by apply. Optional artifacts never gate — you can still author them (cospec instructions <artifact> --change <slug> works for any declared artifact), they just don't block apply or archive if left out.
## Surfaces — the soft-nudge block
Every type except the four no-surface light types (chore, docs, style, test) gets a closed, all-optional ## Surfaces checkbox block in its proposal template:
## Surfaces
- [ ] interactive — a user-visible/interactive surface (UI, TUI, CLI UX)
- [ ] deploy — deploy/runtime/CI-execution topology
- [ ] integration — a third-party/external contract
- [ ] agent-behavior — prompts, tools, model routing, agent output shapeThese four tokens are the only ones the block accepts. Checking a flag never hard-requires anything by itself — it soft-promotes an otherwise-optional verification row or design section into the soft-blocker set at apply. Leaving every box unchecked changes nothing.
For revert / build / ci, checking any ## Surfaces flag (or, for
build/ci, specifically deploy) is what nudges verification from O(trig) into a soft blocker. A flag-free change of one of these types stays a genuinely two-minute ceremony. :::
The full exit-code semantics for apply — including how a soft blocker (exit 3) differs from a hard blocker (exit 2) — live on Apply and archive.
Per-type rationale
featis the only type gated onspecs— a new feature that changes no capability's spec is almost always mis-typed. Itsverificationrequirement also gates on a "verified the wrong layer" rule: a[critical]behavior group whose only evidence row is@unitdoesn't count.fixleavesspecsoptional but requiresverificationwith a mandatory regression row — a fix whose defect the suite never actually exercised is worthless. Add a spec delta only when the bug meant the living spec itself was wrong.perfrequiresverificationrows that prove behavior twice: one row tied to a benchmark, one proving the speedup didn't change behavior.refactoris the only type that requiresdesign— it must also prove an invariant: the existing suite passes unchanged.revert/build/cistay light by covenant:verificationis soft-promoted only if you check a## Surfacesflag, never hard-required.chore/docs/style/testforbidverificationoutright. These types have no runtime behavior surface to exercise — atestchange is its own verification, astylechange is "no semantic diff." Forbidding rather than merely making optional is what protects the two-minute covenant for these four; they also omit## Surfacesentirely.
Schema versioning and grandfathering
Every schema carries a version, currently 2 (bumped from 1 when verification was introduced). cospec new stamps a change's .openspec.yaml with the schema version current at creation time; changes created before verification existed have no stamp and are treated as schemaVersion: 1.
apply and archive compute their required-artifact set from (type, schemaVersion), filtered to artifacts that existed at that schema version — so a schemaVersion: 1 feat or fix change is never retroactively gated on verification. No in-flight change gets blocked by a schema expansion after the fact.
cospec validate emits a non-blocking INFO naming cospec migrate for any change still on schemaVersion: 1. Running cospec migrate <slug> scaffolds a deferred verification.md (every row marked [~] defer: pre-v2 change, verified out-of-band) and bumps the change's stamp to the current version. cospec doctor lists every change still sitting on an old schema version. Nothing runs this automatically — migration is opt-in, one change at a time.
For the customization tiers available on top of the eleven built-in schemas — openspec/config.yaml rules, and forking a schema as an escape hatch — see Configuration reference.