Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 59 additions & 13 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The OpenSpec CLI (`openspec`) provides terminal commands for project setup, vali
| **Validation** | `validate` | Check changes and specs for issues |
| **Lifecycle** | `archive` | Finalize completed changes |
| **Workflow** | `new change`, `status`, `instructions`, `templates`, `schemas` | Artifact-driven workflow support |
| **Schemas** | `schema init`, `schema fork`, `schema validate`, `schema which` | Create and manage custom workflows |
| **Schemas** | `schema init`, `schema fork`, `schema override`, `schema validate`, `schema which` | Create and manage custom workflows |
| **Config** | `config` | View and modify settings |
| **Utility** | `feedback`, `completion` | Feedback and shell integration |

Expand Down Expand Up @@ -887,12 +887,14 @@ openspec templates --json

```
Schema: spec-driven
Source: package + user overlay

Templates:
proposal → ~/.openspec/schemas/spec-driven/templates/proposal.md
specs → ~/.openspec/schemas/spec-driven/templates/specs.md
design → ~/.openspec/schemas/spec-driven/templates/design.md
tasks → ~/.openspec/schemas/spec-driven/templates/tasks.md
proposal:
Path: /usr/local/lib/node_modules/@fission-ai/openspec/schemas/spec-driven/templates/proposal.md
Source: package
tasks:
Path: /home/user/.local/share/openspec/schemas/spec-driven/templates/tasks.md
Source: user
```

---
Expand Down Expand Up @@ -1019,6 +1021,39 @@ openspec schema fork <source> [name] [options]
openspec schema fork spec-driven my-workflow
```

When the source has an active layered user override, the fork materializes the effective schema and effective user/package templates into a self-contained project bundle.

---

### `openspec schema override`

Create a layered user override for a packaged schema. Unlike `schema fork`, this command does not copy `schema.yaml` or its templates; packaged updates remain active for fields and templates you do not override.

```text
openspec schema override <name> [options]
```

**Arguments:**

| Argument | Required | Description |
|----------|----------|-------------|
| `name` | Yes | Packaged schema to customize |

**Options:**

| Option | Description |
|--------|-------------|
| `--force` | Replace an existing layered override with a new starter file |
| `--json` | Output `created`, `schema`, `path`, and `basePath` as JSON; adds `projectSchemaTakesPrecedence: true` when the current project shadows the new override |

**Example:**

```bash
openspec schema override spec-driven
```

This creates `schema.override.yaml` in the user OpenSpec data directory. See [Global Overrides](customization.md#global-overrides) for the patch format, template fallback, and platform-specific paths.

---

### `openspec schema validate`
Expand Down Expand Up @@ -1058,7 +1093,7 @@ openspec schema validate

Show where a schema resolves from (useful for debugging precedence).

```
```text
openspec schema which [name] [options]
```

Expand All @@ -1082,18 +1117,29 @@ openspec schema which [name] [options]
openspec schema which spec-driven
```

**Output:**
**Package-only output:**

```text
Schema: spec-driven
Source: package
Path: /usr/local/lib/node_modules/@fission-ai/openspec/schemas/spec-driven
```
spec-driven resolves from: package
Source: /usr/local/lib/node_modules/@fission-ai/openspec/schemas/spec-driven

**Layered output:**

```text
Schema: spec-driven
Source: package + user overlay
Path: /usr/local/lib/node_modules/@fission-ai/openspec/schemas/spec-driven
Overlay: /home/user/.local/share/openspec/schemas/spec-driven/schema.override.yaml
```

**Schema precedence:**

1. Project: `openspec/schemas/<name>/`
2. User: `~/.local/share/openspec/schemas/<name>/`
3. Package: Built-in schemas
1. Complete project schema: `openspec/schemas/<name>/schema.yaml`
2. Complete user schema: `~/.local/share/openspec/schemas/<name>/schema.yaml`
3. Packaged schema plus optional user `schema.override.yaml`
4. Packaged schema unchanged

---

Expand Down
129 changes: 128 additions & 1 deletion docs/customization.md
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,134 @@ Path: /path/to/project/openspec/schemas/my-workflow

---

> **Note:** OpenSpec also supports user-level schemas at `~/.local/share/openspec/schemas/` for sharing across projects, but project-level schemas in `openspec/schemas/` are recommended since they're version-controlled with your code.
## Global Overrides

OpenSpec has two user-level customization modes. Choose one mode per schema name:

| Mode | File | Update behavior |
|------|------|-----------------|
| **Layered override** | `schema.override.yaml` | Keeps packaged fields and templates unless explicitly changed |
| **Complete replacement** | `schema.yaml` plus `templates/` | Freezes a self-contained copy that fully shadows the package |

User schemas live under the OpenSpec data directory:

- `$XDG_DATA_HOME/openspec/schemas/` when `XDG_DATA_HOME` is set
- `~/.local/share/openspec/schemas/` on Unix and macOS by default
- `%LOCALAPPDATA%\openspec\schemas\` on Windows by default

In the directory examples below, `<OpenSpec data directory>` means
`$XDG_DATA_HOME/openspec`, `~/.local/share/openspec`, or
`%LOCALAPPDATA%\openspec`, depending on the platform and environment.

Project schemas in `openspec/schemas/` remain higher priority than either user mode because they represent version-controlled team intent.

### Layered Global Customization

Create a starter override for a packaged schema:

```bash
openspec schema override spec-driven
```

This creates only:

```text
<OpenSpec data directory>/schemas/spec-driven/
└── schema.override.yaml
```
Comment thread
coderabbitai[bot] marked this conversation as resolved.

The packaged `schema.yaml` remains the base. For example, keep OpenSpec's task guidance and append personal rules:

```yaml
patchVersion: 1

artifacts:
tasks:
instruction:
append: |
Additional rules:
- Include verification commands in every task group.
- Mention the affected package in each task.
```

Text fields use explicit operations:

```yaml
artifacts:
tasks:
instruction:
prepend: Read the repository contribution guide first.
append: Include focused and full verification commands.
```

`prepend` and `append` may be combined. Use `replace` by itself only when you intend to discard the packaged instruction:

```yaml
artifacts:
tasks:
instruction:
replace: Write tasks using my personal workflow.
```

Plain `description`, `generates`, and `template` values replace the matching packaged value. Dependency lists use explicit operations:

```yaml
artifacts:
tasks:
requires:
remove: [design]
add: [proposal]
```

Use either `replace`, or `add`/`remove`, for one dependency field. Layered overrides modify existing artifacts only; use a complete schema fork to add, remove, or reorder artifacts.

### Optional Template Overrides

You do not need to copy the packaged templates. Add only the templates you want to replace:

```text
<OpenSpec data directory>/schemas/spec-driven/
├── schema.override.yaml
└── templates/
└── tasks.md # user version
```

For a layered schema, each template resolves independently:

1. User `templates/<file>`
2. Packaged `templates/<file>`

In this example, `tasks.md` is user-owned while proposal, specs, and design templates continue following package updates. Template files are whole-file replacements; their Markdown contents are not merged.

### Complete Global Replacement

The existing global replacement behavior remains available. Copy a complete schema bundle to the user data directory:

```text
<OpenSpec data directory>/schemas/spec-driven/
├── schema.yaml
└── templates/
├── proposal.md
├── spec.md
├── design.md
└── tasks.md
```

This directory is self-contained. It receives no packaged schema or template updates, and missing templates do not fall back to the package. You must manually compare and rebase it when OpenSpec changes the built-in workflow.

Do not put `schema.yaml` and `schema.override.yaml` in the same user schema directory. OpenSpec rejects that conflict instead of guessing which customization you intended.

### Inspect and Validate

```bash
openspec schema which spec-driven
openspec schema validate spec-driven
openspec templates --schema spec-driven
```

For a layered schema, `which` reports both package and user paths, validation checks the composed schema and every effective template, and `templates` shows whether each concrete template came from the user or package directory.

If you later need structural changes, `openspec schema fork spec-driven my-workflow` materializes the effective packaged-plus-user schema and templates into a self-contained project schema.

---

Expand Down
5 changes: 4 additions & 1 deletion docs/opsx.md
Original file line number Diff line number Diff line change
Expand Up @@ -583,14 +583,17 @@ openspec schema init my-workflow
# Or fork an existing schema as a starting point
openspec schema fork spec-driven my-workflow

# Or add personal guidance while retaining packaged updates
openspec schema override spec-driven

# Validate your schema structure
openspec schema validate my-workflow

# See where a schema resolves from (useful for debugging)
openspec schema which my-workflow
```

Schemas are stored in `openspec/schemas/` (project-local, version controlled) or `~/.local/share/openspec/schemas/` (user global).
Schemas are stored in `openspec/schemas/` (project-local, version controlled) or `~/.local/share/openspec/schemas/` (user global). A user `schema.yaml` is a complete replacement; a user `schema.override.yaml` is layered over the packaged schema and may provide only selected templates. See [Customization](customization.md#global-overrides).

**Schema structure:**
```
Expand Down
30 changes: 30 additions & 0 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,36 @@ openspec schema init <name> # create a custom one

See [Customization](customization.md#custom-schemas).

### My global schema stopped receiving built-in updates

A user-level `schema.yaml` is a complete replacement. Its schema and templates intentionally shadow the packaged bundle, so OpenSpec cannot automatically apply newer built-in guidance.

If you only need additive personal customization, use a layered override instead:

1. Back up the complete user schema, then move or rename its `schema.yaml` outside
the active user schema directory.
2. Create the layered override:

```bash
openspec schema override spec-driven
```

3. Port supported customizations into `schema.override.yaml`, keep only templates
you intentionally replace, and remove the old complete `schema.yaml` after
preserving any custom content you still need.
4. Check the effective result:

```bash
openspec schema validate spec-driven
openspec schema which spec-driven
```

See [Global Overrides](customization.md#global-overrides).

### Complete replacement conflicts with layered override

One user schema directory cannot contain both `schema.yaml` and `schema.override.yaml`. Keep `schema.yaml` for a self-contained frozen workflow, or keep `schema.override.yaml` to inherit packaged updates. `openspec schema which <name>` shows which source is active.

## Migration from the legacy workflow

### "Legacy files detected in non-interactive mode"
Expand Down
2 changes: 2 additions & 0 deletions openspec/changes/add-global-schema-overlays/.openspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-08-17
Loading
Loading