docs-lab/customize/schemas.md
Change what OpenSpec produces: the artifacts, their order, and their templates.
A schema defines what a change proposal produces: which artifacts, in what order, from which templates. For example, spec-driven, the default bundled schema, produces these four in roughly this order, each building on what came before:
proposal → specs → design → tasks
Fork a schema when you want these to be different documents, whether that means fewer of them, different names, or a different structure.
OpenSpec looks for a schema in three places, in order, and uses the first one it finds:
openspec/schemas/, committed with the repo so your whole team gets it.~/.local/share/openspec/schemas on macOS and Linux (or under $XDG_DATA_HOME if you set it), or %LOCALAPPDATA%\openspec\schemas on Windows. Schemas here are available in every project you work in.spec-driven, ship inside openspec itself.The same name can exist in more than one place, and the more specific location wins. openspec schema which shows which copy is in use:
$ openspec schema which spec-driven
Schema: spec-driven
Source: project
Path: /your-project/openspec/schemas/spec-driven
Shadows:
package: .../openspec/schemas/spec-driven
A schema is defined by a folder of plain files: one schema.yaml that declares the artifacts, and a template for each of them. Here's the built-in spec-driven:
spec-driven/
├── schema.yaml
└── templates/
├── proposal.md
├── spec.md
├── design.md
└── tasks.md
Here's the tasks artifact's entry in schema.yaml, trimmed:
artifacts:
- id: tasks
generates: tasks.md
description: Implementation checklist with trackable tasks
template: tasks.md
instruction: |
...what the agent is told when creating tasks.md...
requires:
- specs
- design
The built-in schemas ship inside the openspec package, so you never edit them in place. You get your own copy by forking.
There are two ways to get your own schema:
openspec schema init.Fork the schema you want to start from, running from your project root:
$ openspec schema fork spec-driven
Note: Schema commands are experimental and may change.
✔ Forked 'spec-driven' to 'spec-driven-custom'
Source: .../openspec/schemas/spec-driven (package)
Destination: /your-project/openspec/schemas/spec-driven-custom
Pass a second argument to pick the name (openspec schema fork spec-driven team-flow). Names are kebab-case.
Edit the copy: schema.yaml and the templates. Editing your fork covers what to change.
Validate it:
openspec schema validate spec-driven-custom
This is the one command that catches a broken schema (missing templates, bad YAML, dependency cycles) before you're in the middle of a change.
Point your project at it in openspec/config.yaml. This step is yours to do because fork leaves config.yaml untouched:
schema: spec-driven-custom
New change proposals now follow your schema. Changes created earlier keep the schema they started with.
To replace the default everywhere without touching config.yaml, fork to the same name: openspec schema fork spec-driven spec-driven. Your project's copy then shadows the built-in, as Where schemas live explains.
openspec schema init scaffolds a new schema instead of copying one:
$ openspec schema init lite --description "Lite flow" --artifacts proposal,tasks
✔ Created schema 'lite'
Schema created at: /your-project/openspec/schemas/lite
Artifacts: proposal, tasks
The scaffold is bare. Artifacts come from the built-in four ids only, and the generated templates carry no instructions, so the agent gets less guidance until you write your own. From there the fork steps apply unchanged: validate it, then point config.yaml at it.
A fork has two kinds of files to edit:
For example, to drop the design document for a leaner flow:
Delete the design entry from schema.yaml.
Remove design from the requires list of tasks.
Validate:
$ openspec schema validate spec-driven-custom
✓ Schema 'spec-driven-custom' is valid
Skip step 2 and validate catches it:
✗ Schema 'spec-driven-custom' has errors:
error: Invalid dependency reference in artifact 'tasks': 'design' does not exist
Validate after every hand-edit. A broken schema otherwise surfaces in the middle of a change, when a workflow asks for a file that isn't there. Like config.yaml, schema edits reach the agent on the next run.
openspec update refreshes the installed skills and commands, and it never touches openspec/schemas/. Your fork keeps working exactly as you left it, which also means it stops receiving improvements when the built-in schema evolves. To pick those up later, fork the built-in again under a new name and port the differences across.
Sharing a schema means copying its folder.
openspec/schemas/ and everyone on the repo uses it.openspec/schemas/<name> and it works like your own.We're working on a schema registry, public and private, so schemas can be installed by name instead of copied by hand.