Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
cbb38f3
docs(stores): add initiatives guide + a real example
clay-good Jun 30, 2026
e179ae4
docs(stores): show an initiative as a collection of artifact types
clay-good Jun 30, 2026
8825ed2
docs(stores): add one-pager artifact type + a completed example graph
clay-good Jun 30, 2026
4aa2ebe
docs(stores): add a "Where this could go" section
clay-good Jun 30, 2026
9288424
docs(stores): rework initiatives prototype around the define-your-own…
clay-good Jul 1, 2026
2e1ce30
docs(stores): lock initiative precedence to canonical-store/local-shadow
clay-good Jul 1, 2026
7324d11
feat(stores): working prototype — store-aware schemas, initiative rol…
clay-good Jul 1, 2026
84681ba
feat(stores): surface a store's artifact types + initiatives in the a…
clay-good Jul 1, 2026
567456a
feat(stores): surface a store's artifact types + initiatives in `open…
clay-good Jul 1, 2026
44223bc
docs(stores): reflect that cross-repo artifact/initiative discovery n…
clay-good Jul 1, 2026
74e7360
feat(stores): add `openspec new initiative` thin scaffold
clay-good Jul 1, 2026
dec9652
docs(stores): use `openspec new initiative` in the guide's happy path
clay-good Jul 1, 2026
f3a5767
feat(stores): roll up initiative status across repos (cross-repo)
clay-good Jul 2, 2026
f0164d2
feat(stores): the plan folder — one clean prototype for work above a …
clay-good Jul 2, 2026
f6fe4c6
feat(stores): make the plan destination-first
clay-good Jul 2, 2026
66f6fed
fix(stores): surface destination-only plans in agent context
clay-good Jul 2, 2026
9cda627
feat(stores): the handoff — capture, decompose, hand off through changes
clay-good Jul 2, 2026
f90fb62
docs(stores): point the plan guide at worksets and schemas
clay-good Jul 2, 2026
8c7c25e
feat(stores): initiatives — a portfolio of finite work above evergree…
clay-good Jul 6, 2026
5ee8f92
Merge branch 'main' of https://github.com/Fission-AI/OpenSpec into do…
clay-good Jul 6, 2026
72c437b
fix(stores): pass projectRoot to task progress after merging main
clay-good Jul 6, 2026
bcf9c22
Merge branch 'main' of https://github.com/Fission-AI/OpenSpec into do…
clay-good Jul 8, 2026
a81ef23
fix(tests): reconcile workflow list and golden hashes after merging main
clay-good Jul 8, 2026
e9dff7d
feat(stores): encode PM → engineering handoffs as pull-based stage tr…
clay-good Jul 8, 2026
ba07f5a
fix(tests): bump skill-generation template counts to 13 after update-…
clay-good Jul 8, 2026
2f682ed
refactor(stores): make stage workflows fully persona-agnostic
clay-good Jul 8, 2026
74f2c17
feat(stores): close the dogfooded gaps — discovery on link, the upstr…
clay-good Jul 9, 2026
5dfdd78
feat(stores): teach the initiatives layout in the empty states
clay-good Jul 9, 2026
f588309
feat(stores): dead-simple team path — three commands, all wiring auto…
clay-good Jul 9, 2026
a6e2e30
fix(tests): set USERPROFILE alongside HOME in the default-path setup …
clay-good Jul 9, 2026
acb792d
refactor(stores): dissolve initiatives into typed changes + serves links
clay-good Jul 13, 2026
6c7ee0e
test(stores): retarget suite to serves links, downstream rollup, sche…
clay-good Jul 13, 2026
5b5b8f7
chore(stores): drop stale initiative-era exploration notes and update…
clay-good Jul 13, 2026
428b254
feat(stores): make the happy path one command deep
clay-good Jul 13, 2026
6d67c21
docs(stores): teach the happy path in the upstream-work guide and cha…
clay-good Jul 13, 2026
3b20c64
fix(stores): dogfood round findings — legacy string refs readable, ro…
clay-good Jul 13, 2026
4684edf
docs(stores): integrate upstream work into the beta guide, CLI refere…
clay-good Jul 13, 2026
e63ff98
chore: merge main (docs deploy workflow, release skill, v1.6.0 packag…
clay-good Jul 13, 2026
f4d35c5
refactor(schemas): fold scaffolding into schema init; seed spec Purpo…
clay-good Jul 13, 2026
1ec6c8f
docs(stores): state the any-format contract and the validate seam hon…
clay-good Jul 13, 2026
0948f02
fix(validate): stop demanding delta specs from spec-less workflow sch…
clay-good Jul 13, 2026
6737f23
feat(stores): stateless --scan for the rollup — the CI pattern now ru…
clay-good Jul 13, 2026
985d895
fix(stores): close the fresh-eyes findings from two independent sessions
clay-good Jul 13, 2026
f7c1d65
feat(schemas): sharpen the requirements workflow with deferrals, sign…
clay-good Jul 14, 2026
5ebeb86
feat(stores): divergence rule in the upstream block — intent stays ho…
clay-good Jul 14, 2026
714adad
feat(stores): executable structure + one door
clay-good Jul 14, 2026
981835a
docs(stores): bring the change record and every guide current with th…
clay-good Jul 14, 2026
a77d697
docs(stores): align the upstream-work guide vocabulary with the PR fr…
clay-good Jul 14, 2026
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
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ That second one matters more than it looks. OpenSpec has two halves: a command l
| Doc | What it gives you |
|-----|-------------------|
| [Stores: User Guide](stores-beta/user-guide.md) | Plan in its own repo when your work spans repos or teams |
| [Initiatives](stores-beta/initiatives.md) | Define your own planning artifacts and share them in a store every repo can read |
| [Agent Contract](agent-contract.md) | The machine-readable CLI surfaces agents drive |

## The thirty-second version
Expand Down
13 changes: 8 additions & 5 deletions docs/agent-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Successful JSON payloads embed the root:
## 4. Command JSON shapes

### 4.1 `list --json`
`{ "changes": [ { "name", "completedTasks", "totalTasks", "lastModified", "status": "no-tasks"|"complete"|"in-progress" } ], "root": RootOutput }` — note the per-change `status` is a string enum here. `--specs`: `{ "specs": [ { "id", "requirementCount" } ], "root" }`.
`{ "changes": [ { "name", "completedTasks", "totalTasks", "lastModified", "status": "no-tasks"|"complete"|"in-progress" } ], "root": RootOutput }` — note the per-change `status` is a string enum here. `--specs`: `{ "specs": [ { "id", "requirementCount" } ], "root" }`. `--initiatives`: `{ "initiatives": [ { "id", "title", "changes": [string], "changeStatuses": [ { "id", "store"?, "completedTasks", "totalTasks", "state": "complete"|"in-progress"|"no-tasks"|"not-found" } ], "changesComplete", "changesTotal", "tasksComplete", "tasksTotal", "stores": [string], "shadowsStore"? } ], "root" }`. Each change lives in the initiative's own root, or — when its manifest entry is `{ id, store }` — in that registered store's root; `changeStatuses[].store` names it, `stores` is the distinct set (cross-repo), and `not-found` means the change (or its named store) is missing. `shadowsStore` is the id of a referenced store whose canonical initiative this local one shadows.

### 4.2 `show <item> --json`
Change: `{ "id", "title", "deltaCount", "deltas": [...], "root" }`. Spec: `{ "id", "title", "overview", "requirementCount", "requirements": [...], "metadata": { "version", "format", "sourcePath"? }, "root" }`.
Expand All @@ -59,28 +59,31 @@ Change: `{ "id", "title", "deltaCount", "deltas": [...], "root" }`. Spec: `{ "id
### 4.5 `instructions <artifact> --json`
`{ "changeName", "artifactId", "schemaName", "changeDir", "planningHome"?, "outputPath", "resolvedOutputPath", "existingOutputPaths", "description", "instruction"?, "context"?, "rules"?, "references"?: ReferenceIndexEntry[], "template", "dependencies": [{id,done,path,description}], "unlocks", "root" }`.

`ReferenceIndexEntry`: `{ "store_id", "root"?, "specs"?: [{id,summary}], "fetch"?, "status": [] }` — resolved entries carry root/specs/fetch; unresolved carry store_id + warning status. Index capped at 50KB (`reference_index_truncated`).
`ReferenceIndexEntry`: `{ "store_id", "root"?, "specs"?: [{id,summary}], "schemas"?: [{id,summary,artifacts}], "initiatives"?: [{id,summary}], "fetch"?, "status": [] }` — resolved entries carry root/specs/fetch; `schemas` (the store's own project-local artifact types) and `initiatives` are present only when the store defines them; unresolved carry store_id + warning status. Index capped at 50KB (`reference_index_truncated`).

### 4.6 `instructions apply --json`
`{ "changeName", "changeDir", "schemaName", "contextFiles": { "<artifactId>": ["/abs", ...] }, "progress": {total,complete,remaining}, "tasks": [{id,description,done}], "state": "blocked"|"all_done"|"ready", "missingArtifacts"?, "instruction", "references"?, "root" }`.

### 4.7 `new change <name> --json`
Success: `{ "change": { "id", "path", "metadataPath", "schema" }, "root" }`. Failure: `{ "change": null, "status": [d] }`, exit 1.

### 4.7a `new initiative <name> --json`
Success: `{ "initiative": { "id", "path", "manifestPath", "title" }, "root" }`. Failure: `{ "initiative": null, "status": [d] }`, exit 1.

### 4.8 `archive <name> --json`
Success: `{ "archive": { "change", "archivedAs": "YYYY-MM-DD-name", "path", "specsUpdated", "totals"? }, "root" }`. Failure: `{ "archive": null, "root"?, "status": [d] }`, exit 1. JSON mode is strictly non-interactive: every prompt point becomes an `archive_*` code.

### 4.9 `doctor --json`
`{ "root": { "path", "source", "store_id"?, "healthy", "status": [] }, "store": { "id", "metadata": {present,valid,remote?}, "origin_url"?, "status": [] } | null, "references": [...], "status": [] }`. Health findings of any severity exit 0. Failure payload: `{ "root": null, "store": null, "references": [], "status": [d] }`, exit 1.

### 4.10 `context --json`
`{ "root": { "path", "source", "store_id"?, "role": "openspec_root" }, "members": [ { "role": "referenced_store", "id", "path"?, "remote"?, "fetch"?, "status": [] } ], "status": [] }`. AVAILABLE = path present AND status empty. `--code-workspace <path>` writes `{folders:[{name,path}]}` (available referenced stores only, `ref:` prefixes); in JSON mode the write runs before printing so stdout holds exactly one document even on write failure. Failure: `{ "root": null, "members": [], "status": [d] }`, exit 1.
`{ "root": { "path", "source", "store_id"?, "role": "openspec_root" }, "members": [ { "role": "referenced_store", "id", "path"?, "remote"?, "fetch"?, "artifactTypes"?: [string], "initiatives"?: [string], "status": [] } ], "status": [] }`. AVAILABLE = path present AND status empty. `artifactTypes` (the store's own project-local schema names) and `initiatives` are present only on available members whose store defines them. `--code-workspace <path>` writes `{folders:[{name,path}]}` (available referenced stores only, `ref:` prefixes); in JSON mode the write runs before printing so stdout holds exactly one document even on write failure. Failure: `{ "root": null, "members": [], "status": [d] }`, exit 1.

### 4.11 `store ... --json`
setup/register: `{ "store": {id, root, metadata_path?}, "registry": {path, registered, already_registered}, "git": {is_repository, initialized, committed}, "created_files": [], "status": [] }`. unregister/remove: `{ "store", "registry": {path, removed}, "files": {deleted, deleted_path, left_on_disk}, "status": [] }`. list: `{ "stores": [{id, root}], "status": [] }`. doctor: `{ "stores": [ { id, root, metadata_path?, openspec_root: {...healthy, status}, metadata: {present, valid, id?, remote}, git: {is_repository, has_commits, has_uncommitted_changes, has_remote, origin_url}, status } ], "status": [] }` (`null` = unknown/not probed). Health findings exit 0; failures exit 1 with the matching null-shape. Prompt cancellation exits 130.

### 4.12 `schemas --json` / `templates --json`
`schemas`: bare array `[ {name, description, artifacts, source} ]`. `templates`: keyed object `{ "<artifactId>": {path, source} }`. Both cwd-based, no root/status keys.
`schemas`: bare array `[ {name, description, artifacts, source} ]` — supports `--store <id>` to list a store's schemas (success stays a bare array; a store-resolution failure emits `{status: [...]}` like other commands). `templates`: keyed object `{ "<artifactId>": {path, source} }`, cwd-based, no `--store`.

## 5. Exit-code contract

Expand Down Expand Up @@ -133,5 +136,5 @@ Recorded by the capstone audit; published-key renames are product decisions defe
4. Four parallel envelope type declarations exist in src; archive diagnostics never carry `target`.
5. `list --json` reuses the `status` key as a string enum per change.
6. Only `validate` output carries a `version` field.
7. `schemas`/`templates` ignore root selection (cwd-based, no `--store`).
7. `schemas` honors root selection (`--store <id>` lists a store's schemas); `templates` is still cwd-based (no `--store`).
8. Deprecated noun forms (`change`/`spec` subcommands) emit unenveloped payloads without `root`/`status`.
221 changes: 221 additions & 0 deletions docs/stores-beta/initiatives.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
# Initiatives: your plan, your artifacts, shared across repos

> **Beta.** This builds on [stores](user-guide.md). Names and file shapes may
> change between releases.

## The one idea

Kiro hands you `requirements → design → tasks`. Spec-Kit hands you
`spec → plan → tasks`. You use the artifacts they picked.

OpenSpec is different:

> **You define the artifacts your team actually uses — a brief, a persona, a
> decision record, anything — and share them in one place every repo can read.**

That one place is a **store**. The plan that lives there is an **initiative**.

## What an initiative is

An **initiative** is the home for a big effort — work that is too large for a
single change.

It holds three things:

- **the brief** — what you are doing, and why
- **the artifacts you choose** — personas, decision records, whatever your team
works from
- **the changes** that carry it out — each one still a normal OpenSpec change,
with live status

One effort. One home. Read by every repo that needs it.

```text
acme-plans (a store: planning in its own repo)
openspec/initiatives/
smoother-setup/
initiative.yaml the title, and the changes it groups
brief.md what this is, and why
personas/ who we build for ← your own artifact types
decisions/ the calls we made ← your own artifact types
```

## Two ways to use it: solo, or across repos

The *same* initiative works whether you are one person in one repo or a team
across many. The only thing that changes is where the grouped changes live.

**Solo — one repo, one machine.** Keep the initiative in your own repo. Its
changes are your normal changes, right beside it. The manifest just lists them:

```yaml
# openspec/initiatives/smoother-setup/initiative.yaml
title: Smoother setup
changes:
- simplify-skill-installation
- add-global-install-scope
```

```text
$ openspec list --initiatives
smoother-setup 2/4 changes complete
```

Nothing else to set up. This is the whole story for a solo dev.

**Across repos — a store, a team.** The plan lives in a store; the work is
implemented in several code repos. Each change entry says which repo it lives
in (any registered store id), and the status rolls up across all of them:

```yaml
# team-plans/openspec/initiatives/payments-launch/initiative.yaml
title: Payments launch
changes:
- { id: add-payments-api, store: api-server }
- { id: add-payments-ui, store: web-app }
- update-docs # lives here, in the store
```

```text
$ openspec list --initiatives --store team-plans
payments-launch 2/5 changes complete across api-server, web-app
✓ add-payments-api api-server 5/5 tasks
· add-payments-ui web-app 1/3 tasks
✓ update-docs here 2/2 tasks
? add-refunds web-app not found
```

One command answers "where does the whole effort stand?" — across every repo,
with each change's home shown next to it.

## The happy path

*A team is making setup smoother. The work spans a CLI repo and a docs repo.
The plan should not live in either one.*

### 1. Put the plan in a store, and start an initiative

A store is planning in its own git repo. Stand one up once, then scaffold the
initiative inside it:

```bash
openspec store setup acme-plans --path ~/openspec/acme-plans
openspec new initiative smoother-setup --store acme-plans --title "Smoother setup"
```

Now the plan has a home of its own — an `initiative.yaml` and a `brief.md`,
not buried in anyone's code.

### 2. Define your own artifacts

This is the superpower. Your team works from personas and decision records, so
make those first-class. Describe them once, in a small **schema**:

```yaml
# acme-plans/openspec/schemas/initiative/schema.yaml
artifacts:
- id: brief # what and why
- id: persona # who we build for
- id: decision # a call we made, and the trade-off
```

These are *your* artifact types — labeled in your words. OpenSpec knows them and
lists them like any other schema, from any repo that can reach the store:

```bash
openspec schemas --store acme-plans
```

```text
Available schemas:

spec-driven
Default OpenSpec workflow - proposal → specs → design → tasks
Artifacts: proposal → specs → design → tasks

team-brief (project)
Our own planning artifacts — a brief, then a decision record.
Artifacts: brief → decision
```

### 3. Group the changes it takes

The initiative names the changes that carry it out. Each change is a normal
OpenSpec change — nothing new to learn. You never track status by hand; ask
OpenSpec:

```bash
openspec list --initiatives --store acme-plans
```

```text
Initiatives:
smoother-setup 2/4 changes complete
```

One command. Where the whole effort stands.

### 4. Every repo reads it — nothing copied

Each code repo adds one line to its `openspec/config.yaml`:

```yaml
references:
- acme-plans
```

Now the coding agent in *that* repo sees the shared plan — the brief, the
personas, the decisions, the changes — and builds against it. No pasting. No
drift. The plan is read by name, live from the store.

That is the whole happy path: **your store, your artifacts, read by every
repo, with live status.**

## When two initiatives collide

The question every team hits: the store has an initiative called
`smoother-setup`, and someone starts a local one by the same name in their own
repo. Which wins?

**The rule: the store is canonical.** The store holds the shared, agreed-upon
initiative. A local one with the same name is treated as a *draft that shadows
it* — OpenSpec keeps letting you work locally, but tells you plainly, right in
the list:

```text
Initiatives:
smoother-setup 2/4 changes complete (shadows: acme-plans)
```

Nothing diverges silently. You always know there is a shared source of truth,
and you can reconcile when you are ready. (This mirrors how OpenSpec already
handles schemas: a project schema *shadows* a package one, and `openspec schema
which` shows you it is happening.)

## What works in this prototype

This is a working prototype — every command above runs today:

- **Your own artifact types, discoverable across the store boundary.**
`openspec schemas --store <id>` lists a store's custom schemas from any repo.
- **Initiatives with live, rolled-up status — solo or across repos.**
`openspec list --initiatives` reads each initiative's manifest and rolls up
the status of the changes it groups, from the same source as
`openspec list --changes`. When a change lives in another repo (`{ id, store }`),
the rollup resolves it there and aggregates — one number for the whole effort,
with each change's home shown next to it.
- **Canonical-vs-shadow precedence, enforced.** A local initiative that shares an
id with one in a referenced store is reported as a shadow — never silently
overriding it, never blocking your local work.
- **Read by name via `references:`.** A repo declares the store once, and its
coding agent sees the store's artifact types and initiatives right in its
context — in the instruction block and in `openspec context` — each with a
one-line summary and the command to fetch it. Nothing is copied.

Still a prototype: the initiative folder is a light convention (an
`initiative.yaml` manifest — not a revived command group). A change in another
repo is named explicitly (`{ id, store }`); OpenSpec does not auto-discover
which repos a store's changes live in.

Start simple: one initiative folder in a store, grouping a few real changes,
with the artifacts your team already uses.
7 changes: 4 additions & 3 deletions docs/stores-beta/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,10 @@ tells you which case you're in.
- **No sync, ever — by design.** OpenSpec never clones, pulls, or pushes.
A stale checkout shows stale specs until *you* pull; references are
indexed live from whatever is on disk.
- **Some commands stay where they are.** `view`, `templates`, `schemas`,
and the deprecated noun forms (`openspec change show`, ...) act on the
current directory only — no `--store`.
- **Some commands stay where they are.** `view`, `templates`, and the
deprecated noun forms (`openspec change show`, ...) act on the current
directory only — no `--store`. (`schemas` now accepts `--store` — see the
[initiatives guide](initiatives.md).)
- **Per-machine state is per-machine.** The store registry and worksets
are local settings. Nothing about your machine's layout is
ever committed to shared planning.
Expand Down
Loading
Loading