schema.yaml
Every field of a schema definition, for reading or writing one.
schema.yaml lists the planning files a workflow creates. It also defines their order and the handoff to implementation.
Location
A project schema lives under openspec/schemas/<name>/:
openspec/schemas/review-first/
├── schema.yaml
└── templates/
├── proposal.md
└── tasks.mdOpenSpec checks three places for that directory. The first match wins.
| Copy | Directory |
|---|---|
| 1. Project | <project>/openspec/schemas/<name>/ |
| 2. User, macOS and Linux | ~/.local/share/openspec/schemas/<name>/ |
| 2. User, Windows | %LOCALAPPDATA%\openspec\schemas\<name>\ |
| 3. Package | The schemas installed with the CLI |
If XDG_DATA_HOME is set, the user directory moves to $XDG_DATA_HOME/openspec/schemas/<name>/ on every platform.
The directory name is the lookup key used by --schema, config.yaml, and .openspec.yaml. If the name field differs from the directory name, OpenSpec still uses the directory name for lookup.
openspec schema which <name> prints the active directory and any lower-priority copies it hides.
Top-level fields
| Field | Contract |
|---|---|
name | Required. A non-empty string stored as the schema name. Lookup still uses the directory name. |
version | Required. A positive integer stored as the schema revision. The value doesn't change OpenSpec's behavior. |
description | An optional string printed by openspec schemas. With no value, the schema has no description. |
artifacts | Required. A non-empty list of artifact entries. |
apply | Optional apply settings. With no block, OpenSpec uses the apply defaults. |
Artifact fields
Each entry under artifacts defines one planning file or set of files.
| Field | Contract |
|---|---|
id | Required. A unique, non-empty string used in dependencies, project rules, commands, and apply settings. |
generates | Required. A relative path or glob telling the agent where to write the artifact inside the change folder. |
description | Required. A string that labels the artifact in instructions sent to the agent. |
template | Required. A relative path to the artifact's format in the schema's templates/ folder. |
instruction | Optional guidance telling the agent what content to produce. |
requires | A list of artifact IDs that must be complete first. Default: []. |
generates
The path starts from the change folder. For a change named add-auth:
generates: proposal.mdThe artifact goes here:
openspec/changes/add-auth/proposal.mdA glob can match several files:
generates: specs/**/*.mdThis matches Markdown files below openspec/changes/add-auth/specs/. OpenSpec treats a value containing *, ?, or [ as a glob.
OpenSpec rejects absolute paths and paths containing a .. segment.
Completion
OpenSpec checks whether the output exists. It doesn't read the file to decide whether the artifact is complete.
generates value | Complete when |
|---|---|
proposal.md | That file exists. |
specs/**/*.md | The glob matches at least one file. |
template
The path starts from the schema's templates/ folder. In the review-first schema:
template: proposal.mdOpenSpec reads this file:
openspec/schemas/review-first/templates/proposal.mdOpenSpec gives the template's contents to the agent as the output format. It doesn't copy the template into the change folder.
OpenSpec rejects absolute paths and paths containing a .. segment.
requires
- Dependencies: every ID in
requiresmust name another artifact in the same schema. - Ready state: an artifact becomes ready after all its dependencies are complete.
- Invalid graphs: missing IDs, duplicate IDs, and dependency cycles fail validation.
- Ties: when several artifacts are ready, their order in
artifactsdecides which one OpenSpec returns first.
Apply fields
apply defines what must exist before implementation starts.
| Field | Contract |
|---|---|
requires | Required. A non-empty list of artifacts that must exist before apply instructions become ready. |
tracks | An optional relative path to a Markdown task file in the change folder. Default: null. |
instruction | Optional guidance sent to the agent when apply is ready. OpenSpec uses built-in guidance by default. |
Artifact requires controls planning order. apply.requires controls when apply instructions become ready.
tracks
The path starts from the change folder. For a change named add-auth, tracks: tasks.md reads:
openspec/changes/add-auth/tasks.mdApply stays blocked if that file is missing or contains no checkbox with task text. OpenSpec counts these checkbox forms:
- [ ] Pending task
- [x] Completed task
* [X] Completed task
+ [ ] Pending task
1. [ ] Pending task
2) [x] Completed taskAny Markdown list marker works: -, *, +, or a number of up to nine digits followed by . or ). Leading spaces are allowed. The tasks.md section of the spec-driven page defines the stricter format produced by the default schema.
The tracked file drives the apply state:
blocked: the file is missing, or no checkbox has task text.ready: at least one tracked task is pending.all_done: every tracked task is checked.
OpenSpec rejects absolute paths and paths containing a .. segment.
Apply defaults
| Behavior | Default |
|---|---|
| Required artifacts | Every artifact in the schema |
| Progress tracking | No tracked file |
| Agent guidance | Built-in apply guidance |
Complete example
name: review-first
version: 1
description: Proposal and implementation checklist
artifacts:
- id: proposal
generates: proposal.md
description: Why the change is needed and what it affects
template: proposal.md
instruction: |
Explain the problem, the proposed change, and its impact.
requires: []
- id: tasks
generates: tasks.md
description: Trackable implementation checklist
template: tasks.md
instruction: |
Break the approved proposal into ordered implementation tasks.
requires:
- proposal
apply:
requires:
- tasks
tracks: tasks.md
instruction: |
Work through the pending tasks and mark each one complete.Validation
openspec schema validate <name> checks:
- Field types and required fields
- Relative paths
- Artifact IDs, dependencies, and cycles
apply.requiresIDs: each must be an artifact in the schema- Template files
A schema with an unknown apply.requires ID doesn't load, so every command that uses it reports the error.
Validation warns, without failing, when apply.tracks isn't exactly equal to some artifact's generates value. OpenSpec finds the tracked artifact by comparing those two strings, so anything else leaves it unable to tell which artifact's progress the file belongs to. That includes a typo like task.md, and also tracks: tasks/main.md against generates: tasks/*.md, where the glob does produce the file but the strings still differ. Apply keeps reading the file either way, but openspec list and openspec status count tasks.md instead.
Validation doesn't catch these mistakes:
| Mistake | What happens |
|---|---|
A field is misspelled, such as instrution | OpenSpec ignores it. Validation doesn't report the typo. |
name differs from the schema directory | Validation passes. OpenSpec still uses the directory name for lookup. |