mirror of
https://github.com/Fission-AI/OpenSpec.git
synced 2026-10-03 22:13:19 +08:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8fd65b4947 |
@@ -1,46 +0,0 @@
|
||||
---
|
||||
name: draft-openspec-docs
|
||||
description: Collaborative page-drafting mode for the OpenSpec docs. Builds a scratch plan inside the target page (purpose, structure, numbered draft steps), iterates on it with the user, then drafts one section per approved step and cleans up after itself. Use when a page needs a from-scratch rewrite or a new page is being shaped with the user in the loop.
|
||||
argument-hint: target page
|
||||
---
|
||||
|
||||
# Draft OpenSpec docs (scratch-plan workflow)
|
||||
|
||||
You are shaping a docs page with the user in the loop. The page is planned and reviewed inside the page itself, then drafted one section at a time. Load `write-openspec-docs` (the style authority) and `no-ai-slop` before drafting anything.
|
||||
|
||||
## 1. Set up the scratch section
|
||||
|
||||
Strip the page to its title and `>` goal line, then add a working section below them:
|
||||
|
||||
```md
|
||||
## Scratch: page plan (delete before publish)
|
||||
|
||||
### Purpose
|
||||
|
||||
### Structure
|
||||
```
|
||||
|
||||
- **Purpose**: 3-5 dot points. Who the reader is and what they come to look up, what the page covers, what it links out to. Check `docs-lab/README.md` (the page's goal line) and `docs-lab/message-map.md` (the questions routed here) before writing it.
|
||||
- **Structure**: a numbered list of the page's sections, one line each naming the section and the shape of its content (table, fence, tree, bullets).
|
||||
- Say what the page will do, never what it won't. Plain words and short bullets; the user reads this in their editor.
|
||||
|
||||
## 2. Iterate until the plan is approved
|
||||
|
||||
- Plan edits are cheap; page edits aren't. Reshape the plan as many times as the user asks before drafting.
|
||||
- Record every decision in the plan itself, not only in chat. Add a `### Notes` list for follow-ups that belong to other pages and product observations found along the way.
|
||||
- The user may edit the file directly between turns; their edits are decisions, not drift to revert.
|
||||
- Surface one open call at a time, with a recommendation.
|
||||
|
||||
## 3. Add the draft plan, then draft step by step
|
||||
|
||||
Once the structure holds, add a `### Draft plan` below the notes: one step per page section, each with an ID and a readable title (`**D1. Goal line and intro**`), ending with a consolidation step (cross-page updates) and a cleanup step. Then:
|
||||
|
||||
- Wait for the user to call a step ID. Draft exactly that step, into the page above the scratch block.
|
||||
- Verify each fact against source before writing it; a cheap grep beats trust. Reference content shows the raw contract (templates, instructions, config) verbatim in fences, linked to the file on GitHub, rather than paraphrasing it.
|
||||
- Keep sibling sections on a repeatable sub-structure so the page scans as one system.
|
||||
- Mark the step `(done)` in the plan, report what landed, and name the next step.
|
||||
|
||||
## 4. Consolidation and cleanup
|
||||
|
||||
- **Consolidation**: update everything that points at the page. The README goal line (verbatim match with the page's `>` line), the message map, the sync config (`website/docs.sync.config.mjs`), and any cross-links found by grepping the tree. Run `node website/scripts/sync-docs.mjs` to validate.
|
||||
- **Cleanup**: delete the scratch block, run the retrievability and glance tests from `write-openspec-docs` at desktop and narrow widths, and flip the page's message-map row to Answered if its prose landed.
|
||||
@@ -1,180 +0,0 @@
|
||||
---
|
||||
name: release-openspec
|
||||
description: >-
|
||||
Use this skill when releasing OpenSpec: audit merged work and changeset
|
||||
coverage, decide whether a catch-up changeset PR is needed, prepare or resume
|
||||
the Changesets Version Packages PR, cut a beta or stable release, verify
|
||||
publishing, and polish GitHub release notes. Also use when asked whether an
|
||||
open release PR is complete, what the next release step is, or to continue a
|
||||
release paused for human approval.
|
||||
---
|
||||
|
||||
# Release OpenSpec
|
||||
|
||||
Run the OpenSpec release workflow as a resumable state machine. Inspect live GitHub state on every invocation and take only the next safe action. Do not assume an earlier invocation completed.
|
||||
|
||||
## Principles
|
||||
|
||||
- Treat `Fission-AI/OpenSpec` and `origin/main` as the release source of truth.
|
||||
- Default to a read-only audit when the user asks for status, readiness, or advice.
|
||||
- Treat a request to release, prepare a release, continue, or resume as authorization to perform the applicable release actions.
|
||||
- Preserve the user's checkout. Never discard unrelated changes or switch their current branch just to prepare a changeset.
|
||||
- Use a temporary worktree from current `origin/main` for release-authored commits when the checkout is dirty or not on `main`.
|
||||
- Never approve your own PR. Human review is a deliberate gate.
|
||||
- Treat merge-queue entry as an intermediate state, not a merge. Advance only after GitHub reports `mergedAt` and the commit is present on `main`.
|
||||
- Never create the automated Version Packages PR manually. The Changesets action owns it.
|
||||
- Never push an empty commit merely to retrigger CI. Diagnose the failed or missing run first.
|
||||
- Report URLs, the state reached, and the exact human action needed whenever pausing.
|
||||
|
||||
## Know the two PR types
|
||||
|
||||
Keep these distinct in output and decisions:
|
||||
|
||||
- **Changeset PR**: A normal human-authored PR that adds one or more `.changeset/*.md` files. Prefer adding a changeset to the feature/fix PR; create a catch-up changeset PR only for already-merged work that should be included.
|
||||
- **Version Packages PR**: The automated `changeset-release/main` PR titled `chore(release): version packages`. Merging or adding changesets to `main` updates this same PR. Merging it publishes the stable release.
|
||||
|
||||
An open Version Packages PR does not prohibit a catch-up changeset PR. It means a catch-up PR is useful only when the audit finds missing release-worthy work. Once that PR merges, wait for the existing Version Packages PR to update.
|
||||
|
||||
## Start with a release audit
|
||||
|
||||
1. Verify the repository and tools:
|
||||
- Resolve the GitHub repository with `gh repo view --json nameWithOwner,url`.
|
||||
- Require authenticated `gh`, `git`, and `pnpm` before write actions.
|
||||
- Stop before release mutations if the canonical repository is not `Fission-AI/OpenSpec`.
|
||||
2. Refresh without modifying the worktree:
|
||||
|
||||
```bash
|
||||
git fetch origin main
|
||||
```
|
||||
|
||||
Do not fetch every tag indiscriminately. This repository may contain a conflicting historical local tag, which can make `git fetch --tags` fail even though `origin/main` fetched successfully.
|
||||
|
||||
3. Find the latest stable GitHub release. Exclude drafts and prereleases; do not use `git describe`, because a beta tag may be newer than the stable baseline.
|
||||
|
||||
```bash
|
||||
gh release list --repo Fission-AI/OpenSpec \
|
||||
--exclude-drafts --exclude-pre-releases --limit 100 \
|
||||
--json tagName,publishedAt \
|
||||
--jq 'max_by(.publishedAt) | {tagName, publishedAt}'
|
||||
```
|
||||
|
||||
Ensure that exact stable tag resolves locally before using it as a `git log` boundary. Fetch only that tag if it is missing. If a same-named local tag disagrees with the canonical remote, report the mismatch and use a separately resolved canonical commit; never force-rewrite the user's tag as part of an audit.
|
||||
|
||||
4. Find open release-related PRs:
|
||||
|
||||
```bash
|
||||
gh pr list --repo Fission-AI/OpenSpec --state open \
|
||||
--head changeset-release/main \
|
||||
--json number,title,headRefName,baseRefName,url,reviewDecision,statusCheckRollup
|
||||
```
|
||||
|
||||
Identify the Version Packages PR by `headRefName == "changeset-release/main"`, not title alone. Separately list likely changeset PRs and inspect their files; require positive additions to `.changeset/*.md`. Do not mistake the Version Packages PR's changeset deletions for authored changesets, and do not rely on titles because a feature/fix PR may add release tracking.
|
||||
5. Read the live release policy in `.changeset/README.md`, pending `.changeset/*.md` files on `origin/main`, and the Version Packages PR body/files when it exists.
|
||||
6. List first-parent commits since the latest stable tag:
|
||||
|
||||
```bash
|
||||
git log --first-parent --date=short \
|
||||
--pretty=format:'%h%x09%ad%x09%s' <stable-tag>..origin/main
|
||||
```
|
||||
|
||||
7. Map release-worthy merged PRs to existing changesets. Use PR files and changeset history; do not infer coverage from similar wording alone.
|
||||
8. Classify the audit as:
|
||||
- `missing-tracking`: user-facing work intended for this release lacks a changeset;
|
||||
- `awaiting-changeset-review`: a suitable changeset PR already exists;
|
||||
- `awaiting-merge-queue`: an approved changeset or Version Packages PR is queued but has not landed on `main`;
|
||||
- `awaiting-version-update`: required changesets are on `main`, but the Version Packages PR has not incorporated them;
|
||||
- `awaiting-version-review`: the Version Packages PR is current but lacks approval;
|
||||
- `ready-to-publish`: the Version Packages PR is current, approved, and green;
|
||||
- `publishing`: the Version Packages PR merged but artifacts are incomplete;
|
||||
- `needs-finalization`: npm, tag, and GitHub Release exist but notes are still raw;
|
||||
- `complete`: package, tag, GitHub Release, and polished notes agree.
|
||||
|
||||
Present a compact audit with the stable baseline, proposed version, covered changes, possible omissions, intentionally skipped internal/docs work, open PRs, and next action.
|
||||
|
||||
## Decide changeset coverage
|
||||
|
||||
Follow `.changeset/README.md` rather than assuming every merged PR needs a changeset.
|
||||
|
||||
Include work selected for release tracking, especially:
|
||||
|
||||
- new user-facing features or commands;
|
||||
- notable fixes or hotfixes;
|
||||
- breaking changes or deprecations;
|
||||
- user-visible performance improvements.
|
||||
|
||||
Normally skip documentation-only work, tests, CI/tooling, and internal refactors. Flag ambiguous user-visible changes instead of silently excluding them. Ask the user only when the ambiguity materially changes release scope or the semantic version; otherwise use best judgment and let PR review be the approval gate.
|
||||
|
||||
## Create or continue a changeset PR
|
||||
|
||||
Do this only for `missing-tracking`.
|
||||
|
||||
1. If an open changeset PR already covers the missing work, reuse it. Inspect its `headRefName`, head repository, and `maintainerCanModify`; fetch that exact head branch from its owning repository into a temporary worktree, make the update there, and push back to the same PR head. Stop if the branch is not writable. Do not create a duplicate PR or replacement branch.
|
||||
2. Read `.changeset/README.md` immediately before authoring.
|
||||
3. Only when no suitable PR exists, create a short `changeset-<scope>` branch from current `origin/main`. Use a temporary worktree so the operator's checkout remains untouched.
|
||||
4. Prefer one changeset per coherent release unit. A single catch-up changeset may summarize several small items selected for the same release.
|
||||
5. Use the exact package name `"@fission-ai/openspec"`, the highest required semantic bump, only relevant headings, and user-focused descriptions.
|
||||
6. Validate before pushing:
|
||||
|
||||
```bash
|
||||
pnpm exec changeset status
|
||||
```
|
||||
|
||||
7. Commit, push, and open a PR whose body lists the covered merged PRs and explains why the catch-up is needed.
|
||||
8. Stop after returning the PR URL and request human approval. Do not approve it yourself.
|
||||
|
||||
On a later invocation, if the PR is approved and checks are green, merge or enqueue it only when the user asked to continue or complete the release. If GitHub uses a merge queue, inspect `mergeQueueEntry`, queue checks, and `mergedAt`; remain in `awaiting-merge-queue` until the PR actually lands on `main`. Then wait for the Changesets action on `main` to update the existing Version Packages PR. Poll with concise progress updates; do not push an empty commit or another branch update, because that can dismiss approval and restart the queue.
|
||||
|
||||
## Validate the Version Packages PR
|
||||
|
||||
Before calling it ready:
|
||||
|
||||
1. Confirm it targets `main` from `changeset-release/main` and is generated by the expected automation.
|
||||
2. Enumerate every pending `.changeset/*.md` file on current `main`, excluding `.changeset/README.md`. Verify the PR consumes every one and contains the corresponding changelog content. If any pending changeset should be deferred, stop: remove or revise it through a separately reviewed change and wait for automation to regenerate the Version Packages PR before continuing.
|
||||
3. Fetch `baseRefOid` and `headRefOid` with `gh pr view`, require `baseRefOid` to equal current `origin/main`, and create clean detached temporary worktrees for both revisions. If the head object is missing locally, fetch the immutable `pull/<number>/head` ref first. Never validate from the operator's current worktree.
|
||||
4. In the base worktree, run `pnpm exec changeset status --output changeset-status.json` and read the expected package/version from that file. Install locked dependencies in the temporary worktree first if the Changesets CLI is unavailable.
|
||||
5. Compare the base status and complete pending-changeset set against the head worktree: `package.json`, `CHANGELOG.md`, removed changeset files, PR body, and proposed version must all agree. This is a base-to-head comparison because the head has already consumed the changesets and cannot calculate the pending release itself.
|
||||
6. Remove the temporary worktrees after validation, then inspect all required checks and review state with `gh pr view` / `gh pr checks`.
|
||||
|
||||
If current but unapproved, return the URL and pause for human approval. If approved and green, merge or enqueue only when the user asked to release or continue. With merge queue enabled, do not treat approval, auto-merge enablement, or queue entry as the stable publish trigger; wait for `mergedAt` and confirmation that the merge reached `main`.
|
||||
|
||||
## Verify stable publishing
|
||||
|
||||
After the Version Packages PR merges:
|
||||
|
||||
1. Find the release workflow run for the merge commit and wait for completion.
|
||||
2. Verify all three artifacts independently:
|
||||
- `npm view @fission-ai/openspec@<version> version`
|
||||
- remote tag `v<version>` points at the expected commit;
|
||||
- `gh release view v<version>` exists and is not a prerelease.
|
||||
3. If only some artifacts exist, report partial state and resume verification before retrying any publish action. Never republish a version already on npm.
|
||||
4. Once all artifacts exist, read [references/release-notes.md](references/release-notes.md), polish the GitHub Release, and verify the saved title/body.
|
||||
|
||||
## Cut a beta
|
||||
|
||||
Only enter this path when the user explicitly asks for a beta or prerelease.
|
||||
|
||||
1. Run the same audit and confirm pending changesets produce a next stable version.
|
||||
2. Explain that beta publishing does not consume changesets or replace the stable Version Packages PR.
|
||||
3. Trigger the existing `release-prepare.yml` workflow on `main`; do not calculate or set the beta version locally.
|
||||
4. Verify the workflow-selected version, npm `beta` dist-tag, remote tag, and prerelease GitHub Release.
|
||||
5. Do not merge the stable Version Packages PR as part of a beta request.
|
||||
|
||||
## Handle failures
|
||||
|
||||
- For failed CI, inspect the failing check and logs before proposing a rerun or code change.
|
||||
- For a stale Version Packages PR, first confirm a successful `push` run of `release-prepare.yml` occurred after the latest changeset reached `main`.
|
||||
- For branch divergence, let the Changesets action update its branch. Do not force-push `changeset-release/main`.
|
||||
- For a queued PR, inspect merge-group checks and queue state. Do not re-enqueue, update the branch, or rerun unrelated checks while it is progressing normally.
|
||||
- For a version that already exists on npm, stop and reconcile the tag/GitHub Release rather than incrementing or republishing implicitly.
|
||||
- For missing GitHub permissions or required review, report the exact gate and URL; preserve the detected state so the next invocation can resume by inspection.
|
||||
|
||||
## Completion report
|
||||
|
||||
Report:
|
||||
|
||||
- released version and stable/beta channel;
|
||||
- changeset PR and Version Packages PR URLs, when applicable;
|
||||
- release workflow result;
|
||||
- npm package, tag, and GitHub Release verification;
|
||||
- release-notes finalization status;
|
||||
- any intentionally deferred changes.
|
||||
@@ -1,4 +0,0 @@
|
||||
interface:
|
||||
display_name: "Release OpenSpec"
|
||||
short_description: "Audit, prepare, publish, and finalize releases"
|
||||
default_prompt: "Use $release-openspec to audit the current release state and take the next safe release step."
|
||||
@@ -1,89 +0,0 @@
|
||||
# GitHub release notes
|
||||
|
||||
Read this file only after the npm package, tag, and GitHub Release exist, or when the user explicitly asks to preview or polish release notes.
|
||||
|
||||
## Gather source material
|
||||
|
||||
1. Bind the release values once and fetch the current release. Replace the example values, but keep every expansion quoted:
|
||||
|
||||
```bash
|
||||
tag="vX.Y.Z"
|
||||
previous_tag="vA.B.C"
|
||||
gh release view "$tag" --repo Fission-AI/OpenSpec \
|
||||
--json body,name,isPrerelease,url
|
||||
```
|
||||
|
||||
2. For a stable release, find the preceding stable release by excluding drafts and prereleases. For a beta, compare against the preceding tag in the same beta series when one exists; otherwise compare against the latest stable release.
|
||||
3. Fetch GitHub-generated notes to recover first-time contributor attribution and the full changelog link:
|
||||
|
||||
```bash
|
||||
gh api repos/Fission-AI/OpenSpec/releases/generate-notes \
|
||||
-f "tag_name=$tag" -f "previous_tag_name=$previous_tag" -q '.body'
|
||||
```
|
||||
|
||||
4. Cross-check the final content against the released `CHANGELOG.md` section and the merged Version Packages PR. Never invent an item from commit titles alone.
|
||||
|
||||
## Title
|
||||
|
||||
Use:
|
||||
|
||||
```text
|
||||
<tag> - <one-to-four-word theme>
|
||||
```
|
||||
|
||||
Lead with the most notable user-facing addition. For two similarly important additions, comma-separate them. For a fix-only release, name the primary fixed area.
|
||||
|
||||
## Body
|
||||
|
||||
Use only the sections that contain content:
|
||||
|
||||
```markdown
|
||||
## What's New in <tag>
|
||||
|
||||
<One direct sentence describing the release theme.>
|
||||
|
||||
### New
|
||||
|
||||
- **Feature** - What users can now do and when it helps.
|
||||
|
||||
### Improved
|
||||
|
||||
- **Area** - What became easier, safer, faster, or more consistent.
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Area** - What now behaves correctly.
|
||||
|
||||
## New Contributors
|
||||
|
||||
* @username made their first contribution in #PR
|
||||
|
||||
**Full Changelog**: <compare-link>
|
||||
```
|
||||
|
||||
## Voice and cleanup
|
||||
|
||||
- Write for developers using OpenSpec with AI coding assistants.
|
||||
- Be direct and practical; avoid marketing language.
|
||||
- Lead with user capability or impact, not implementation.
|
||||
- Keep each item to one or two sentences.
|
||||
- Remove commit hashes, changeset wrappers, raw semantic-bump headings, and inline `Thanks @user` boilerplate.
|
||||
- Omit internal CI, test, and refactor details unless users experience the result.
|
||||
- Keep contribution credit in `New Contributors`, not inside feature bullets.
|
||||
- Preserve GitHub's first-contribution wording and PR link.
|
||||
- Exclude core maintainer `@TabishB` from `New Contributors`. If no external first-time contributors remain, omit that section.
|
||||
- Always retain the full changelog compare link.
|
||||
|
||||
## Apply and verify
|
||||
|
||||
Create a temporary file, write the body to it with the available file-editing tool, bind the final title, then update:
|
||||
|
||||
```bash
|
||||
notes_file="$(mktemp)"
|
||||
title="$tag - Release Theme"
|
||||
# Write the polished Markdown body to "$notes_file" before continuing.
|
||||
gh release edit "$tag" --repo Fission-AI/OpenSpec \
|
||||
--title "$title" --notes-file "$notes_file"
|
||||
```
|
||||
|
||||
When the user asked only for a preview or audit, show the proposed title/body without editing. When the user asked to run, continue, or complete the release, apply the polished notes without an extra confirmation pause, then fetch the release again and verify the saved title/body.
|
||||
@@ -1,49 +0,0 @@
|
||||
---
|
||||
name: verify-openspec-docs
|
||||
description: Fact-checks OpenSpec user documentation with a fresh-context subagent that re-runs commands and checks claims against source. Manually triggered; not part of the drafting loop. Use when the user asks to verify, fact-check, or accuracy-check a docs page, section, or set of changed claims.
|
||||
argument-hint: page or section
|
||||
---
|
||||
|
||||
# Verify OpenSpec docs
|
||||
|
||||
Check finished docs prose against reality. The point of a fresh context is that the reviewer hasn't watched the prose get written, so it can't be talked into the author's assumptions.
|
||||
|
||||
This skill runs only when the user asks for it. Drafting is owned by `write-openspec-docs`; don't invoke this from inside a drafting session unless the user requests a verification pass.
|
||||
|
||||
## Scope the run
|
||||
|
||||
1. Confirm the target: a page, one `##` section, or a list of changed claims. If invoked without a target, ask.
|
||||
2. Read the README at the root of the docs tree the target lives in; its invariants and page map are part of what gets checked.
|
||||
3. One subagent per unit (one `##` section, or the stated claim list). A full page is several subagents, run in parallel.
|
||||
|
||||
## Spawn the reviewer
|
||||
|
||||
General-purpose subagent. Subagents don't inherit skills, so the prompt hands the reviewer everything by path. Fill every placeholder, make every path absolute, and send:
|
||||
|
||||
```
|
||||
You are reviewing one unit of OpenSpec's user documentation before it reaches the docs owner. Be the two hardest readers it will meet: a skeptical developer reading it cold, and a fact-checker with the repo open.
|
||||
|
||||
Repo root: <ABSOLUTE REPO ROOT>. Use absolute paths with every tool.
|
||||
|
||||
Read first:
|
||||
1. <DOCS TREE ROOT>/README.md: the page map and standing invariants.
|
||||
2. <ABSOLUTE REPO ROOT>/.agents/skills/write-openspec-docs/writing.md: the house writing rules.
|
||||
3. <PAGE PATH>: review only <the section "<HEADING>" | these changed claims: <LIST>>; read the rest of the page for context.
|
||||
|
||||
Then check, in this order:
|
||||
|
||||
1. Facts. Every command, flag, path, config key, output block, default, and behavior claim. Re-run the terminal commands shown: read-only commands anywhere, anything that mutates state in a scratch directory or not at all. Commands for the AI chat surface (like /opsx:propose) can't run in a shell; verify their names and behavior against the skill sources this repo ships. Check names against src/ and the CLI's own --help. An output block must match what the command actually prints.
|
||||
2. Examples. Any example spec or change must pass `openspec validate`. Run it when the example exists on disk.
|
||||
3. Structure. Flag anything that re-explains a topic whose canonical home is another page, or breaks a rule the docs tree's README states.
|
||||
4. Job fit. Does the unit serve the page's stated job (the one-line statement under the title, if present)? Does the arriving reader get what they came for quickly?
|
||||
5. Trust and slop. Flag: hype or comfort adjectives (easy, simple, powerful, seamless), claims with no shown evidence, vague generalization where a specific fact belongs, binary contrasts ("not X, it's Y"), colon reveals, importance puffery, summary endings, em dashes, bullet lists that should be prose, and three parallel punchy sentences in a row.
|
||||
|
||||
Report findings only, most severe first. For each: quote the line, say what is wrong, and give the fix in one line. For every fact you verified, say how (the command you ran, or the file and line you checked). List any claim you could not verify and why. Do not rewrite the unit. If the unit is clean, say so and list exactly what you verified.
|
||||
```
|
||||
|
||||
## Handle the report
|
||||
|
||||
- Default is report, not rewrite: show the user the findings ranked most severe first, each with the quoted line and one-line fix, plus what was verified and how, and any claim the reviewer couldn't verify.
|
||||
- Apply fixes only when the user asked for a verify-and-fix run or approves the findings. A verifier can also be wrong: rejections go in the report with your reason, so the user can overrule you.
|
||||
- If an applied fix changed a factual claim, verify again, scoped to the changed claims. Typo and wording fixes don't need a second pass.
|
||||
- Two passes without converging means stop and take it to the user. Don't polish in a loop.
|
||||
@@ -1,34 +0,0 @@
|
||||
---
|
||||
name: write-openspec-docs
|
||||
description: Switches into OpenSpec docs-writing mode; loads the house style guide and drafts or revises pages in its voice (action-first, no preamble, scannable). Use when writing or editing pages in the OpenSpec docs tree.
|
||||
argument-hint: page or section
|
||||
---
|
||||
|
||||
# Write OpenSpec docs
|
||||
|
||||
You are now writing OpenSpec's user docs. Read [writing.md](writing.md); it is the style authority for everything drafted here. The short version, in effect immediately:
|
||||
|
||||
- A page is a retrieval surface, not an essay. Structure decides whether the reader finds the answer; prose only decides how it reads. Open every section with the answer, never a running story.
|
||||
- Choose the page type before the outline. Guides follow the reader's task; reference mirrors the product's structure and uses exact field, command, and file names as scan anchors. Reference needs complete coverage without compressing several facts into one sentence, cell, or paragraph.
|
||||
- Draft the shortest version that answers; expanding a spare page is cheap, cutting a bloated one is a rewrite. Plain words, the fewest of them: an idea that fits in one line takes one line. Depth most readers skip goes behind a link, and the payload (commands, real output, failures and fixes) stays whole.
|
||||
- Dumb sentences, smart structure. Write the obvious sentence (actor, verb, object, stating the literal event); never compress extra facts in or take an angle. No hype adjectives, no preamble, no em dashes.
|
||||
- One job per slot: one fact per sentence, list intros only announce the list, one reader question or lookup target per section. A related fact gets its own slot, never a ride in someone else's.
|
||||
- Ground items in what the reader can verify: path or folder first, concept as the gloss, real output shown honestly.
|
||||
- No house template. Inventories open with a list naming every item, then expand each in its own unit after the list, never inline. Sequences take numbered steps (numbers mean order; inventories take bullets). Single ideas and reasoning stay in short prose.
|
||||
- Every load-bearing fact sits on a scan anchor: code fence, numbered bold lead-in, `**Term**: fact` bullet, table, file tree. Never only mid-paragraph.
|
||||
- Before finishing, run two backstop tests. Retrievability: can each question or exact product name be found by scanning alone? The glance: inspect the rendered page as shapes; does it look finishable, or like work? Check table-heavy changes at desktop and narrow widths. A failure means a slot got written without being earned; fix it now, don't leave it for review.
|
||||
|
||||
## Ground rules
|
||||
|
||||
- Load the `no-ai-slop` skill before drafting; it owns the generic slop patterns, while [writing.md](writing.md) owns what OpenSpec's docs specifically look and sound like.
|
||||
- Read the target page in full before editing it.
|
||||
- Real facts only: flags, paths, and output as they exist in source. If a claim can't be checked cheaply, still write it, but name it as unchecked when you show the work; never bridge a gap with a plausible-sounding sentence.
|
||||
- A fact lives on one page; everywhere else links to it. The docs tree's README owns the page map and structural invariants; check it before restructuring or adding pages.
|
||||
- For reference pages, inventory the contract from source before drafting prose. Follow the reference process in [writing.md](writing.md#reference-pages).
|
||||
- When unsure how something should scan or sound, match the exemplars: `docs-lab/start/setup.md` for section shape and inventories, `docs-lab/start/installation.md` (Uninstalling) for multi-step tasks.
|
||||
|
||||
## When done
|
||||
|
||||
Show the user what changed and name any unchecked claims.
|
||||
|
||||
If the user asks for the deep, evidence-first drafting session (run every command, one section per sitting, formal checkpoints), follow [full-process.md](full-process.md).
|
||||
@@ -1,49 +0,0 @@
|
||||
# Full drafting process (opt-in)
|
||||
|
||||
The evidence-first, checkpointed way to draft a page. Use this only when the user asks for the deep process; the default mode is SKILL.md alone.
|
||||
|
||||
## Orient (every session, before any writing)
|
||||
|
||||
1. Read the README at the root of the docs tree you're writing in. Where it states invariants or a page map, it wins over this skill.
|
||||
2. Read the target page top to bottom, plus anything its comments cite.
|
||||
3. Read the sibling pages this page links to or overlaps with, enough to know what must stay a link rather than become an explanation.
|
||||
4. Write down the page's job in one line: who arrives, trying to do what, and what they leave able to do. If the page carries a job statement (docs-lab pages use a `>` blockquote under the title), test against it. If the unit you're about to write doesn't serve that job, stop and raise it instead of drafting around it.
|
||||
|
||||
## Work in small units
|
||||
|
||||
- The default unit is one `##` section. A page is several sittings, not one.
|
||||
- For revisions to existing prose, the unit is the requested change, however many headings it touches.
|
||||
- Draft the next unit only after the user has reviewed the current one. When the user asks for fixes, fix only that; don't smuggle in the next unit.
|
||||
|
||||
## Evidence before prose
|
||||
|
||||
Before drafting a unit, know where its claims come from.
|
||||
|
||||
- Run the terminal commands the unit will show when they're cheap: read-only commands anywhere, anything that mutates state in a scratch directory or not at all. Paste real output; trim it, never retouch it.
|
||||
- Check names against source: flags, paths, config keys, and defaults come from `src/` and the CLI's own help, not from older docs. When docs and source disagree, source wins; note the conflict for the user.
|
||||
- Never bridge a gap with a plausible-sounding sentence. A claim you couldn't check gets flagged at the checkpoint, not silently shipped. Don't let one expensive check stall the draft.
|
||||
|
||||
## Strip the slop
|
||||
|
||||
Invoke the `no-ai-slop` skill on the drafted unit and apply its edit pass. Docs prose gets no exemption: the patterns it names read as machine-written to exactly the audience these docs must win over.
|
||||
|
||||
## Does it do the job?
|
||||
|
||||
Reread the unit cold, as the reader the job line names, arriving with their actual problem. Answer three questions:
|
||||
|
||||
1. Can they act? Every step is runnable as written, and nothing depends on knowledge the page hasn't given or linked.
|
||||
2. Do they know it worked? Where success could be in doubt, the unit shows something visible: output, a file, what the agent does next. Where the outcome is obvious, no success line is owed.
|
||||
3. What can they do now that they couldn't before? If the honest answer is "they read some context", the unit is explaining instead of solving; cut it back to what serves the job or raise it with the user.
|
||||
|
||||
A unit that fails here gets fixed before the checkpoint, not annotated.
|
||||
|
||||
## Checkpoint
|
||||
|
||||
End the unit by showing the user:
|
||||
|
||||
- the file path and the unit written;
|
||||
- the page's job in one line, and what this unit lets the reader do toward it;
|
||||
- which claims you checked and how (commands run, files read);
|
||||
- any claim still unchecked.
|
||||
|
||||
Then stop. The next unit starts when the user says so.
|
||||
@@ -1,204 +0,0 @@
|
||||
# OpenSpec docs: the style guide
|
||||
|
||||
Structure, voice, tone, and language for OpenSpec's user docs. This file is the primary style authority for the docs tree. The tree's own README owns structure (the page map and which page teaches what); when this file and that README disagree, the README wins. `no-ai-slop` owns the generic slop patterns; this file owns what OpenSpec's docs specifically look and sound like.
|
||||
|
||||
## Six principles
|
||||
|
||||
Every rule below applies one of these; when rules collide, the principles decide.
|
||||
|
||||
- **A page is a retrieval surface, not an essay.** The reader arrives mid-task with a question, scans for the answer, and leaves. Structure decides whether they find it; prose only decides how it reads. Structure wins.
|
||||
- **The shortest version that answers is the right length, drafted that way from the start.** Expanding a spare page is cheap; cutting a bloated one is a rewrite. Plain words, and the fewest of them: an idea that fits in one line takes one line.
|
||||
- **Dumb sentences, smart structure.** Write the obvious sentence: actor, verb, object, stating the literal event ("Running init creates two things in your project"). Never the version that compresses facts in or takes an angle ("Everything init creates is meant to be committed"). If a sentence needs unpacking, it failed.
|
||||
- **One job per slot.** A sentence carries one fact (one carrying three hides two). A list intro only announces its list. A section owns one reader question or lookup target. Related facts get their own slot, never a ride in someone else's.
|
||||
- **Ground everything in what the reader can verify.** Name things by path, file, or real output: what the reader could match against `ls`. The concept is the gloss, never the name.
|
||||
- **No house template.** Shape follows content: inventories get overview-then-expand, sequences get numbered steps, a single idea gets short paragraphs, and reasoning lives in prose. The universal check is the retrievability test, not bullet count.
|
||||
|
||||
## The retrievability test
|
||||
|
||||
Name the questions or exact product terms a reader would bring to the section ("does init touch `.gitignore`?", "how do I add a tool later?", `generates`). Each answer or term must be findable by scanning, heading to anchor to fact, without reading paragraphs. If finding a fact means reading sentences, restructure; prose that passes needs no bullets, and no amount of bullets saves a section that fails.
|
||||
|
||||
## The shortest draft
|
||||
|
||||
Brevity happens at drafting time, not review. A page that needs heavy cutting in review gets rewritten, and a rewrite costs more than writing it spare the first time. Start from the shortest version that answers and expand only where a real reader question goes unanswered.
|
||||
|
||||
Every slot is earned before it's written:
|
||||
|
||||
- **The unit**: it answers a reader question or documents a lookup target, or it doesn't go in. Tight prose on the wrong scope is still the wrong scope.
|
||||
- **The sentence**: would any reader come back for it? If not, it spends attention without buying anything; don't write it.
|
||||
- **The depth**: an edge case or rationale most readers skip goes behind a link to its canonical page, not inline. The docs keep the depth; this page doesn't charge every reader for it.
|
||||
- **The payload**: the command, the real output, the failure and its fix stay whole. Spare means no wind-up and no commentary, never fewer facts.
|
||||
|
||||
The glance test is the backstop, not the method. Scroll the rendered page and read it as shapes: short units, air between anchors, no screen-filling block of anything. A page that looks like work loses its reader before the first sentence; if yours does, something above got in without earning its slot. For table or layout changes, check both desktop and narrow widths; the Markdown source can't show cramped columns, poor wrapping, or horizontal scrolling.
|
||||
|
||||
## Shape of a section
|
||||
|
||||
- **Answer first**: open with the command, the inventory, or the fact in one line. Context and rationale come after, never first.
|
||||
- **Inventory, then expand**: when a section covers several things (what init installs, what an uninstall leaves behind), open with a list naming every item in one line each, then expand each in its own unit after the list (a subsection or bold lead-in).
|
||||
- **The overview only names**: a count ("two things:") is not an inventory, and expansion never happens inline in the list; the reader sees the whole footprint, then the detail.
|
||||
- **Place first, meaning second**: name each on-disk item by its path or folder ("an `openspec/` folder at the repo root"), never by concept alone ("the planning folder"). The concept gloss can wait for the item's expansion. When a location varies (per tool, per OS), anchor it with a real folder or two ("`.agents/`, `.claude/`") and link the full list.
|
||||
- **Core before nuance**: inside every unit, the answer, then what to expect, then edge cases last. A reader who stops early still leaves with the core.
|
||||
- **One unit per target**: task pages separate different reader questions. Reference pages separate different product elements when readers look them up independently. Two facts with different targets get separate units, even when one elegant sentence could join them.
|
||||
|
||||
## Scan anchors
|
||||
|
||||
Every load-bearing fact sits on an anchor: something the eye lands on without reading. A fact a reader might come back for never lives only in the middle of a paragraph. The anchors these docs use:
|
||||
|
||||
- Code fences, for commands and real output.
|
||||
- Numbered steps with bold lead-ins (`**1. Remove the package.**`) for multi-step tasks.
|
||||
- `**Term**: fact` bullets for options, properties, and locations.
|
||||
- Tables, when several items share the same attributes (mostly reference pages).
|
||||
- File trees with inline annotations for layouts.
|
||||
|
||||
A full screen of content with no anchor is a wall, even when every sentence in it is true.
|
||||
|
||||
## Choosing the shape
|
||||
|
||||
No house template: facts go on anchors (enumerable content defaults to a list or table); explanation, reasoning, and judgment go in prose. The content picks the form:
|
||||
|
||||
- **Sequences**: numbered steps, one bounded action each. Numbers mean order of execution; an inventory of things takes bullets, never numbers. Restate any value a step needs rather than pointing back three steps.
|
||||
- **Options, properties, locations**: `**Term**: fact` bullets.
|
||||
- **Items sharing the same attributes**: a table.
|
||||
- **A single idea** (why a store is worth it, what sync treats as drift): a couple of short paragraphs; that is the right shape.
|
||||
- **Connected reasoning**: a paragraph. Shredding a thought into fragments makes it harder to read, not easier; a bullet list of full explanatory sentences is a paragraph in costume, so write the paragraph.
|
||||
|
||||
Across every form:
|
||||
|
||||
- Cap lists at about five items. Longer than that, split by priority: common path first, edge cases into their own list or a linked page.
|
||||
- Keep items parallel: same internal order (name, fact, catch, link), same grammatical shape. Repetition across items is what makes scanning work; never vary structure between items for the sake of the prose.
|
||||
- Uniformity is right when the content is uniform (a reference table, an install matrix). When every section on a varied page resolves to the same pattern, some of those lists are disguised paragraphs.
|
||||
|
||||
## Prose budget
|
||||
|
||||
Paragraphs are glue between anchors, not containers for facts.
|
||||
|
||||
- One to three lines. Three is the ceiling; a glue line between two anchors is often enough.
|
||||
- The list intro has exactly one job: say what the list is ("Running init creates two things in your project:"). Never spend that slot on a different fact, however related; it gets its own line after the list.
|
||||
- Parentheses and semicolon riders are for true asides only (a version caveat, a pointer). If a reader might return for the fact, it gets its own anchor.
|
||||
- A section that is mostly paragraphs is misshaped, unless the page is genuinely conceptual (Concepts, explanations of the model). Even there, front-load each paragraph and leave air between them.
|
||||
|
||||
## Sentences
|
||||
|
||||
- Short sentences, active voice. Default subject is "you" or the tool by name.
|
||||
- No preamble. The first sentence of any unit states the thing itself, never wind-up ("Before we get into...", "It's worth understanding that...").
|
||||
- No em dashes anywhere in these docs. Use a colon, a comma, parentheses, or two sentences.
|
||||
- Write the sentence you would say out loud. A draft that splices clauses with semicolons or colon-stacked fragments ("different documents: fewer of them, different names, different structure") gets rewritten as the spoken version ("when you want these to be different documents, whether that means fewer of them, different names, or a different structure"). Colons still introduce lists, fences, and labels. They don't splice prose.
|
||||
- Contractions are fine ("you're set", "doesn't come along"). These docs talk, they don't proclaim.
|
||||
- Inside narrative paragraphs, vary sentence length so the prose doesn't read staccato. Paragraphs only; list items stay parallel even when the cadence repeats.
|
||||
|
||||
## Voice
|
||||
|
||||
The narrator is a colleague who has run every command on the page, hit the failure modes personally, and is telling you what they know. Not a marketer, not a tutorial host, not a manual.
|
||||
|
||||
- Calm and specific. The reader wants the fact, the command, and the catch, in that order.
|
||||
- Confidence comes from precision, not emphasis. Never "very", "extremely", "critical", bold-for-importance, or exclamation marks.
|
||||
- Plain judgment is welcome. The docs may tell the reader what to do and what to skip: "The `openspec/` folder: pause first."
|
||||
- Address the reader as "you". OpenSpec, the CLI, and init do things. "We" appears only for project decisions ("we say skills"), never as a tour guide.
|
||||
- Dry beats chirpy. No cheerleading, no apologizing, no drama around failures. A failure is a fact with a fix.
|
||||
|
||||
## Structure and tone by page type
|
||||
|
||||
Same voice everywhere; structure and temperature shift:
|
||||
|
||||
- **Start pages**: numbered steps and short units, nothing assumed, every step ends in something visible. Warmest the docs get, which is still plain.
|
||||
- **Guides**: peer to peer, skip re-orientation. The judgment calls are the reason guides exist; put them on anchors so they scan.
|
||||
- **Reference**: mirror the product, use its exact names as anchors, and cover the contract without compressing it. Tables and fragments are common, but scan speed decides the shape. No motivation or persuasion; the reader is here to look something up and leave.
|
||||
- **Troubleshooting**: symptom, cause, fix, in that order, one unit per symptom. Name the error the reader sees. Never "you may notice" or "sometimes it can happen that".
|
||||
|
||||
Guides and Customize pages share one skeleton: a one-line what, a link to the Quickstart (never a recap), the 80% path, then Advanced. The exception is the concepts page, which is an explanation, not a task guide; its shape follows its concerns.
|
||||
|
||||
## Reference pages
|
||||
|
||||
Reference describes the product for a reader who is already working with it. The outline follows the machinery: file, block, field; command group, command, option; object, property, value. Use the product's exact names as headings when readers will search for those names. Reader-question headings belong to task pages unless the question itself is the established lookup term.
|
||||
|
||||
Cover the full contract without packing several facts into one sentence, cell, or paragraph.
|
||||
|
||||
### Draft the contract first
|
||||
|
||||
Before writing prose:
|
||||
|
||||
1. Inventory the product elements from source.
|
||||
2. Arrange them in the same hierarchy as the product.
|
||||
3. Write the smallest complete contract for each element.
|
||||
4. Expand only the elements whose behavior needs more room.
|
||||
5. Add examples that illustrate one rule at a time.
|
||||
6. Audit defaults, constraints, failures, ignored input, and validation gaps.
|
||||
|
||||
For each field, option, command, or file, record the identity facts that apply:
|
||||
|
||||
- Exact name and syntax
|
||||
- Type or accepted values
|
||||
- Required state and default
|
||||
- Scope, location, or base path
|
||||
|
||||
Then record the behavior facts that apply:
|
||||
|
||||
- Behavior and side effects
|
||||
- Constraints
|
||||
- Failure and ignored-input behavior
|
||||
- What validation catches and misses
|
||||
|
||||
Don't create empty sections or table columns for facts that don't apply.
|
||||
|
||||
### Inventory, then expand
|
||||
|
||||
Open with a complete table or list. Expand an item below the inventory only when its behavior can't fit cleanly in the overview. Put the expansion under the item's exact name so the table of contents works as an index.
|
||||
|
||||
For field and option references, `Field | Contract` is the safe table shape when definitions need sentences. Add more columns only when every cell is short and comparable. If columns split one coherent definition into fragments or wrap badly at a narrow width, use fewer columns or move the detail below the inventory.
|
||||
|
||||
### Examples and edge cases
|
||||
|
||||
An example illustrates one mapping, rule, or result. It doesn't become a sequence the reader follows or a narrative about completing a task. A complete example may follow the contract when seeing the elements together helps lookup.
|
||||
|
||||
Put the concrete default path or value in the primary slot. Put environment variables and uncommon overrides afterward.
|
||||
|
||||
State the observable consequence of a limit. If OpenSpec ignores a misspelled field, say that validation passes and the field has no effect. If a value falls back, name the value OpenSpec uses.
|
||||
|
||||
## Two surfaces
|
||||
|
||||
OpenSpec spans the terminal and the AI chat, and readers mix them up. Label every snippet:
|
||||
|
||||
```
|
||||
In your terminal:
|
||||
openspec init
|
||||
|
||||
In your AI chat:
|
||||
/opsx:propose add-rate-limit
|
||||
```
|
||||
|
||||
Where the reader could doubt it worked (a fresh install, a first run, a command with no output of its own), end with the concrete success signal: the line the command prints, the file that now exists, what the agent says next. Where the outcome is obvious, stop; an unneeded success line is noise.
|
||||
|
||||
## Authoring mechanics
|
||||
|
||||
Pages are plain markdown; GitHub and the site both render them. JSX components (`<Callout>`, `<Tabs>`, `<details>`) don't render; never use them.
|
||||
|
||||
- **Install commands**: write the global npm command once, in a fence whose language is `npm`; the site renders it as npm/pnpm/yarn/bun tabs with a copy button per tab (`remarkNpm` in `website/source.config.ts`, which also persists the reader's choice across blocks). On GitHub the fence degrades to the plain npm command.
|
||||
- **Callouts**: GitHub-style blockquote alerts (`> [!NOTE]`, `> [!TIP]`, `> [!IMPORTANT]`, `> [!WARNING]`, `> [!CAUTION]`); GitHub styles them natively and the site renders them as callouts (`remarkGfmAlert` in `website/lib/remark-gfm-alert.ts`). Never place one directly under the page title: the sync lifts the leading blockquote into the page description.
|
||||
|
||||
## What earns a developer's trust
|
||||
|
||||
- Show the real command and its real output, trimmed honestly. A retouched output is a lie the reader catches on their first run.
|
||||
- No hype and no comfort adjectives: easy, simple, just, powerful, seamless, robust. Three lines that show the thing beat any adjective about it.
|
||||
- State limits plainly. A named limitation builds more trust than praise: "Your assistant does need to be able to run shell commands; a few IDE integrations can't."
|
||||
- Don't generalize. Where you're tempted to write what OpenSpec "helps" with, write what actually happens: which file appears, what the diff shows, what the agent does next.
|
||||
- Don't define what you can show. An unfamiliar term whose instances explain themselves (the workflow list: propose, explore, apply...) is introduced by showing the instances with one-phrase glosses; the abstraction can wait.
|
||||
- Exact names: flags, paths, config keys, and versions as they exist in source, linked to their canonical page on first use.
|
||||
|
||||
## Naming and terms
|
||||
|
||||
- One term per concept, the glossary's term if the tree has one; today that means "skills", never "slash commands".
|
||||
- No invented taxonomy. Product terms (spec, change, delta, profile, store) name real things; use them freely. Any other organizing word in a heading or goal ("layers", "levers", "pillars") must pass one test: would a reader use it to ask their own question? If not, write the reader's question or the plain enumeration ("What you can customize", never "The three layers").
|
||||
- Examples invoke workflows by skill: the ask that triggers it ("ask your agent to propose a change") or the skill's name (`openspec-propose`), which is the same in every tool. A command spelling (`/opsx:propose`) appears only as a labeled per-tool example, never as the generic instruction; commands are headed for deprecation and their spellings vary per tool.
|
||||
- Prefer the shared `.agents/` folder in file-path examples; a tool-specific folder (`.claude/`) appears only when the example is about that tool.
|
||||
- Headings lead with a verb when the section is something the reader does ("Initialize your project"). Found content takes a plain noun phrase ("Install methods"). Never a vague verb ("Understand it") and never a pun.
|
||||
- If the page carries a one-line job statement under the title (docs-lab uses a `>` blockquote the site lifts into the page description), keep it plain, concrete, and true of the finished page.
|
||||
|
||||
## One canonical home
|
||||
|
||||
A fact lives on exactly one page; everywhere else links to it. A second copy is a future contradiction. The tree's README says which page owns what; when in doubt, link.
|
||||
|
||||
## Exemplars
|
||||
|
||||
When unsure how something should scan or sound, match these:
|
||||
|
||||
- `docs-lab/start/setup.md`: section shape, inventory-then-expand, enumerable facts on bullets.
|
||||
- `docs-lab/start/installation.md`, the Uninstalling section: multi-step tasks with bold numbered lead-ins.
|
||||
+4
-95
@@ -1,97 +1,6 @@
|
||||
# Changesets
|
||||
This directory is managed by Changesets.
|
||||
|
||||
This directory is managed by [Changesets](https://github.com/changesets/changesets).
|
||||
- Add a changeset locally with `pnpm changeset`.
|
||||
- The CI "Release (prepare)" workflow opens/updates a Version Packages PR.
|
||||
- Publishing happens from a GitHub Release via the "Publish to npm" workflow.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
pnpm changeset
|
||||
```
|
||||
|
||||
Follow the prompts to select version bump type and describe your changes.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Choose the release path**: Maintainers decide whether a PR follows the normal release cadence or gets dedicated release tracking.
|
||||
2. **Add dedicated release tracking**: When a maintainer asks for a changeset, run `pnpm changeset` locally before or after your PR.
|
||||
3. **Version PR**: CI opens/updates a "Version Packages" PR when changesets merge to main.
|
||||
4. **Release**: Merging the Version PR triggers npm publish and GitHub Release.
|
||||
|
||||
> **Note:** The default path is the normal release cadence. Add a changeset when a maintainer or release owner wants dedicated release notes and version tracking for the PR. Versioning (`changeset version`) and publishing happen automatically in CI.
|
||||
|
||||
## Template
|
||||
|
||||
Use this structure for your changeset content:
|
||||
|
||||
```markdown
|
||||
---
|
||||
"@fission-ai/openspec": patch
|
||||
---
|
||||
|
||||
### New Features
|
||||
|
||||
- **Feature name** — What users can now do
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fixed issue where X happened when Y
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- `oldMethod()` has been removed, use `newMethod()` instead
|
||||
|
||||
### Deprecations
|
||||
|
||||
- `legacyOption` is deprecated and will be removed in v2.0
|
||||
|
||||
### Other
|
||||
|
||||
- Internal refactoring of X for better performance
|
||||
```
|
||||
|
||||
Include only the sections relevant to your change.
|
||||
|
||||
## Version Bump Guide
|
||||
|
||||
| Type | When to use | Example |
|
||||
|------|-------------|---------|
|
||||
| `patch` | Release-tracked bug fixes, small improvements | Fixed crash when config missing |
|
||||
| `minor` | New features, non-breaking additions | Added `--verbose` flag |
|
||||
| `major` | Breaking changes, removed features | Renamed `init` to `setup` |
|
||||
|
||||
## When to Create a Changeset
|
||||
|
||||
**Use dedicated release tracking for:**
|
||||
- New features or commands selected for release
|
||||
- Notable bug fixes or hotfixes requested by a maintainer/release owner
|
||||
- Breaking changes or deprecations
|
||||
- Performance improvements users would notice and that are planned for release
|
||||
|
||||
**Use the normal release cadence for:**
|
||||
- Routine bug fixes that fit the normal release cadence
|
||||
- Documentation-only changes
|
||||
- Test additions/fixes
|
||||
- Internal refactoring that preserves user behavior
|
||||
- CI/tooling changes
|
||||
|
||||
## Writing Good Descriptions
|
||||
|
||||
**Do:** Write for users, not developers
|
||||
```markdown
|
||||
- **Shell completions** — Tab completion now available for Bash, Fish, and PowerShell
|
||||
```
|
||||
|
||||
**Don't:** Write implementation details
|
||||
```markdown
|
||||
- Added ShellCompletionGenerator class with Bash/Fish/PowerShell subclasses
|
||||
```
|
||||
|
||||
**Do:** Explain the impact
|
||||
```markdown
|
||||
- Fixed config loading to respect `XDG_CONFIG_HOME` on Linux
|
||||
```
|
||||
|
||||
**Don't:** Just reference the fix
|
||||
```markdown
|
||||
- Fixed #123
|
||||
```
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
{
|
||||
"$schema": "https://unpkg.com/@changesets/config/schema.json",
|
||||
"changelog": [
|
||||
"@changesets/changelog-github",
|
||||
{ "repo": "Fission-AI/OpenSpec" }
|
||||
],
|
||||
"changelog": "@changesets/cli/changelog",
|
||||
"commit": false,
|
||||
"fixed": [],
|
||||
"linked": [],
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
|
||||
# Minimal configuration for getting started
|
||||
language: "en-US"
|
||||
reviews:
|
||||
profile: "chill"
|
||||
high_level_summary: true
|
||||
auto_review:
|
||||
enabled: true
|
||||
drafts: false
|
||||
base_branches:
|
||||
- ".*"
|
||||
@@ -1,92 +0,0 @@
|
||||
# Dev Container Setup
|
||||
|
||||
This directory contains the VS Code dev container configuration for OpenSpec development.
|
||||
|
||||
## What's Included
|
||||
|
||||
- **Node.js 20 LTS** (>=20.19.0) - TypeScript/JavaScript runtime
|
||||
- **pnpm** - Fast, disk space efficient package manager
|
||||
- **Git + GitHub CLI** - Version control tools
|
||||
- **VS Code Extensions**:
|
||||
- ESLint & Prettier for code quality
|
||||
- Vitest Explorer for running tests
|
||||
- GitLens for enhanced git integration
|
||||
- Error Lens for inline error highlighting
|
||||
- Code Spell Checker
|
||||
- Path IntelliSense
|
||||
|
||||
## How to Use
|
||||
|
||||
### First Time Setup
|
||||
|
||||
1. **Install Prerequisites** (on your local machine):
|
||||
- [VS Code](https://code.visualstudio.com/)
|
||||
- [Docker Desktop](https://www.docker.com/products/docker-desktop)
|
||||
- [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
|
||||
|
||||
2. **Open in Container**:
|
||||
- Open this project in VS Code
|
||||
- You'll see a notification: "Folder contains a Dev Container configuration file"
|
||||
- Click "Reopen in Container"
|
||||
|
||||
OR
|
||||
|
||||
- Open Command Palette (`Cmd/Ctrl+Shift+P`)
|
||||
- Type "Dev Containers: Reopen in Container"
|
||||
- Press Enter
|
||||
|
||||
3. **Wait for Setup**:
|
||||
- The container will build (first time takes a few minutes)
|
||||
- `pnpm install` runs automatically via `postCreateCommand`
|
||||
- All extensions install automatically
|
||||
|
||||
### Daily Development
|
||||
|
||||
Once set up, the container preserves your development environment:
|
||||
|
||||
```bash
|
||||
# Run development build
|
||||
pnpm run dev
|
||||
|
||||
# Run CLI in development
|
||||
pnpm run dev:cli
|
||||
|
||||
# Run tests
|
||||
pnpm test
|
||||
|
||||
# Run tests in watch mode
|
||||
pnpm test:watch
|
||||
|
||||
# Build the project
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
### SSH Keys
|
||||
|
||||
Your SSH keys are mounted read-only from `~/.ssh`, so git operations work seamlessly with GitHub/GitLab.
|
||||
|
||||
### Rebuilding the Container
|
||||
|
||||
If you modify `.devcontainer/devcontainer.json`:
|
||||
- Command Palette → "Dev Containers: Rebuild Container"
|
||||
|
||||
## Benefits
|
||||
|
||||
- No need to install Node.js or pnpm on your local machine
|
||||
- Consistent development environment across team members
|
||||
- Isolated from other Node.js projects on your machine
|
||||
- All dependencies and tools containerized
|
||||
- Easy onboarding for new developers
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Container won't build:**
|
||||
- Ensure Docker Desktop is running
|
||||
- Check Docker has enough memory allocated (recommend 4GB+)
|
||||
|
||||
**Extensions not appearing:**
|
||||
- Rebuild the container: "Dev Containers: Rebuild Container"
|
||||
|
||||
**Permission issues:**
|
||||
- The container runs as the `node` user (non-root)
|
||||
- Files created in the container are owned by this user
|
||||
@@ -1,68 +0,0 @@
|
||||
{
|
||||
"name": "OpenSpec Development",
|
||||
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm",
|
||||
|
||||
// Additional tools and features
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/git:1": {
|
||||
"version": "latest",
|
||||
"ppa": true
|
||||
},
|
||||
"ghcr.io/devcontainers/features/github-cli:1": {
|
||||
"version": "latest"
|
||||
}
|
||||
},
|
||||
|
||||
// Configure tool-specific properties
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
// Set default container specific settings
|
||||
"settings": {
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"typescript.enablePromptUseWorkspaceTsdk": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll": "explicit"
|
||||
},
|
||||
"files.eol": "\n",
|
||||
"terminal.integrated.defaultProfile.linux": "bash"
|
||||
},
|
||||
|
||||
// Add extensions you want installed when the container is created
|
||||
"extensions": [
|
||||
// TypeScript/JavaScript essentials
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
|
||||
// Testing
|
||||
"vitest.explorer",
|
||||
|
||||
// Git
|
||||
"eamodio.gitlens",
|
||||
|
||||
// Utilities
|
||||
"streetsidesoftware.code-spell-checker",
|
||||
"usernamehw.errorlens",
|
||||
"christian-kohler.path-intellisense"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally
|
||||
// "forwardPorts": [],
|
||||
|
||||
// Use 'postCreateCommand' to run commands after the container is created
|
||||
"postCreateCommand": "corepack enable && corepack prepare pnpm@latest --activate && pnpm install",
|
||||
|
||||
// Configure mounts to preserve SSH keys for git operations
|
||||
"mounts": [
|
||||
"source=${localEnv:HOME}${localEnv:USERPROFILE}/.ssh,target=/home/node/.ssh,readonly,type=bind,consistency=cached"
|
||||
],
|
||||
|
||||
// Set the default user to 'node' (non-root user)
|
||||
"remoteUser": "node",
|
||||
|
||||
// Ensure git is properly configured
|
||||
"initializeCommand": "echo 'Initializing dev container...'"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
# The skills.sh distribution files are generated LF-only and compared
|
||||
# byte-for-byte by test/core/templates/skillssh-parity.test.ts. Force LF on
|
||||
# checkout so Windows autocrlf doesn't turn them into CRLF and fail parity.
|
||||
skills/** text eol=lf
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
# Default code ownership
|
||||
* @Fission-AI/openspec-maintainers
|
||||
* @TabishB
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
version: 2
|
||||
|
||||
# Dependabot does not manage two dependency surfaces in this repo:
|
||||
# 1. pnpm `overrides` (pnpm-workspace.yaml, root and website) — transitive
|
||||
# version pins that remediate advisories Dependabot can't otherwise reach.
|
||||
# It never bumps or removes these; each carries an inline advisory comment
|
||||
# noting the removal condition (see pnpm-workspace.yaml). They live in
|
||||
# pnpm-workspace.yaml only, because Dependabot *does* rewrite a plain-name
|
||||
# override (`postcss: ^8.5.26`) mirrored under package.json's `pnpm.overrides`
|
||||
# — and that block replaces the workspace list rather than merging with it,
|
||||
# so the mirror displaces the real pins. See #1812.
|
||||
# 2. The Nix flake (flake.nix / flake.lock). Update nixpkgs manually with
|
||||
# `nix flake update`; there is no Dependabot ecosystem for Nix. Note that the
|
||||
# pnpmDeps FOD hash in flake.nix must be regenerated on any root lockfile change.
|
||||
|
||||
updates:
|
||||
# Published CLI package
|
||||
- package-ecosystem: npm
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: monday
|
||||
# Let a freshly published version sit before adopting it. Security updates
|
||||
# ignore the cooldown, so this only delays routine bumps — long enough for a
|
||||
# compromised release to be yanked before it reaches this repo.
|
||||
cooldown:
|
||||
default-days: 7
|
||||
semver-major-days: 30
|
||||
semver-minor-days: 7
|
||||
semver-patch-days: 3
|
||||
open-pull-requests-limit: 5
|
||||
ignore:
|
||||
- dependency-name: "@types/node"
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
# Chalk 6 requires Node 22, while the published CLI supports Node 20.19.
|
||||
- dependency-name: "chalk"
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- dependency-name: "typescript"
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
commit-message:
|
||||
prefix: chore
|
||||
include: scope
|
||||
groups:
|
||||
production-dependencies:
|
||||
dependency-type: production
|
||||
update-types:
|
||||
- minor
|
||||
- patch
|
||||
development-dependencies:
|
||||
dependency-type: development
|
||||
update-types:
|
||||
- minor
|
||||
- patch
|
||||
|
||||
# Documentation site (not published to npm)
|
||||
- package-ecosystem: npm
|
||||
directory: /website
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: monday
|
||||
# Let a freshly published version sit before adopting it. Security updates
|
||||
# ignore the cooldown, so this only delays routine bumps — long enough for a
|
||||
# compromised release to be yanked before it reaches this repo.
|
||||
cooldown:
|
||||
default-days: 7
|
||||
semver-major-days: 30
|
||||
semver-minor-days: 7
|
||||
semver-patch-days: 3
|
||||
open-pull-requests-limit: 3
|
||||
ignore:
|
||||
- dependency-name: "@types/node"
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
- dependency-name: "typescript"
|
||||
update-types:
|
||||
- version-update:semver-major
|
||||
commit-message:
|
||||
prefix: chore
|
||||
include: scope
|
||||
groups:
|
||||
website-dependencies:
|
||||
patterns:
|
||||
- "*"
|
||||
update-types:
|
||||
- minor
|
||||
- patch
|
||||
|
||||
# CI workflow actions
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
day: monday
|
||||
# Actions are not semver-versioned the way packages are, so this ecosystem
|
||||
# accepts default-days only.
|
||||
cooldown:
|
||||
default-days: 7
|
||||
commit-message:
|
||||
prefix: ci
|
||||
groups:
|
||||
github-actions:
|
||||
patterns:
|
||||
- "*"
|
||||
@@ -1,20 +0,0 @@
|
||||
# Github Workflows
|
||||
|
||||
## Testing CI Locally
|
||||
|
||||
Test GitHub Actions workflows locally using [act](https://nektosact.com/):
|
||||
|
||||
```bash
|
||||
# Test all PR checks
|
||||
act pull_request
|
||||
|
||||
# Test specific job
|
||||
act pull_request -j nix-flake-validate
|
||||
|
||||
# Dry run to see what would execute
|
||||
act pull_request --dryrun
|
||||
```
|
||||
|
||||
The `.actrc` file configures act to use the appropriate Docker image.
|
||||
|
||||
|
||||
+67
-201
@@ -3,8 +3,6 @@ name: CI
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
merge_group:
|
||||
branches: [main]
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
@@ -17,41 +15,50 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# Detect which files changed to enable path-based filtering
|
||||
changes:
|
||||
name: Detect changes
|
||||
test_pr:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
nix: ${{ steps.filter.outputs.nix }}
|
||||
timeout-minutes: 10
|
||||
if: github.event_name == 'pull_request'
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check for Nix-related changes
|
||||
uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4
|
||||
id: filter
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
filters: |
|
||||
nix:
|
||||
- 'flake.nix'
|
||||
- 'flake.lock'
|
||||
- 'package.json'
|
||||
- 'pnpm-lock.yaml'
|
||||
- 'pnpm-workspace.yaml'
|
||||
- 'scripts/update-flake.sh'
|
||||
- '.github/workflows/ci.yml'
|
||||
# The Nix build runs `openspec completion generate`, so a change to
|
||||
# the generator can break packaging without touching flake.nix.
|
||||
- 'src/commands/completion.ts'
|
||||
- 'src/core/completions/**'
|
||||
version: 9
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build project
|
||||
run: pnpm run build
|
||||
|
||||
- name: Run tests
|
||||
run: pnpm test
|
||||
|
||||
- name: Upload test coverage
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage-report-pr
|
||||
path: coverage/
|
||||
retention-days: 7
|
||||
|
||||
test_matrix:
|
||||
name: Test (${{ matrix.label }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 15
|
||||
if: github.event_name == 'pull_request' || github.event_name == 'merge_group' || github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
||||
if: github.event_name != 'pull_request'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -59,15 +66,12 @@ jobs:
|
||||
- os: ubuntu-latest
|
||||
shell: bash
|
||||
label: linux-bash
|
||||
vitest_workers: 4
|
||||
- os: macos-latest
|
||||
shell: bash
|
||||
label: macos-bash
|
||||
vitest_workers: 4
|
||||
- os: windows-latest
|
||||
shell: pwsh
|
||||
label: windows-pwsh
|
||||
vitest_workers: 2
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -75,18 +79,19 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.19.0'
|
||||
node-version: '20'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Print environment diagnostics
|
||||
@@ -100,48 +105,32 @@ jobs:
|
||||
run: pnpm run build
|
||||
|
||||
- name: Run tests
|
||||
env:
|
||||
VITEST_MAX_WORKERS: ${{ matrix.vitest_workers }}
|
||||
run: pnpm test
|
||||
|
||||
- name: Upload test coverage
|
||||
if: matrix.os == 'ubuntu-latest'
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage-report-${{ github.event_name }}
|
||||
name: coverage-report-main
|
||||
path: coverage/
|
||||
retention-days: 7
|
||||
|
||||
test_pr_required:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
needs: [test_matrix]
|
||||
if: always() && (github.event_name == 'pull_request' || github.event_name == 'merge_group')
|
||||
steps:
|
||||
- name: Verify matrix tests passed
|
||||
run: |
|
||||
if [[ "${{ needs.test_matrix.result }}" != "success" ]]; then
|
||||
echo "Matrix test job failed"
|
||||
exit 1
|
||||
fi
|
||||
echo "All matrix tests passed!"
|
||||
|
||||
lint:
|
||||
name: Lint & Type Check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.19.0'
|
||||
node-version: '20'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
@@ -153,9 +142,6 @@ jobs:
|
||||
- name: Type check
|
||||
run: pnpm exec tsc --noEmit
|
||||
|
||||
- name: Lint
|
||||
run: pnpm lint
|
||||
|
||||
- name: Check for build artifacts
|
||||
run: |
|
||||
if [ ! -d "dist" ]; then
|
||||
@@ -167,173 +153,61 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
nix-flake-validate:
|
||||
name: Nix Flake Validation
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
needs: changes
|
||||
if: needs.changes.outputs.nix == 'true'
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install Nix
|
||||
uses: DeterminateSystems/nix-installer-action@3138316df39ed29be04236d7ffc686fa525866aa # v23
|
||||
|
||||
- name: Setup Nix cache
|
||||
uses: DeterminateSystems/magic-nix-cache-action@84c0677f58dcedf3b91f8223ce36a9ea5b3c84b7 # v15
|
||||
|
||||
# Run the update script before `nix build`, not after. The script recomputes
|
||||
# the pnpmDeps hash from pnpm-lock.yaml and rewrites flake.nix in place, so a
|
||||
# stale hash is reported here as the exact value to paste. Built first, the
|
||||
# same staleness surfaces as pnpm's ERR_PNPM_NO_OFFLINE_TARBALL — which names
|
||||
# a missing tarball, not the hash — and the script never runs to say otherwise.
|
||||
# Every root lockfile change needs this value, and Dependabot cannot produce it.
|
||||
- name: Verify pnpmDeps hash matches the lockfile
|
||||
run: |
|
||||
bash scripts/update-flake.sh
|
||||
if git diff --quiet flake.nix; then
|
||||
echo "✅ flake.nix pnpmDeps hash is up to date"
|
||||
exit 0
|
||||
fi
|
||||
# Scoped to the pnpmDeps block: a bare first-match would report some other
|
||||
# FOD's hash if one is ever added above it.
|
||||
HASH=$(sed -n '/pnpmDeps = /,/};/p' flake.nix \
|
||||
| sed -nE 's/.*hash = "(sha256-[^"]+)".*/\1/p' | head -1)
|
||||
git diff flake.nix
|
||||
echo "::error file=flake.nix::Stale pnpmDeps hash. Set pnpmDeps.hash to $HASH and push."
|
||||
exit 1
|
||||
|
||||
- name: Restore flake.nix
|
||||
if: always()
|
||||
run: git checkout -- flake.nix || true
|
||||
|
||||
- name: Build with Nix
|
||||
run: nix build
|
||||
|
||||
- name: Verify build output
|
||||
run: |
|
||||
if [ ! -e "result" ]; then
|
||||
echo "Error: Nix build output 'result' symlink not found"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "result/bin/openspec" ]; then
|
||||
echo "Error: openspec binary not found in build output"
|
||||
exit 1
|
||||
fi
|
||||
for completion in \
|
||||
"share/bash-completion/completions/openspec.bash" \
|
||||
"share/fish/vendor_completions.d/openspec.fish" \
|
||||
"share/zsh/site-functions/_openspec"; do
|
||||
if [ ! -s "result/$completion" ]; then
|
||||
echo "Error: completion script missing or empty: $completion"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
if [ "$(head -1 result/share/zsh/site-functions/_openspec)" != "#compdef openspec" ]; then
|
||||
echo "Error: zsh completion is not autoloadable (missing #compdef header)"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ Build output verified"
|
||||
|
||||
- name: Test binary execution
|
||||
run: |
|
||||
VERSION=$(nix run . -- --version)
|
||||
echo "OpenSpec version: $VERSION"
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "Error: Version command returned empty output"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ Binary execution successful"
|
||||
|
||||
validate-changesets:
|
||||
name: Validate Release Tracking
|
||||
name: Validate Changesets
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'pull_request' || github.event_name == 'merge_group'
|
||||
if: github.event_name == 'pull_request'
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Determine release tracking
|
||||
id: changed-changesets
|
||||
run: |
|
||||
changed_changesets="$(git diff --name-only --diff-filter=ACMRT origin/main...HEAD -- '.changeset/*.md' ':!.changeset/README.md')"
|
||||
if [[ -n "$changed_changesets" ]]; then
|
||||
echo "has_changesets=true" >> "$GITHUB_OUTPUT"
|
||||
# Run-unique delimiter: the value is a list of PR-authored paths, so a
|
||||
# fixed "EOF" would let a crafted path close the block early and append
|
||||
# its own key=value outputs.
|
||||
delim="EOF_$(openssl rand -hex 16)"
|
||||
{
|
||||
echo "files<<$delim"
|
||||
echo "$changed_changesets"
|
||||
echo "$delim"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "has_changesets=false" >> "$GITHUB_OUTPUT"
|
||||
echo "This PR follows the normal release cadence; continuing with standard validation"
|
||||
fi
|
||||
|
||||
- name: Setup pnpm
|
||||
if: steps.changed-changesets.outputs.has_changesets == 'true'
|
||||
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Setup Node.js
|
||||
if: steps.changed-changesets.outputs.has_changesets == 'true'
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '24'
|
||||
node-version: '20'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies
|
||||
if: steps.changed-changesets.outputs.has_changesets == 'true'
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Validate release-tracked changesets
|
||||
if: steps.changed-changesets.outputs.has_changesets == 'true'
|
||||
env:
|
||||
CHANGESET_FILES: ${{ steps.changed-changesets.outputs.files }}
|
||||
- name: Validate changesets
|
||||
run: |
|
||||
echo "Validating changed changesets:"
|
||||
printf '%s\n' "$CHANGESET_FILES"
|
||||
pnpm exec changeset status --since=origin/main
|
||||
if command -v changeset &> /dev/null; then
|
||||
pnpm exec changeset status --since=origin/main
|
||||
else
|
||||
echo "Changesets not configured, skipping validation"
|
||||
fi
|
||||
|
||||
required-checks-pr:
|
||||
name: All checks passed
|
||||
runs-on: ubuntu-latest
|
||||
needs: [test_matrix, lint, nix-flake-validate]
|
||||
if: always() && (github.event_name == 'pull_request' || github.event_name == 'merge_group')
|
||||
needs: [test_pr, lint]
|
||||
if: always() && github.event_name == 'pull_request'
|
||||
steps:
|
||||
- name: Verify all checks passed
|
||||
run: |
|
||||
if [[ "${{ needs.test_matrix.result }}" != "success" ]]; then
|
||||
echo "Matrix test job failed"
|
||||
if [[ "${{ needs.test_pr.result }}" != "success" ]]; then
|
||||
echo "Test job failed"
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${{ needs.lint.result }}" != "success" ]]; then
|
||||
echo "Lint job failed"
|
||||
exit 1
|
||||
fi
|
||||
# Nix validation may be skipped if no Nix-related files changed
|
||||
if [[ "${{ needs.nix-flake-validate.result }}" != "success" && "${{ needs.nix-flake-validate.result }}" != "skipped" ]]; then
|
||||
echo "Nix flake validation job failed"
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${{ needs.nix-flake-validate.result }}" == "skipped" ]]; then
|
||||
echo "Nix flake validation skipped (no Nix-related changes)"
|
||||
fi
|
||||
echo "All required checks passed!"
|
||||
|
||||
required-checks-main:
|
||||
name: All checks passed
|
||||
runs-on: ubuntu-latest
|
||||
needs: [test_matrix, lint, nix-flake-validate]
|
||||
if: always() && github.event_name == 'push'
|
||||
needs: [test_matrix, lint]
|
||||
if: always() && github.event_name != 'pull_request'
|
||||
steps:
|
||||
- name: Verify all checks passed
|
||||
run: |
|
||||
@@ -345,12 +219,4 @@ jobs:
|
||||
echo "Lint job failed"
|
||||
exit 1
|
||||
fi
|
||||
# Nix validation may be skipped if no Nix-related files changed
|
||||
if [[ "${{ needs.nix-flake-validate.result }}" != "success" && "${{ needs.nix-flake-validate.result }}" != "skipped" ]]; then
|
||||
echo "Nix flake validation job failed"
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${{ needs.nix-flake-validate.result }}" == "skipped" ]]; then
|
||||
echo "Nix flake validation skipped (no Nix-related changes)"
|
||||
fi
|
||||
echo "All required checks passed!"
|
||||
|
||||
@@ -1,192 +1,37 @@
|
||||
name: Release
|
||||
name: Release (prepare)
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch: # manually cut a beta prerelease from main
|
||||
|
||||
# Floor for both jobs. The prepare job widens this to pull-requests: write for
|
||||
# the Version Packages PR; the beta job only tags/releases + publishes via OIDC
|
||||
# and needs no PR access, so it inherits this narrower default.
|
||||
permissions:
|
||||
contents: write
|
||||
id-token: write # Required for npm OIDC trusted publishing
|
||||
|
||||
concurrency:
|
||||
group: release-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
if: github.repository == 'Fission-AI/OpenSpec' && github.event_name == 'push'
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write # changesets opens/updates the Version Packages PR
|
||||
id-token: write # Required for npm OIDC trusted publishing
|
||||
steps:
|
||||
# Generate GitHub App token first - used for checkout and changesets
|
||||
# This allows git operations to trigger CI workflows on the version PR
|
||||
# (GITHUB_TOKEN cannot trigger workflows by design)
|
||||
- name: Generate GitHub App Token
|
||||
id: app-token
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3
|
||||
with:
|
||||
app-id: ${{ vars.APP_ID }}
|
||||
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
||||
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
|
||||
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
node-version: '24' # Node 24 includes npm 11.5.1+ required for OIDC
|
||||
version: 9
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'pnpm'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
|
||||
# Opens/updates the Version Packages PR; publishes when the Version PR merges
|
||||
# Opens/updates the Version Packages PR; no publishing here
|
||||
- name: Create/Update Version PR
|
||||
id: changesets
|
||||
uses: changesets/action@ae32849d5ba541f9ae29e40e22a623bc13562f51 # v2.1.2
|
||||
uses: changesets/action@v1
|
||||
with:
|
||||
github-token: ${{ steps.app-token.outputs.token }}
|
||||
pr-title: 'chore(release): version packages'
|
||||
create-github-releases: true
|
||||
# Preserve the v1 release path: pushes use the GitHub App token from
|
||||
# checkout so version PR updates trigger their normal CI workflows.
|
||||
push-with-git-cli: true
|
||||
# Use CI-specific release script: relies on version PR having been merged
|
||||
# so package.json already contains the bumped version.
|
||||
publish-script: pnpm run release:ci
|
||||
title: 'chore(release): version packages'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
# npm authentication handled via OIDC trusted publishing (no token needed)
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Manually-dispatched beta prerelease from main: version is the next stable
|
||||
# release per pending changesets with a -beta.N suffix (e.g. v1.6.0-beta.1),
|
||||
# published to npm under the `beta` dist-tag and posted as a prerelease-flagged
|
||||
# GitHub Release. Changesets are left unconsumed, so the stable flow above is
|
||||
# unaffected. This job lives in this file because npm trusted publishing
|
||||
# authorizes a single workflow file per package.
|
||||
#
|
||||
# Users opt in with: npm install -g @fission-ai/openspec@beta
|
||||
beta:
|
||||
if: github.repository == 'Fission-AI/OpenSpec' && github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
|
||||
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: '24' # Node 24 includes npm 11.5.1+ required for OIDC
|
||||
cache: 'pnpm'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
|
||||
# Beta version = next stable version per pending changesets, plus a
|
||||
# -beta.N suffix that increments over existing beta tags for that version.
|
||||
- name: Compute beta version
|
||||
id: version
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
git fetch --tags --force origin
|
||||
pnpm exec changeset status --output=changeset-status.json
|
||||
NEXT=$(node -p "JSON.parse(require('fs').readFileSync('changeset-status.json','utf8')).releases[0]?.newVersion ?? ''")
|
||||
rm changeset-status.json
|
||||
if [ -z "$NEXT" ]; then
|
||||
echo "No pending changesets on main - nothing to cut a beta from."
|
||||
exit 1
|
||||
fi
|
||||
N=1
|
||||
while true; do
|
||||
VERSION="${NEXT}-beta.${N}"
|
||||
TAG="v${VERSION}"
|
||||
TAG_EXISTS=false
|
||||
NPM_EXISTS=false
|
||||
RELEASE_EXISTS=false
|
||||
|
||||
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then
|
||||
TAG_EXISTS=true
|
||||
fi
|
||||
if npm view "@fission-ai/openspec@${VERSION}" version >/dev/null 2>&1; then
|
||||
NPM_EXISTS=true
|
||||
fi
|
||||
if gh release view "${TAG}" >/dev/null 2>&1; then
|
||||
RELEASE_EXISTS=true
|
||||
fi
|
||||
|
||||
if [ "$TAG_EXISTS" = false ] && [ "$NPM_EXISTS" = false ] && [ "$RELEASE_EXISTS" = false ]; then
|
||||
break
|
||||
fi
|
||||
if [ "$RELEASE_EXISTS" = false ]; then
|
||||
echo "Resuming incomplete beta ${TAG}"
|
||||
break
|
||||
fi
|
||||
|
||||
N=$((N + 1))
|
||||
done
|
||||
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
||||
echo "Cutting ${TAG}"
|
||||
|
||||
- name: Set package version
|
||||
env:
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
run: npm version "$VERSION" --no-git-tag-version
|
||||
|
||||
# prepublishOnly runs the build. npm authentication handled via OIDC
|
||||
# trusted publishing (no token needed).
|
||||
- name: Publish to npm under the beta dist-tag
|
||||
env:
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
run: |
|
||||
if npm view "@fission-ai/openspec@${VERSION}" version >/dev/null 2>&1; then
|
||||
echo "@fission-ai/openspec@${VERSION} is already on npm; skipping publish."
|
||||
exit 0
|
||||
fi
|
||||
npm publish --tag beta
|
||||
|
||||
- name: Tag and create GitHub prerelease
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
VERSION: ${{ steps.version.outputs.version }}
|
||||
run: |
|
||||
TAG="v${VERSION}"
|
||||
HEAD_SHA=$(git rev-parse HEAD)
|
||||
|
||||
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then
|
||||
TAG_SHA=$(git rev-list -n 1 "${TAG}")
|
||||
if [ "$TAG_SHA" != "$HEAD_SHA" ]; then
|
||||
echo "${TAG} already exists at ${TAG_SHA}, not current HEAD ${HEAD_SHA}."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
git tag "${TAG}"
|
||||
fi
|
||||
|
||||
if git ls-remote --exit-code --tags origin "refs/tags/${TAG}" >/dev/null 2>&1; then
|
||||
echo "${TAG} already exists on origin; skipping tag push."
|
||||
else
|
||||
git push origin "${TAG}"
|
||||
fi
|
||||
|
||||
if gh release view "${TAG}" >/dev/null 2>&1; then
|
||||
echo "GitHub Release ${TAG} already exists; skipping release creation."
|
||||
else
|
||||
gh release create "${TAG}" \
|
||||
--prerelease \
|
||||
--generate-notes \
|
||||
--title "${TAG}" \
|
||||
--notes "Beta prerelease. Install with \`npm install -g @fission-ai/openspec@beta\`."
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
name: Publish to npm
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch: {}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: publish-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'pnpm'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
scope: '@fission-ai'
|
||||
always-auth: true
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build project
|
||||
run: pnpm run build
|
||||
|
||||
- name: Ensure running from a tag
|
||||
run: |
|
||||
if [[ "$GITHUB_REF" != refs/tags/* ]]; then
|
||||
echo "This workflow must run from a tag (got: $GITHUB_REF)";
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
- name: Verify release tag matches package.json
|
||||
run: |
|
||||
TAG="${GITHUB_REF_NAME#v}"
|
||||
PKG_VERSION=$(node -p "require('./package.json').version")
|
||||
if [ "$TAG" != "$PKG_VERSION" ]; then
|
||||
echo "Tag v$TAG does not match package.json $PKG_VERSION"; exit 1
|
||||
fi
|
||||
|
||||
- name: Debug npm auth and context
|
||||
run: |
|
||||
test -n "$NODE_AUTH_TOKEN" || (echo "NODE_AUTH_TOKEN is missing" && exit 1)
|
||||
echo "NODE_AUTH_TOKEN present"
|
||||
npm --version
|
||||
pnpm --version
|
||||
node --version
|
||||
npm config get registry
|
||||
npm whoami
|
||||
npm ping
|
||||
|
||||
- run: pnpm test
|
||||
|
||||
- name: Publish
|
||||
run: pnpm publish --access public --provenance --no-git-checks
|
||||
@@ -1,120 +0,0 @@
|
||||
name: Security
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- '**/package.json'
|
||||
- '**/pnpm-lock.yaml'
|
||||
- '**/pnpm-workspace.yaml'
|
||||
- '.github/workflows/security.yml'
|
||||
pull_request:
|
||||
branches: [main]
|
||||
schedule:
|
||||
# Weekly, so a newly published advisory surfaces even with no commits.
|
||||
- cron: '17 6 * * 1'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: security-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# Blocks a pull request that introduces a vulnerable or badly licensed dependency.
|
||||
dependency-review:
|
||||
name: Dependency Review
|
||||
if: github.event_name == 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
# No PR comment: that needs `pull-requests: write`, which a fork's token
|
||||
# never gets. The failed check plus its log is the signal.
|
||||
- name: Review dependency changes
|
||||
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
|
||||
with:
|
||||
fail-on-severity: high
|
||||
|
||||
audit:
|
||||
name: Audit
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
|
||||
|
||||
# No dependency cache: `pnpm audit` reads the lockfile, nothing is installed,
|
||||
# so a cache-save step would fail on the missing store path.
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: '20.19.0'
|
||||
|
||||
# Advisory on pull requests: a newly published advisory should not stop an
|
||||
# unrelated change, and the step depends on registry availability.
|
||||
# Blocking everywhere else — on the weekly schedule and on pushes to main
|
||||
# — so a high-severity advisory in a shipped dependency still fails a run
|
||||
# even when no dependency changed.
|
||||
- name: Audit published dependencies
|
||||
continue-on-error: ${{ github.event_name == 'pull_request' }}
|
||||
run: pnpm audit --prod --audit-level high
|
||||
|
||||
# Build and test tooling never reaches an installed copy of OpenSpec, so an
|
||||
# advisory here is a scheduled-update item.
|
||||
- name: Audit build and test tooling
|
||||
continue-on-error: true
|
||||
run: pnpm audit --audit-level high
|
||||
|
||||
# The docs site keeps its own lockfile and is not a workspace member, so
|
||||
# neither audit above can see it. Without this step a website advisory is
|
||||
# invisible — which is how two of them sat open long enough to need a
|
||||
# manual override.
|
||||
#
|
||||
# Same blocking rule as the published-dependency audit: advisory on pull
|
||||
# requests, blocking on the weekly schedule and on pushes to main. Green
|
||||
# here has to mean the site is clean, or the step just relocates the blind
|
||||
# spot into a passing log. `!cancelled()` because the two audits above can
|
||||
# fail hard, and a root advisory must not silently skip this one.
|
||||
- name: Audit documentation site
|
||||
if: ${{ !cancelled() }}
|
||||
continue-on-error: ${{ github.event_name == 'pull_request' }}
|
||||
run: pnpm audit --audit-level high --dir website
|
||||
|
||||
# The website keeps its own lockfile and is never installed or built elsewhere
|
||||
# in CI, so a website/package.json change — e.g. a security override — that is
|
||||
# not reflected in website/pnpm-lock.yaml goes unnoticed: the override you think
|
||||
# patches an advisory may not be in the committed graph at all, and `pnpm audit`
|
||||
# would happily audit the stale (possibly still-vulnerable) tree. A frozen-lockfile
|
||||
# install fails fast on that drift. Root drift is already caught by the
|
||||
# `--frozen-lockfile` installs in ci.yml; this closes the same gap for the website.
|
||||
# `--ignore-scripts` skips sharp's native build (irrelevant to lockfile validation
|
||||
# and the usual source of install flake).
|
||||
website-lockfile:
|
||||
name: Website Lockfile Drift
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: '20.19.0'
|
||||
|
||||
- name: Verify website lockfile matches package.json
|
||||
run: pnpm install --frozen-lockfile --ignore-scripts --dir website
|
||||
+2
-21
@@ -140,29 +140,10 @@ dist/
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
|
||||
# Internal Docs
|
||||
docs/
|
||||
|
||||
# Claude
|
||||
.claude/
|
||||
CLAUDE.md
|
||||
.DS_Store
|
||||
|
||||
# Pnpm
|
||||
.pnpm-store/
|
||||
/package-lock.json
|
||||
result
|
||||
|
||||
# OpenCode
|
||||
.opencode/
|
||||
opencode.json
|
||||
|
||||
# Codex
|
||||
.codex/
|
||||
|
||||
# Bob
|
||||
.bob/
|
||||
|
||||
# Trae
|
||||
.trae/
|
||||
|
||||
# Cursor
|
||||
.cursor/
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Repository Guidelines
|
||||
|
||||
## Project Structure & Module Organization
|
||||
OpenSpec ships as a TypeScript-first CLI. Source code lives in `src`, with feature logic in `core`, interactive flows in `cli`, reusable helpers in `utils`, and command wiring in `commands`. After `pnpm run build`, deliverables land in `dist` and feed the published entry point `bin/openspec.js`. Specs and change proposals reside in `openspec/specs` and `openspec/changes`; update them whenever behavior shifts so automation stays aligned. Shared assets live in `assets`, and Vitest suites in `test` mirror the source layout for easy cross-reference.
|
||||
|
||||
## Build, Test, and Development Commands
|
||||
Run `pnpm install` to sync dependencies. `pnpm run build` compiles TypeScript to `dist` and must stay green before release. Use `pnpm run dev` for a `tsc --watch` loop and `pnpm run dev:cli` to rebuild then execute the local CLI. `pnpm test` runs the Vitest suite once, `pnpm run test:watch` keeps it hot while iterating, and `pnpm run test:coverage` verifies instrumentation thresholds. Use `pnpm run changeset` when preparing a release entry.
|
||||
|
||||
## Coding Style & Naming Conventions
|
||||
We follow idiomatic TypeScript with ES modules, 2-space indentation, and semicolons. Prefer named exports from index barrels and keep filenames kebab-cased (e.g., `list-command.ts`). Classes use `PascalCase`, functions and variables use `camelCase`, and constants representing flags may use `SCREAMING_SNAKE_CASE`. Keep modules small, colocate helpers under `src/utils`, and avoid new dependencies without spec-backed justification.
|
||||
|
||||
## Testing Guidelines
|
||||
Every behavior change needs Vitest coverage under `test`, co-located by feature (e.g., `test/core/update.test.ts`). Name suites after the module under test and lean on `vitest.setup.ts` for shared configuration. Run `pnpm test` before pushing and add regression cases for each bug fix or spec requirement.
|
||||
|
||||
## Commit & Pull Request Guidelines
|
||||
Commits follow Conventional Commits (`type(scope): subject`) and stay single-line. Reference the touched module in the scope when practical. Each PR should summarize the spec or issue it fulfills, list manual verification steps, and note updates to any `openspec/` assets. Include CLI output snippets or screenshots when the UX changes, and ensure CI and coverage checks pass before requesting review.
|
||||
|
||||
## OpenSpec Workflow Tips
|
||||
Treat specs as the contract: update `openspec/project.md` or the relevant `openspec/specs/*.md` before coding, then run `pnpm run dev:cli` to validate the CLI against the revised artifacts. `openspec list --specs` confirms the catalog, and `openspec change` drafts proposals—commit these alongside code so reviewers can trace rationale to implementation.
|
||||
|
||||
-1206
File diff suppressed because it is too large
Load Diff
@@ -1,47 +0,0 @@
|
||||
# Contributing
|
||||
|
||||
Thanks for helping improve OpenSpec.
|
||||
|
||||
## 1. Open a discussion or an issue first
|
||||
|
||||
Every change starts here, including small ones.
|
||||
|
||||
- [Start a discussion](https://github.com/Fission-AI/OpenSpec/discussions) if it affects OpenSpec's core design.
|
||||
- [Open an issue](https://github.com/Fission-AI/OpenSpec/issues) for bugs and everything else.
|
||||
|
||||
This is so we can agree on the approach before you spend time building. PRs without a linked issue or a prior discussion may be closed.
|
||||
|
||||
## 2. Decide whether it needs a change proposal
|
||||
|
||||
A bug fix, a typo, or a small improvement goes straight to a PR.
|
||||
|
||||
A new feature, a significant refactor, or anything that changes OpenSpec's architecture needs an OpenSpec change proposal first, so we can align on intent and goals before implementation begins. Open it as a PR containing only `openspec/changes/<name>/` and wait for it to be approved before you write the code.
|
||||
|
||||
When writing a proposal, keep the OpenSpec philosophy in mind: we serve a wide variety of users across different coding agents, models, and use cases. Changes should work well for everyone.
|
||||
|
||||
If you are not sure which side of the line your change falls on, ask in the discussion or issue from step 1.
|
||||
|
||||
## 3. Make your change
|
||||
|
||||
You need Node 20.19+ and pnpm.
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm build # tests run against the build output
|
||||
pnpm test
|
||||
pnpm exec tsc --noEmit
|
||||
pnpm lint
|
||||
```
|
||||
|
||||
Those four commands are what CI runs, so a green local run means a green CI run.
|
||||
|
||||
Run `pnpm changeset` if your change affects users, and commit the file it generates.
|
||||
|
||||
## 4. Open the PR
|
||||
|
||||
- Branch off `main` in your fork.
|
||||
- Title it as a conventional commit: `type(scope): subject`, for example `fix(archive): keep authored Purpose`.
|
||||
- Link what you opened in step 1: `Closes #123` for an issue, or a link to the discussion when there is no issue.
|
||||
- If a coding agent wrote the code, say which agent and model, and confirm you tested it. AI-generated code is welcome when it has been verified.
|
||||
|
||||
Maintainers are listed in [MAINTAINERS.md](MAINTAINERS.md).
|
||||
@@ -1,24 +0,0 @@
|
||||
# Maintainers
|
||||
|
||||
People who maintain and guide OpenSpec.
|
||||
|
||||
## Core Maintainers
|
||||
|
||||
| Name | GitHub | Role |
|
||||
|------|--------|------|
|
||||
| Tabish Bidiwale | [@TabishB](https://github.com/TabishB) | Lead maintainer |
|
||||
| Clay Good | [@clay-good](https://github.com/clay-good) | Maintainer |
|
||||
|
||||
## Automation Maintainers
|
||||
|
||||
| Name | GitHub | Role |
|
||||
|------|--------|------|
|
||||
| Alfred | [@alfred-openspec](https://github.com/alfred-openspec) | Automation maintainer |
|
||||
|
||||
## Advisors
|
||||
|
||||
Advisors help shape technical direction and provide guidance to the project.
|
||||
|
||||
| Name | GitHub | Focus |
|
||||
|------|--------|-------|
|
||||
| Hari Krishnan | [@harikrishnan83](https://github.com/harikrishnan83) | Technical direction |
|
||||
@@ -1,268 +1,328 @@
|
||||
<p align="center">
|
||||
<a href="https://github.com/Fission-AI/OpenSpec">
|
||||
<picture>
|
||||
<source srcset="assets/openspec_bg.png">
|
||||
<img src="assets/openspec_bg.png" alt="OpenSpec logo">
|
||||
<source srcset="assets/openspec_pixel_dark.svg" media="(prefers-color-scheme: dark)">
|
||||
<source srcset="assets/openspec_pixel_light.svg" media="(prefers-color-scheme: light)">
|
||||
<img src="assets/openspec_pixel_light.svg" alt="OpenSpec logo" height="64">
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
</p>
|
||||
|
||||
<p align="center">Spec-driven development for AI coding assistants.</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/Fission-AI/OpenSpec/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Fission-AI/OpenSpec/actions/workflows/ci.yml/badge.svg" /></a>
|
||||
<a href="https://www.npmjs.com/package/@fission-ai/openspec"><img alt="npm version" src="https://img.shields.io/npm/v/@fission-ai/openspec?style=flat-square" /></a>
|
||||
<a href="https://nodejs.org/"><img alt="node version" src="https://img.shields.io/node/v/@fission-ai/openspec?style=flat-square" /></a>
|
||||
<a href="./LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square" /></a>
|
||||
<a href="https://discord.gg/YctCnvvshC"><img alt="Discord" src="https://img.shields.io/discord/1411657095639601154?style=flat-square&logo=discord&logoColor=white&label=Discord&suffix=%20online" /></a>
|
||||
<a href="https://conventionalcommits.org"><img alt="Conventional Commits" src="https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg?style=flat-square" /></a>
|
||||
<a href="https://discord.gg/saTQQGQZ"><img alt="Discord" src="https://img.shields.io/badge/Discord-Join%20the%20community-5865F2?logo=discord&logoColor=white&style=flat-square" /></a>
|
||||
</p>
|
||||
|
||||
<details>
|
||||
<summary><strong>The most loved spec framework.</strong></summary>
|
||||
|
||||
[](https://github.com/Fission-AI/OpenSpec/stargazers)
|
||||
[](https://www.npmjs.com/package/@fission-ai/openspec)
|
||||
[](https://github.com/Fission-AI/OpenSpec/graphs/contributors)
|
||||
|
||||
</details>
|
||||
<p></p>
|
||||
Our philosophy:
|
||||
|
||||
```text
|
||||
→ fluid not rigid
|
||||
→ iterative not waterfall
|
||||
→ easy not complex
|
||||
→ built for brownfield not just greenfield
|
||||
→ scalable from personal projects to enterprises
|
||||
```
|
||||
|
||||
> [!TIP]
|
||||
> **New workflow now available!** We've rebuilt OpenSpec with a new artifact-guided workflow.
|
||||
>
|
||||
> Run `/opsx:propose "your idea"` to get started. → [Learn more here](docs/opsx.md)
|
||||
|
||||
<p align="center">
|
||||
Follow <a href="https://x.com/0xTab">@0xTab on X</a> for updates · Join the <a href="https://discord.gg/YctCnvvshC">OpenSpec Discord</a> for help and questions.
|
||||
</p>
|
||||
|
||||
<!-- TODO: Add GIF demo of /opsx:propose → /opsx:archive workflow -->
|
||||
|
||||
## See it in action
|
||||
|
||||
```text
|
||||
You: /opsx:explore
|
||||
AI: What would you like to explore?
|
||||
You: I want dark mode but I'm not sure how to do it cleanly.
|
||||
AI: Let me look at your styling setup...
|
||||
Cleanest path here: CSS variables + a small theme context,
|
||||
with system-preference detection. No new dependencies. Scope it?
|
||||
You: Yes, let's do it.
|
||||
|
||||
You: /opsx:propose add-dark-mode
|
||||
AI: Created openspec/changes/add-dark-mode/
|
||||
✓ proposal.md — why we're doing this, what's changing
|
||||
✓ specs/ — requirements and scenarios
|
||||
✓ design.md — technical approach
|
||||
✓ tasks.md — implementation checklist
|
||||
Ready for implementation!
|
||||
|
||||
You: /opsx:apply
|
||||
AI: Implementing tasks...
|
||||
✓ 1.1 Add theme context provider
|
||||
✓ 1.2 Create toggle component
|
||||
✓ 2.1 Add CSS variables
|
||||
✓ 2.2 Wire up localStorage
|
||||
All tasks complete!
|
||||
|
||||
You: /opsx:archive
|
||||
AI: Archived to openspec/changes/archive/2025-01-23-add-dark-mode/
|
||||
Specs updated. Ready for the next feature.
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary><strong>What do the specs actually look like?</strong></summary>
|
||||
|
||||
Plain Markdown — requirements with concrete scenarios, no special syntax to learn. Here's what goes in the `specs/` folder created above:
|
||||
|
||||
```markdown
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Theme selection
|
||||
The app SHALL let users switch between light and dark themes,
|
||||
defaulting to the system preference.
|
||||
|
||||
#### Scenario: User toggles dark mode
|
||||
- **WHEN** the user clicks the theme toggle
|
||||
- **THEN** the app switches to dark mode and persists the choice
|
||||
```
|
||||
|
||||
Your AI writes these; you review the plan before any code is written.
|
||||
|
||||
OpenSpec is built with OpenSpec — browse this repo's live [specs](openspec/specs) and in-flight [changes](openspec/changes) for real examples at scale.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>OpenSpec Dashboard</strong></summary>
|
||||
|
||||
<p align="center">
|
||||
<img src="assets/openspec_dashboard.png" alt="OpenSpec dashboard preview" width="90%">
|
||||
</p>
|
||||
|
||||
</details>
|
||||
<p align="center">
|
||||
Follow <a href="https://x.com/0xTab">@0xTab on X</a> for updates · Join the <a href="https://discord.gg/saTQQGQZ">OpenSpec Discord</a> for help and questions.
|
||||
</p>
|
||||
|
||||
## Why teams adopt OpenSpec
|
||||
|
||||
Solo, OpenSpec keeps you and your AI honest on a single repo. On a team, the hard part moves: a feature spans the API server, the web app, and a shared library; requirements are owned by one team and consumed by others; planning starts before any code exists.
|
||||
|
||||
**[Stores](docs/stores-beta/user-guide.md)** are the answer — planning in a repo of its own. The same `openspec/` shape you already know (specs and changes), shared by `git push` like anything else. One source of truth your whole team and every coding agent can read, across every repo.
|
||||
|
||||
- **Cross-repo features** — one change, one plan, even when the code lands in three repos.
|
||||
- **Shared requirements** — a platform team owns the specs; product teams reference them read-only, right where their coding agent can read them. No drifting wiki.
|
||||
- **Plan before code** — capture the plan in the store now; the code repos catch up later.
|
||||
|
||||
> Stores are in **beta**. Start with the [Stores User Guide](docs/stores-beta/user-guide.md).
|
||||
|
||||
## Quick Start
|
||||
|
||||
**Requires Node.js 20.19.0 or higher.** Homebrew installs it as a dependency.
|
||||
|
||||
Install OpenSpec globally:
|
||||
|
||||
```bash
|
||||
npm install -g @fission-ai/openspec@latest
|
||||
```
|
||||
|
||||
Or install the official [Homebrew formula](https://formulae.brew.sh/formula/openspec) on macOS or Linux:
|
||||
|
||||
```bash
|
||||
brew install openspec
|
||||
```
|
||||
|
||||
Then navigate to your project directory and initialize:
|
||||
|
||||
```bash
|
||||
cd your-project
|
||||
openspec init
|
||||
```
|
||||
|
||||
> **Want your AI to do it?** Paste the [setup prompt](docs-lab/start/installation.md#install-with-your-ai-assistant) into your coding assistant — it installs the CLI, runs `openspec init`, and verifies the result.
|
||||
|
||||
Now talk to your AI:
|
||||
|
||||
- **Not sure what to build yet?** Start with `/opsx:explore`, a no-stakes thinking partner that reads your code, weighs options, and shapes a plan before any code gets written. ([Explore guide](docs/explore.md))
|
||||
- **Already know what you want?** Go straight to `/opsx:propose <what-you-want-to-build>`.
|
||||
|
||||
Both are in the default profile. If you want the expanded workflow (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:bulk-archive`, `/opsx:onboard`), select it with `openspec config profile` and apply with `openspec update`.
|
||||
|
||||
`/opsx:propose` is the canonical name; your tool may spell it `/opsx-propose` (Cursor, GitHub Copilot), `@opsx-propose` (Amazon Q) or `$openspec-propose` (Codex). `openspec init` prints the right form for the tools you picked — see [How To Invoke](docs/supported-tools.md#how-to-invoke).
|
||||
|
||||
> [!NOTE]
|
||||
> Not sure if your tool is supported? [View the full list](docs/supported-tools.md) – we support 30+ tools and growing.
|
||||
>
|
||||
> Also works with Homebrew, pnpm, yarn, bun, and Nix. [See installation options](docs-lab/start/installation.md).
|
||||
|
||||
## Docs
|
||||
|
||||
**Start here:** the **[Documentation Home](docs/README.md)** maps everything. New to OpenSpec? Read [Getting Started](docs/getting-started.md), then [How Commands Work](docs/how-commands-work.md) (where you actually type `/opsx:propose`).
|
||||
|
||||
→ **[Getting Started](docs/getting-started.md)**: first steps<br>
|
||||
→ **[Explore First](docs/explore.md)**: think it through with `/opsx:explore` before you commit<br>
|
||||
→ **[How Commands Work](docs/how-commands-work.md)**: where slash commands run vs the CLI<br>
|
||||
→ **[Core Concepts at a Glance](docs/overview.md)**: the whole mental model, one page<br>
|
||||
→ **[Examples & Recipes](docs/examples.md)**: real changes, start to finish<br>
|
||||
→ **[Workflows](docs/workflows.md)**: combos and patterns<br>
|
||||
→ **[Existing Projects](docs/existing-projects.md)**: adopt OpenSpec on a brownfield codebase<br>
|
||||
→ **[Editing a Change](docs/editing-changes.md)**: update artifacts, go back, reconcile manual edits<br>
|
||||
→ **[Commands](docs/commands.md)**: slash commands & skills<br>
|
||||
→ **[CLI](docs/cli.md)**: terminal reference<br>
|
||||
→ **[Stores](docs/stores-beta/user-guide.md)**: plan in a separate repo, shared across your team (beta)<br>
|
||||
→ **[Supported Tools](docs/supported-tools.md)**: tool integrations & install paths<br>
|
||||
→ **[Concepts](docs/concepts.md)**: how it all fits<br>
|
||||
→ **[Multi-Language](docs/multi-language.md)**: multi-language support<br>
|
||||
→ **[Customization](docs/customization.md)**: make it yours<br>
|
||||
→ **[Community Showcase](docs/community.md)**: projects and resources built with and for OpenSpec<br>
|
||||
→ **[FAQ](docs/faq.md)** · **[Troubleshooting](docs/troubleshooting.md)** · **[Glossary](docs/glossary.md)**: quick help
|
||||
|
||||
|
||||
## Community schemas
|
||||
|
||||
Third-party schema bundles distributed via standalone repositories — these provide opinionated workflows that integrate OpenSpec with other tools, similar to how [github/spec-kit's community extension catalog](https://github.com/github/spec-kit/tree/main/extensions) handles tool integrations.
|
||||
|
||||
→ **[Browse the catalog](docs/customization.md#community-schemas)** in the customization docs.
|
||||
# OpenSpec
|
||||
|
||||
OpenSpec aligns humans and AI coding assistants with spec-driven development so you agree on what to build before any code is written. **No API keys required.**
|
||||
|
||||
## Why OpenSpec?
|
||||
|
||||
AI coding assistants are powerful but unpredictable when requirements live only in chat history. OpenSpec adds a lightweight spec layer so you agree on what to build before any code is written.
|
||||
AI coding assistants are powerful but unpredictable when requirements live in chat history. OpenSpec adds a lightweight specification workflow that locks intent before implementation, giving you deterministic, reviewable outputs.
|
||||
|
||||
- **Agree before you build** — human and AI align on specs before code gets written
|
||||
- **Stay organized** — each change gets its own folder with proposal, specs, design, and tasks
|
||||
- **Work fluidly** — update any artifact anytime, no rigid phase gates
|
||||
- **Use your tools** — works with 30+ AI assistants via slash commands
|
||||
Key outcomes:
|
||||
- Human and AI stakeholders agree on specs before work begins.
|
||||
- Structured change folders (proposals, tasks, and spec updates) keep scope explicit and auditable.
|
||||
- Shared visibility into what's proposed, active, or archived.
|
||||
- Works with the AI tools you already use: custom slash commands where supported, context rules everywhere else.
|
||||
|
||||
### How we compare
|
||||
## How It Works
|
||||
|
||||
**vs. [Spec Kit](https://github.com/github/spec-kit)** (GitHub) — Thorough but heavyweight. Rigid phase gates, lots of Markdown, Python setup. OpenSpec is lighter and lets you iterate freely.
|
||||
```
|
||||
┌────────────────────┐
|
||||
│ Draft Change │
|
||||
│ Proposal │
|
||||
└────────┬───────────┘
|
||||
│ share intent with your AI
|
||||
▼
|
||||
┌────────────────────┐
|
||||
│ Review & Align │
|
||||
│ (edit specs/tasks) │◀──── feedback loop ──────┐
|
||||
└────────┬───────────┘ │
|
||||
│ approved plan │
|
||||
▼ │
|
||||
┌────────────────────┐ │
|
||||
│ Implement Tasks │──────────────────────────┘
|
||||
│ (AI writes code) │
|
||||
└────────┬───────────┘
|
||||
│ ship the change
|
||||
▼
|
||||
┌────────────────────┐
|
||||
│ Archive & Update │
|
||||
│ Specs (source) │
|
||||
└────────────────────┘
|
||||
|
||||
**vs. [Kiro](https://kiro.dev)** (AWS) — Powerful but you're locked into their IDE and limited to Claude models. OpenSpec works with the tools you already use.
|
||||
1. Draft a change proposal that captures the spec updates you want.
|
||||
2. Review the proposal with your AI assistant until everyone agrees.
|
||||
3. Implement tasks that reference the agreed specs.
|
||||
4. Archive the change to merge the approved updates back into the source-of-truth specs.
|
||||
```
|
||||
|
||||
**vs. nothing** — AI coding without specs means vague prompts and unpredictable results. OpenSpec brings predictability without the ceremony.
|
||||
## Getting Started
|
||||
|
||||
## Updating OpenSpec
|
||||
### Supported AI Tools
|
||||
|
||||
**Upgrade the package**
|
||||
#### Native Slash Commands
|
||||
These tools have built-in OpenSpec commands. Select the OpenSpec integration when prompted.
|
||||
|
||||
| Tool | Commands |
|
||||
|------|----------|
|
||||
| **Claude Code** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` |
|
||||
| **Cursor** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` |
|
||||
| **OpenCode** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` |
|
||||
|
||||
#### AGENTS.md Compatible
|
||||
These tools automatically read workflow instructions from `openspec/AGENTS.md`. Ask them to follow the OpenSpec workflow if they need a reminder. Learn more about the [AGENTS.md convention](https://agents.md/).
|
||||
|
||||
| Tools |
|
||||
|-------|
|
||||
| Codex • Amp • Jules • Gemini CLI • GitHub Copilot • Others |
|
||||
|
||||
### Install & Initialize
|
||||
|
||||
#### Prerequisites
|
||||
- **Node.js >= 20.19.0** - Check your version with `node --version`
|
||||
|
||||
#### Step 1: Install the CLI globally
|
||||
|
||||
```bash
|
||||
npm install -g @fission-ai/openspec@latest
|
||||
```
|
||||
|
||||
If you installed OpenSpec with Homebrew:
|
||||
|
||||
Verify installation:
|
||||
```bash
|
||||
brew upgrade openspec
|
||||
openspec --version
|
||||
```
|
||||
|
||||
**Refresh agent instructions**
|
||||
|
||||
Run this inside each project to regenerate AI guidance and ensure the latest slash commands are active:
|
||||
#### Step 2: Initialize OpenSpec in your project
|
||||
|
||||
Navigate to your project directory:
|
||||
```bash
|
||||
openspec update
|
||||
cd my-project
|
||||
```
|
||||
|
||||
## Usage Notes
|
||||
Run the initialization:
|
||||
```bash
|
||||
openspec init
|
||||
```
|
||||
|
||||
**Model selection**: OpenSpec works best with high-reasoning models. We recommend Codex 5.5 and Opus 4.7 for both planning and implementation.
|
||||
**What happens during initialization:**
|
||||
- You'll be prompted to select your AI tool (Claude Code, Cursor, etc.)
|
||||
- OpenSpec automatically configures slash commands or `AGENTS.md` based on your selection
|
||||
- A new `openspec/` directory structure is created in your project
|
||||
|
||||
**Context hygiene**: OpenSpec benefits from a clean context window. Clear your context before starting implementation and maintain good context hygiene throughout your session.
|
||||
**After setup:**
|
||||
- Primary AI tools can trigger `/openspec` workflows without additional configuration
|
||||
- Run `openspec list` to verify the setup and view any active changes
|
||||
|
||||
### Create Your First Change
|
||||
|
||||
Here's a real example showing the complete OpenSpec workflow. This works with any AI tool. Those with native slash commands will recognize the shortcuts automatically.
|
||||
|
||||
#### 1. Draft the Proposal
|
||||
Start by asking your AI to create a change proposal:
|
||||
|
||||
```text
|
||||
You: Create an OpenSpec change proposal for adding profile search filters by role and team
|
||||
(Shortcut for tools with slash commands: /openspec:proposal Add profile search filters)
|
||||
|
||||
AI: I'll create an OpenSpec change proposal for profile filters.
|
||||
*Scaffolds openspec/changes/add-profile-filters/ with proposal.md, tasks.md, spec deltas.*
|
||||
```
|
||||
|
||||
#### 2. Verify & Review
|
||||
Check that the change was created correctly and review the proposal:
|
||||
|
||||
```bash
|
||||
$ openspec list # Confirm the change folder exists
|
||||
$ openspec validate add-profile-filters # Validate spec formatting
|
||||
$ openspec show add-profile-filters # Review proposal, tasks, and spec delta
|
||||
```
|
||||
|
||||
#### 3. Refine the Specs
|
||||
Iterate on the specifications until they match your needs:
|
||||
|
||||
```text
|
||||
You: Can you add acceptance criteria for the role and team filters?
|
||||
|
||||
AI: I'll update the spec delta with scenarios for role and team filters.
|
||||
*Edits openspec/changes/add-profile-filters/specs/profile/spec.md and tasks.md.*
|
||||
```
|
||||
|
||||
#### 4. Implement the Change
|
||||
Once specs look good, start implementation:
|
||||
|
||||
```text
|
||||
You: The specs look good. Let's implement this change.
|
||||
(Shortcut for tools with slash commands: /openspec:apply add-profile-filters)
|
||||
|
||||
AI: I'll work through the tasks in the add-profile-filters change.
|
||||
*Implements tasks from openspec/changes/add-profile-filters/tasks.md*
|
||||
*Marks tasks complete: Task 1.1 ✓, Task 1.2 ✓, Task 2.1 ✓...*
|
||||
```
|
||||
|
||||
#### 5. Archive the Completed Change
|
||||
After implementation is complete, archive the change:
|
||||
|
||||
```text
|
||||
AI: All tasks are complete. The implementation is ready.
|
||||
|
||||
You: Please archive the change
|
||||
(Shortcut for tools with slash commands: /openspec:archive add-profile-filters)
|
||||
|
||||
AI: I'll archive the add-profile-filters change.
|
||||
*Runs: openspec archive add-profile-filters --yes*
|
||||
✓ Change archived successfully. Specs updated. Ready for the next feature!
|
||||
```
|
||||
|
||||
Or run the command yourself in terminal:
|
||||
```bash
|
||||
$ openspec archive add-profile-filters --yes # Archive the completed change without prompts
|
||||
```
|
||||
|
||||
**Note:** Tools with native slash commands (Claude Code, Cursor) can use the shortcuts shown. All other tools work with natural language requests to "create an OpenSpec proposal", "apply the OpenSpec change", or "archive the change".
|
||||
|
||||
## Command Reference
|
||||
|
||||
```bash
|
||||
openspec list # View active change folders
|
||||
openspec view # Interactive dashboard of specs and changes
|
||||
openspec show <change> # Display change details (proposal, tasks, spec updates)
|
||||
openspec validate <change> # Check spec formatting and structure
|
||||
openspec archive <change> [--yes|-y] # Move a completed change into archive/ (non-interactive with --yes)
|
||||
```
|
||||
|
||||
## Example: How AI Creates OpenSpec Files
|
||||
|
||||
When you ask your AI assistant to "add two-factor authentication", it creates:
|
||||
|
||||
```
|
||||
openspec/
|
||||
├── specs/
|
||||
│ └── auth/
|
||||
│ └── spec.md # Current auth spec (if exists)
|
||||
└── changes/
|
||||
└── add-2fa/ # AI creates this entire structure
|
||||
├── proposal.md # Why and what changes
|
||||
├── tasks.md # Implementation checklist
|
||||
├── design.md # Technical decisions (optional)
|
||||
└── specs/
|
||||
└── auth/
|
||||
└── spec.md # Delta showing additions
|
||||
```
|
||||
|
||||
### AI-Generated Spec (created in `openspec/specs/auth/spec.md`):
|
||||
|
||||
```markdown
|
||||
# Auth Specification
|
||||
|
||||
## Purpose
|
||||
Authentication and session management.
|
||||
|
||||
## Requirements
|
||||
### Requirement: User Authentication
|
||||
The system SHALL issue a JWT on successful login.
|
||||
|
||||
#### Scenario: Valid credentials
|
||||
- WHEN a user submits valid credentials
|
||||
- THEN a JWT is returned
|
||||
```
|
||||
|
||||
### AI-Generated Change Delta (created in `openspec/changes/add-2fa/specs/auth/spec.md`):
|
||||
|
||||
```markdown
|
||||
# Delta for Auth
|
||||
|
||||
## ADDED Requirements
|
||||
### Requirement: Two-Factor Authentication
|
||||
The system MUST require a second factor during login.
|
||||
|
||||
#### Scenario: OTP required
|
||||
- WHEN a user submits valid credentials
|
||||
- THEN an OTP challenge is required
|
||||
```
|
||||
|
||||
### AI-Generated Tasks (created in `openspec/changes/add-2fa/tasks.md`):
|
||||
|
||||
```markdown
|
||||
## 1. Database Setup
|
||||
- [ ] 1.1 Add OTP secret column to users table
|
||||
- [ ] 1.2 Create OTP verification logs table
|
||||
|
||||
## 2. Backend Implementation
|
||||
- [ ] 2.1 Add OTP generation endpoint
|
||||
- [ ] 2.2 Modify login flow to require OTP
|
||||
- [ ] 2.3 Add OTP verification endpoint
|
||||
|
||||
## 3. Frontend Updates
|
||||
- [ ] 3.1 Create OTP input component
|
||||
- [ ] 3.2 Update login flow UI
|
||||
```
|
||||
|
||||
**Important:** You don't create these files manually. Your AI assistant generates them based on your requirements and the existing codebase.
|
||||
|
||||
## Understanding OpenSpec Files
|
||||
|
||||
### Delta Format
|
||||
|
||||
Deltas are "patches" that show how specs change:
|
||||
|
||||
- **`## ADDED Requirements`** - New capabilities
|
||||
- **`## MODIFIED Requirements`** - Changed behavior (include complete updated text)
|
||||
- **`## REMOVED Requirements`** - Deprecated features
|
||||
|
||||
**Format requirements:**
|
||||
- Use `### Requirement: <name>` for headers
|
||||
- Every requirement needs at least one `#### Scenario:` block
|
||||
- Use SHALL/MUST in requirement text
|
||||
|
||||
## How OpenSpec Compares
|
||||
|
||||
### vs. Kiro.dev
|
||||
OpenSpec groups every change for a feature in one folder (`openspec/changes/feature-name/`), making it easy to track related specs, tasks, and designs together. Kiro spreads updates across multiple spec folders, which can make feature tracking harder.
|
||||
|
||||
### vs. No Specs
|
||||
Without specs, AI coding assistants generate code from vague prompts, often missing requirements or adding unwanted features. OpenSpec brings predictability by agreeing on the desired behavior before any code is written.
|
||||
|
||||
## Team Adoption
|
||||
|
||||
1. **Initialize OpenSpec** – Run `openspec init` in your repo.
|
||||
2. **Start with new features** – Ask your AI to capture upcoming work as change proposals.
|
||||
3. **Grow incrementally** – Each change archives into living specs that document your system.
|
||||
4. **Stay flexible** – Different teammates can use Claude Code, Cursor, or any AGENTS.md-compatible tool while sharing the same specs.
|
||||
|
||||
Run `openspec update` whenever someone switches tools so your agents pick up the latest instructions and slash-command bindings.
|
||||
|
||||
## Updating OpenSpec
|
||||
|
||||
1. **Upgrade the package**
|
||||
```bash
|
||||
npm install -g @fission-ai/openspec@latest
|
||||
```
|
||||
2. **Refresh agent instructions**
|
||||
- Run `openspec update` inside each project to regenerate AI guidance and ensure the latest slash commands are active.
|
||||
|
||||
## Contributing
|
||||
|
||||
Open a discussion (for core design changes) or an issue before you open a PR, and link the issue or discussion from the PR. New features, significant refactors, and architectural changes need an OpenSpec change proposal first.
|
||||
|
||||
→ **[CONTRIBUTING.md](CONTRIBUTING.md)**: the full process, from first issue to merged PR
|
||||
|
||||
## Other
|
||||
|
||||
<details>
|
||||
<summary><strong>Telemetry</strong></summary>
|
||||
|
||||
OpenSpec collects anonymous usage stats.
|
||||
|
||||
We collect only command names and version to understand usage patterns. No arguments, paths, content, or PII. Automatically disabled in CI.
|
||||
|
||||
**Opt-out (any one is enough):**
|
||||
- `openspec config set telemetry.enabled false` (global config; unset means on)
|
||||
- `export OPENSPEC_TELEMETRY=0` or `export DO_NOT_TRACK=1` (env overrides config)
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Maintainers & Advisors</strong></summary>
|
||||
|
||||
See [MAINTAINERS.md](MAINTAINERS.md) for the list of core maintainers and advisors who help guide the project.
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
- Install dependencies: `pnpm install`
|
||||
- Build: `pnpm run build`
|
||||
- Test: `pnpm test`
|
||||
- Develop CLI locally: `pnpm run dev` or `pnpm run dev:cli`
|
||||
- Conventional commits (one-line): `type(scope): subject`
|
||||
|
||||
## License
|
||||
|
||||
|
||||
-475
@@ -1,475 +0,0 @@
|
||||
<p align="center">
|
||||
<a href="https://github.com/Fission-AI/OpenSpec">
|
||||
<picture>
|
||||
<source srcset="assets/openspec_pixel_dark.svg" media="(prefers-color-scheme: dark)">
|
||||
<source srcset="assets/openspec_pixel_light.svg" media="(prefers-color-scheme: light)">
|
||||
<img src="assets/openspec_pixel_light.svg" alt="OpenSpec logo" height="64">
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
</p>
|
||||
<p align="center">Spec-driven development for AI coding assistants.</p>
|
||||
<p align="center">
|
||||
<a href="https://github.com/Fission-AI/OpenSpec/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Fission-AI/OpenSpec/actions/workflows/ci.yml/badge.svg" /></a>
|
||||
<a href="https://www.npmjs.com/package/@fission-ai/openspec"><img alt="npm version" src="https://img.shields.io/npm/v/@fission-ai/openspec?style=flat-square" /></a>
|
||||
<a href="https://nodejs.org/"><img alt="node version" src="https://img.shields.io/node/v/@fission-ai/openspec?style=flat-square" /></a>
|
||||
<a href="./LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square" /></a>
|
||||
<a href="https://conventionalcommits.org"><img alt="Conventional Commits" src="https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg?style=flat-square" /></a>
|
||||
<a href="https://discord.gg/YctCnvvshC"><img alt="Discord" src="https://img.shields.io/badge/Discord-Join%20the%20community-5865F2?logo=discord&logoColor=white&style=flat-square" /></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="assets/openspec_dashboard.png" alt="OpenSpec dashboard preview" width="90%">
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
Follow <a href="https://x.com/0xTab">@0xTab on X</a> for updates · Join the <a href="https://discord.gg/YctCnvvshC">OpenSpec Discord</a> for help and questions.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<sub>🧪 <strong>New:</strong> <a href="docs/opsx.md">OPSX Workflow</a> — schema-driven, hackable, fluid. Iterate on workflows without code changes.</sub>
|
||||
</p>
|
||||
|
||||
# OpenSpec
|
||||
|
||||
OpenSpec aligns humans and AI coding assistants with spec-driven development so you agree on what to build before any code is written. **No API keys required.**
|
||||
|
||||
## Why OpenSpec?
|
||||
|
||||
AI coding assistants are powerful but unpredictable when requirements live in chat history. OpenSpec adds a lightweight specification workflow that locks intent before implementation, giving you deterministic, reviewable outputs.
|
||||
|
||||
Key outcomes:
|
||||
- Human and AI stakeholders agree on specs before work begins.
|
||||
- Structured change folders (proposals, tasks, and spec updates) keep scope explicit and auditable.
|
||||
- Shared visibility into what's proposed, active, or archived.
|
||||
- Works with the AI tools you already use: custom slash commands where supported, context rules everywhere else.
|
||||
|
||||
## How OpenSpec compares (at a glance)
|
||||
|
||||
- **Lightweight**: simple workflow, no API keys, minimal setup.
|
||||
- **Brownfield-first**: works great beyond 0→1. OpenSpec separates the source of truth from proposals: `openspec/specs/` (current truth) and `openspec/changes/` (proposed updates). This keeps diffs explicit and manageable across features.
|
||||
- **Change tracking**: proposals, tasks, and spec deltas live together; archiving merges the approved updates back into specs.
|
||||
- **Compared to spec-kit & Kiro**: those shine for brand-new features (0→1). OpenSpec also excels when modifying existing behavior (1→n), especially when updates span multiple specs.
|
||||
|
||||
See the full comparison in [How OpenSpec Compares](#how-openspec-compares).
|
||||
|
||||
## How It Works
|
||||
|
||||
```
|
||||
┌────────────────────┐
|
||||
│ Draft Change │
|
||||
│ Proposal │
|
||||
└────────┬───────────┘
|
||||
│ share intent with your AI
|
||||
▼
|
||||
┌────────────────────┐
|
||||
│ Review & Align │
|
||||
│ (edit specs/tasks) │◀──── feedback loop ──────┐
|
||||
└────────┬───────────┘ │
|
||||
│ approved plan │
|
||||
▼ │
|
||||
┌────────────────────┐ │
|
||||
│ Implement Tasks │──────────────────────────┘
|
||||
│ (AI writes code) │
|
||||
└────────┬───────────┘
|
||||
│ ship the change
|
||||
▼
|
||||
┌────────────────────┐
|
||||
│ Archive & Update │
|
||||
│ Specs (source) │
|
||||
└────────────────────┘
|
||||
|
||||
1. Draft a change proposal that captures the spec updates you want.
|
||||
2. Review the proposal with your AI assistant until everyone agrees.
|
||||
3. Implement tasks that reference the agreed specs.
|
||||
4. Archive the change to merge the approved updates back into the source-of-truth specs.
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Supported AI Tools
|
||||
|
||||
<details>
|
||||
<summary><strong>Native Slash Commands</strong> (click to expand)</summary>
|
||||
|
||||
These tools have built-in OpenSpec commands. Select the OpenSpec integration when prompted.
|
||||
|
||||
| Tool | Commands |
|
||||
|------|----------|
|
||||
| **Amazon Q Developer** | `@openspec-proposal`, `@openspec-apply`, `@openspec-archive` (`.amazonq/prompts/`) |
|
||||
| **Antigravity** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.agent/workflows/`) |
|
||||
| **Auggie (Augment CLI)** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.augment/commands/`) |
|
||||
| **Claude Code** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` |
|
||||
| **Cline** | Workflows in `.clinerules/workflows/` directory (`.clinerules/workflows/openspec-*.md`) |
|
||||
| **CodeBuddy Code (CLI)** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` (`.codebuddy/commands/`) — see [docs](https://www.codebuddy.ai/cli) |
|
||||
| **Codex** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (global: `~/.codex/prompts`, auto-installed) |
|
||||
| **Continue** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.continue/prompts/`) |
|
||||
| **CoStrict** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.cospec/openspec/commands/`) — see [docs](https://costrict.ai)|
|
||||
| **Crush** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.crush/commands/openspec/`) |
|
||||
| **Cursor** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` |
|
||||
| **Factory Droid** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.factory/commands/`) |
|
||||
| **Gemini CLI** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` (`.gemini/commands/openspec/`) |
|
||||
| **GitHub Copilot** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.github/prompts/`) |
|
||||
| **iFlow (iflow-cli)** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.iflow/commands/`) |
|
||||
| **Kilo Code** | `/openspec-proposal.md`, `/openspec-apply.md`, `/openspec-archive.md` (`.kilocode/workflows/`) |
|
||||
| **OpenCode** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` |
|
||||
| **Qoder** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` (`.qoder/commands/openspec/`) — see [docs](https://qoder.com) |
|
||||
| **Qwen Code** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.qwen/commands/`) |
|
||||
| **RooCode** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.roo/commands/`) |
|
||||
| **Windsurf** | `/openspec-proposal`, `/openspec-apply`, `/openspec-archive` (`.windsurf/workflows/`) |
|
||||
|
||||
Kilo Code discovers team workflows automatically. Save the generated files under `.kilocode/workflows/` and trigger them from the command palette with `/openspec-proposal.md`, `/openspec-apply.md`, or `/openspec-archive.md`.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>AGENTS.md Compatible</strong> (click to expand)</summary>
|
||||
|
||||
These tools automatically read workflow instructions from `openspec/AGENTS.md`. Ask them to follow the OpenSpec workflow if they need a reminder. Learn more about the [AGENTS.md convention](https://agents.md/).
|
||||
|
||||
| Tools |
|
||||
|-------|
|
||||
| Amp • Jules • Others |
|
||||
|
||||
</details>
|
||||
|
||||
### Install & Initialize
|
||||
|
||||
#### Prerequisites
|
||||
- **Node.js >= 20.19.0** - Check your version with `node --version`
|
||||
|
||||
#### Step 1: Install the CLI globally
|
||||
|
||||
**Option A: Using npm**
|
||||
|
||||
```bash
|
||||
npm install -g @fission-ai/openspec@latest
|
||||
```
|
||||
|
||||
Verify installation:
|
||||
```bash
|
||||
openspec --version
|
||||
```
|
||||
|
||||
**Option B: Using Nix (NixOS and Nix package manager)**
|
||||
|
||||
Run OpenSpec directly without installation:
|
||||
```bash
|
||||
nix run github:Fission-AI/OpenSpec -- init
|
||||
```
|
||||
|
||||
Or install to your profile:
|
||||
```bash
|
||||
nix profile install github:Fission-AI/OpenSpec
|
||||
```
|
||||
|
||||
Or add to your development environment in `flake.nix`:
|
||||
```nix
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
openspec.url = "github:Fission-AI/OpenSpec";
|
||||
};
|
||||
|
||||
outputs = { nixpkgs, openspec, ... }: {
|
||||
devShells.x86_64-linux.default = nixpkgs.legacyPackages.x86_64-linux.mkShell {
|
||||
buildInputs = [ openspec.packages.x86_64-linux.default ];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Verify installation:
|
||||
```bash
|
||||
openspec --version
|
||||
```
|
||||
|
||||
#### Step 2: Initialize OpenSpec in your project
|
||||
|
||||
Navigate to your project directory:
|
||||
```bash
|
||||
cd my-project
|
||||
```
|
||||
|
||||
Run the initialization:
|
||||
```bash
|
||||
openspec init
|
||||
```
|
||||
|
||||
**What happens during initialization:**
|
||||
- You'll be prompted to pick any natively supported AI tools (Claude Code, CodeBuddy, Cursor, OpenCode, Qoder,etc.); other assistants always rely on the shared `AGENTS.md` stub
|
||||
- OpenSpec automatically configures slash commands for the tools you choose and always writes a managed `AGENTS.md` hand-off at the project root
|
||||
- A new `openspec/` directory structure is created in your project
|
||||
|
||||
**After setup:**
|
||||
- Primary AI tools can trigger `/openspec` workflows without additional configuration
|
||||
- Run `openspec list` to verify the setup and view any active changes
|
||||
- If your coding assistant doesn't surface the new slash commands right away, restart it. Slash commands are loaded at startup,
|
||||
so a fresh launch ensures they appear
|
||||
|
||||
### Optional: Populate Project Context
|
||||
|
||||
After `openspec init` completes, you'll receive a suggested prompt to help populate your project context:
|
||||
|
||||
```text
|
||||
Populate your project context:
|
||||
"Please read openspec/project.md and help me fill it out with details about my project, tech stack, and conventions"
|
||||
```
|
||||
|
||||
Use `openspec/project.md` to define project-level conventions, standards, architectural patterns, and other guidelines that should be followed across all changes.
|
||||
|
||||
### Create Your First Change
|
||||
|
||||
Here's a real example showing the complete OpenSpec workflow. This works with any AI tool. Those with native slash commands will recognize the shortcuts automatically.
|
||||
|
||||
#### 1. Draft the Proposal
|
||||
Start by asking your AI to create a change proposal:
|
||||
|
||||
```text
|
||||
You: Create an OpenSpec change proposal for adding profile search filters by role and team
|
||||
(Shortcut for tools with slash commands: /openspec:proposal Add profile search filters)
|
||||
|
||||
AI: I'll create an OpenSpec change proposal for profile filters.
|
||||
*Scaffolds openspec/changes/add-profile-filters/ with proposal.md, tasks.md, spec deltas.*
|
||||
```
|
||||
|
||||
#### 2. Verify & Review
|
||||
Check that the change was created correctly and review the proposal:
|
||||
|
||||
```bash
|
||||
$ openspec list # Confirm the change folder exists
|
||||
$ openspec validate add-profile-filters # Validate spec formatting
|
||||
$ openspec show add-profile-filters # Review proposal, tasks, and spec delta
|
||||
```
|
||||
|
||||
#### 3. Refine the Specs
|
||||
Iterate on the specifications until they match your needs:
|
||||
|
||||
```text
|
||||
You: Can you add acceptance criteria for the role and team filters?
|
||||
|
||||
AI: I'll update the spec delta with scenarios for role and team filters.
|
||||
*Edits openspec/changes/add-profile-filters/specs/profile/spec.md and tasks.md.*
|
||||
```
|
||||
|
||||
#### 4. Implement the Change
|
||||
Once specs look good, start implementation:
|
||||
|
||||
```text
|
||||
You: The specs look good. Let's implement this change.
|
||||
(Shortcut for tools with slash commands: /openspec:apply add-profile-filters)
|
||||
|
||||
AI: I'll work through the tasks in the add-profile-filters change.
|
||||
*Implements tasks from openspec/changes/add-profile-filters/tasks.md*
|
||||
*Marks tasks complete: Task 1.1 ✓, Task 1.2 ✓, Task 2.1 ✓...*
|
||||
```
|
||||
|
||||
#### 5. Archive the Completed Change
|
||||
After implementation is complete, archive the change:
|
||||
|
||||
```text
|
||||
AI: All tasks are complete. The implementation is ready.
|
||||
|
||||
You: Please archive the change
|
||||
(Shortcut for tools with slash commands: /openspec:archive add-profile-filters)
|
||||
|
||||
AI: I'll archive the add-profile-filters change.
|
||||
*Runs: openspec archive add-profile-filters --yes*
|
||||
✓ Change archived successfully. Specs updated. Ready for the next feature!
|
||||
```
|
||||
|
||||
Or run the command yourself in terminal:
|
||||
```bash
|
||||
$ openspec archive add-profile-filters --yes # Archive the completed change without prompts
|
||||
```
|
||||
|
||||
**Note:** Tools with native slash commands (Claude Code, CodeBuddy, Cursor, Codex, Qoder, RooCode) can use the shortcuts shown. All other tools work with natural language requests to "create an OpenSpec proposal", "apply the OpenSpec change", or "archive the change".
|
||||
|
||||
## Command Reference
|
||||
|
||||
```bash
|
||||
openspec list # View active change folders
|
||||
openspec view # Interactive dashboard of specs and changes
|
||||
openspec show <change> # Display change details (proposal, tasks, spec updates)
|
||||
openspec validate <change> # Check spec formatting and structure
|
||||
openspec archive <change> [--yes|-y] # Move a completed change into archive/ (non-interactive with --yes)
|
||||
```
|
||||
|
||||
## Example: How AI Creates OpenSpec Files
|
||||
|
||||
When you ask your AI assistant to "add two-factor authentication", it creates:
|
||||
|
||||
```
|
||||
openspec/
|
||||
├── specs/
|
||||
│ └── auth/
|
||||
│ └── spec.md # Current auth spec (if exists)
|
||||
└── changes/
|
||||
└── add-2fa/ # AI creates this entire structure
|
||||
├── proposal.md # Why and what changes
|
||||
├── tasks.md # Implementation checklist
|
||||
├── design.md # Technical decisions (optional)
|
||||
└── specs/
|
||||
└── auth/
|
||||
└── spec.md # Delta showing additions
|
||||
```
|
||||
|
||||
### AI-Generated Spec (created in `openspec/specs/auth/spec.md`):
|
||||
|
||||
```markdown
|
||||
# Auth Specification
|
||||
|
||||
## Purpose
|
||||
Authentication and session management.
|
||||
|
||||
## Requirements
|
||||
### Requirement: User Authentication
|
||||
The system SHALL issue a JWT on successful login.
|
||||
|
||||
#### Scenario: Valid credentials
|
||||
- WHEN a user submits valid credentials
|
||||
- THEN a JWT is returned
|
||||
```
|
||||
|
||||
### AI-Generated Change Delta (created in `openspec/changes/add-2fa/specs/auth/spec.md`):
|
||||
|
||||
```markdown
|
||||
# Delta for Auth
|
||||
|
||||
## ADDED Requirements
|
||||
### Requirement: Two-Factor Authentication
|
||||
The system MUST require a second factor during login.
|
||||
|
||||
#### Scenario: OTP required
|
||||
- WHEN a user submits valid credentials
|
||||
- THEN an OTP challenge is required
|
||||
```
|
||||
|
||||
### AI-Generated Tasks (created in `openspec/changes/add-2fa/tasks.md`):
|
||||
|
||||
```markdown
|
||||
## 1. Database Setup
|
||||
- [ ] 1.1 Add OTP secret column to users table
|
||||
- [ ] 1.2 Create OTP verification logs table
|
||||
|
||||
## 2. Backend Implementation
|
||||
- [ ] 2.1 Add OTP generation endpoint
|
||||
- [ ] 2.2 Modify login flow to require OTP
|
||||
- [ ] 2.3 Add OTP verification endpoint
|
||||
|
||||
## 3. Frontend Updates
|
||||
- [ ] 3.1 Create OTP input component
|
||||
- [ ] 3.2 Update login flow UI
|
||||
```
|
||||
|
||||
**Important:** You don't create these files manually. Your AI assistant generates them based on your requirements and the existing codebase.
|
||||
|
||||
## Understanding OpenSpec Files
|
||||
|
||||
### Delta Format
|
||||
|
||||
Deltas are "patches" that show how specs change:
|
||||
|
||||
- **`## ADDED Requirements`** - New capabilities
|
||||
- **`## MODIFIED Requirements`** - Changed behavior (include complete updated text)
|
||||
- **`## REMOVED Requirements`** - Deprecated features
|
||||
|
||||
**Format requirements:**
|
||||
- Use `### Requirement: <name>` for headers
|
||||
- Every requirement needs at least one `#### Scenario:` block
|
||||
- Use SHALL/MUST in requirement text
|
||||
|
||||
## How OpenSpec Compares
|
||||
|
||||
### vs. spec-kit
|
||||
OpenSpec’s two-folder model (`openspec/specs/` for the current truth, `openspec/changes/` for proposed updates) keeps state and diffs separate. This scales when you modify existing features or touch multiple specs. spec-kit is strong for greenfield/0→1 but provides less structure for cross-spec updates and evolving features.
|
||||
|
||||
### vs. Kiro.dev
|
||||
OpenSpec groups every change for a feature in one folder (`openspec/changes/feature-name/`), making it easy to track related specs, tasks, and designs together. Kiro spreads updates across multiple spec folders, which can make feature tracking harder.
|
||||
|
||||
### vs. No Specs
|
||||
Without specs, AI coding assistants generate code from vague prompts, often missing requirements or adding unwanted features. OpenSpec brings predictability by agreeing on the desired behavior before any code is written.
|
||||
|
||||
## Team Adoption
|
||||
|
||||
1. **Initialize OpenSpec** – Run `openspec init` in your repo.
|
||||
2. **Start with new features** – Ask your AI to capture upcoming work as change proposals.
|
||||
3. **Grow incrementally** – Each change archives into living specs that document your system.
|
||||
4. **Stay flexible** – Different teammates can use Claude Code, CodeBuddy, Cursor, or any AGENTS.md-compatible tool while sharing the same specs.
|
||||
|
||||
Run `openspec update` whenever someone switches tools so your agents pick up the latest instructions and slash-command bindings.
|
||||
|
||||
## Updating OpenSpec
|
||||
|
||||
1. **Upgrade the package**
|
||||
```bash
|
||||
npm install -g @fission-ai/openspec@latest
|
||||
```
|
||||
2. **Refresh agent instructions**
|
||||
- Run `openspec update` inside each project to regenerate AI guidance and ensure the latest slash commands are active.
|
||||
|
||||
## Experimental Features
|
||||
|
||||
<details>
|
||||
<summary><strong>🧪 OPSX: Fluid, Iterative Workflow</strong> (Claude Code only)</summary>
|
||||
|
||||
**Why this exists:**
|
||||
- Standard workflow is locked down — you can't tweak instructions or customize
|
||||
- When AI output is bad, you can't improve the prompts yourself
|
||||
- Same workflow for everyone, no way to match how your team works
|
||||
|
||||
**What's different:**
|
||||
- **Hackable** — edit templates and schemas yourself, test immediately, no rebuild
|
||||
- **Granular** — each artifact has its own instructions, test and tweak individually
|
||||
- **Customizable** — define your own workflows, artifacts, and dependencies
|
||||
- **Fluid** — no phase gates, update any artifact anytime
|
||||
|
||||
```
|
||||
You can always go back:
|
||||
|
||||
proposal ──→ specs ──→ design ──→ tasks ──→ implement
|
||||
▲ ▲ ▲ │
|
||||
└───────────┴──────────┴────────────────────┘
|
||||
```
|
||||
|
||||
| Command | What it does |
|
||||
|---------|--------------|
|
||||
| `/opsx:new` | Start a new change |
|
||||
| `/opsx:continue` | Create the next artifact (based on what's ready) |
|
||||
| `/opsx:ff` | Fast-forward (all planning artifacts at once) |
|
||||
| `/opsx:apply` | Implement tasks, updating artifacts as needed |
|
||||
| `/opsx:archive` | Archive when done |
|
||||
|
||||
**Setup:** `openspec experimental`
|
||||
|
||||
[Full documentation →](docs/opsx.md)
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Telemetry</strong> – OpenSpec collects anonymous usage stats (opt-out: <code>OPENSPEC_TELEMETRY=0</code>)</summary>
|
||||
|
||||
We collect only command names and version to understand usage patterns. No arguments, paths, content, or PII. Automatically disabled in CI.
|
||||
|
||||
**Opt-out:** `export OPENSPEC_TELEMETRY=0` or `export DO_NOT_TRACK=1`
|
||||
|
||||
</details>
|
||||
|
||||
## Contributing
|
||||
|
||||
- Install dependencies: `pnpm install`
|
||||
- Build: `pnpm run build`
|
||||
- Test: `pnpm test`
|
||||
- Develop CLI locally: `pnpm run dev` or `pnpm run dev:cli`
|
||||
- Conventional commits (one-line): `type(scope): subject`
|
||||
|
||||
<details>
|
||||
<summary><strong>Maintainers & Advisors</strong></summary>
|
||||
|
||||
See [MAINTAINERS.md](MAINTAINERS.md) for the list of core maintainers and advisors who help guide the project.
|
||||
|
||||
</details>
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
-62
@@ -1,62 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting a vulnerability
|
||||
|
||||
Report privately through [GitHub Security Advisories](https://github.com/Fission-AI/OpenSpec/security/advisories/new). Please don't open a public issue for a suspected vulnerability.
|
||||
|
||||
Include what you can: affected version, reproduction steps, and the impact you believe it has. We aim to acknowledge within 3 business days and to ship a fix or a decision within 30 days. Valid reports are credited in the advisory unless you'd rather stay anonymous.
|
||||
|
||||
## Supported versions
|
||||
|
||||
Fixes ship in the latest published version on npm. Older versions are not patched — upgrade to pick up a fix.
|
||||
|
||||
## Threat model
|
||||
|
||||
OpenSpec is a local command-line tool. It has no server, no network listener, and no privileged daemon. It reads and writes markdown under the directory you run it in, using paths you supply, with your own user permissions. It can offer to upgrade itself during `openspec update`, and only with your say-so. It sends anonymous usage telemetry, which you can disable with `OPENSPEC_TELEMETRY=0`.
|
||||
|
||||
That shapes what is and isn't a vulnerability here:
|
||||
|
||||
| In scope | Out of scope |
|
||||
| --- | --- |
|
||||
| Code execution triggered by parsing a spec, config, or template file | Reading or writing a file path you passed to the CLI yourself |
|
||||
| Escaping the directory OpenSpec was pointed at, via untrusted input | Static-analysis findings on file-path joins with no untrusted input |
|
||||
| Leaking credentials or file contents through telemetry or logs | Vulnerabilities in devDependencies that don't ship in the published package |
|
||||
| Prototype pollution or injection reachable from a config or spec file | Denial of service against your own machine using your own input |
|
||||
|
||||
If you think something sits on the boundary, report it and we'll work it out together.
|
||||
|
||||
## Published package contents
|
||||
|
||||
The `openspec` npm package publishes `dist/`, `bin/`, and `schemas/`. Build and test tooling (vite, rollup, vitest, eslint, and their transitive dependencies) is not published. Scanners that read `pnpm-lock.yaml` without separating dependency scope will report advisories for packages that never reach an installed copy of OpenSpec.
|
||||
|
||||
You do not have to take that on trust — install the package and look:
|
||||
|
||||
```sh
|
||||
npm install @fission-ai/openspec
|
||||
ls node_modules | grep -E '^(vite|rollup|vitest|eslint|js-yaml|minimatch)$' # no matches
|
||||
```
|
||||
|
||||
`pnpm audit --prod` in this repository reports the same scope, and CI runs it on every pull request.
|
||||
|
||||
## What the CLI does on your machine
|
||||
|
||||
| Surface | Behavior |
|
||||
| --- | --- |
|
||||
| Install scripts | The package ships no `preinstall`, `install`, or `postinstall` script, so installing it from the npm registry runs no code from OpenSpec. (`prepare` is still declared; npm runs it only for git and local-directory installs, where it builds from source.) Shell completions are opt-in via `openspec completion install`; the CLI prints a one-line tip about them on its first run. |
|
||||
| Running other programs | Every call that goes through a shell uses a fixed literal (`which gh`, `gh auth status`). Anything carrying your input — issue text, editor paths, workset commands, the path passed to `openspec update` — uses an argument array, never string interpolation into a shell. On Windows, `.cmd` shims are launched through `cross-spawn`, which escapes arguments rather than concatenating them. |
|
||||
| Installing software | `openspec update` can run `npm install -g @fission-ai/openspec@latest` and then re-run `openspec update` with the upgraded CLI. It does this only after you answer yes to a prompt, only for the OpenSpec package itself, only when npm owns the install, and never in CI or a non-interactive shell. A global install lives outside your project, so it runs with your permissions there and executes whatever lifecycle scripts the published package ships. It then reads the installed binary's version back rather than assuming the upgrade took. Decline and it prints the command for you to run yourself. |
|
||||
| Telemetry | Command name, OpenSpec version, and a locally generated random UUID. No file paths, no file contents, no environment, no hostname, and IP capture is explicitly disabled. Opt out with `OPENSPEC_TELEMETRY=0` or `DO_NOT_TRACK=1`; it is off in CI automatically. |
|
||||
| Network | Telemetry when enabled, and one npm registry request during `openspec update` to check whether a newer CLI has been published. That request sends no data about you beyond what any HTTP request reveals, runs once per `openspec update` with nothing cached, and is skipped when `CI` is set to anything but an explicit off-value, under `NODE_ENV=test`, or when `OPENSPEC_NO_UPDATE_CHECK`, `DO_NOT_TRACK=1`, or `OPENSPEC_TELEMETRY=0` is set. Reading, writing, and validating specs is entirely local. |
|
||||
|
||||
## Automated checks
|
||||
|
||||
| Tool | Covers |
|
||||
| --- | --- |
|
||||
| [CodeQL](https://github.com/Fission-AI/OpenSpec/security/code-scanning) | Static analysis on every push and pull request to `main` |
|
||||
| [Dependabot](https://github.com/Fission-AI/OpenSpec/security/dependabot) | Dependency advisories plus weekly update pull requests for the CLI, the docs site, and CI actions |
|
||||
| Dependency review | Blocks a pull request that introduces a high-severity dependency |
|
||||
| Secret scanning | Enabled on the repository, including push protection |
|
||||
| `pnpm audit` | Published dependencies are audited on every pull request, on pushes to `main`, and weekly. Advisory on pull requests so an unrelated change is not blocked; failing elsewhere, so a new advisory surfaces even when no dependency changed. Build tooling is always advisory. |
|
||||
| Pinned actions | Every GitHub Action runs from a commit SHA, so a moved tag cannot change what CI executes |
|
||||
|
||||
Alerts are triaged against the threat model above, so a finding in build-only tooling is fixed on the normal update cadence rather than treated as an incident.
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 34 KiB |
+1
-3
@@ -1,5 +1,3 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { runCli } from '../dist/cli/index.js';
|
||||
|
||||
runCli();
|
||||
import '../dist/cli/index.js';
|
||||
@@ -1,94 +0,0 @@
|
||||
Ok these are my notes when reviewing the different sections/file in docs-lab.
|
||||
I've written down my thoughts when looking at these sections so we can think about how to update these
|
||||
docs with the feedback in mind.
|
||||
|
||||
|
||||
## Start > Overview
|
||||
|
||||
Ok the following subtitle here is horrible:
|
||||
|
||||
> OpenSpec gives you and your coding agent a shared, reviewable plan before code is written.
|
||||
|
||||
This is not a strong value prop in the day and age of plan mode, but other than that i don't think it sells openspec hard enough
|
||||
|
||||
OpenSpec is not really about a shared plan for a single session it's about a keeping things on track and aligned for larger features.
|
||||
|
||||
what we focus on:
|
||||
- making it work for teams
|
||||
- git native / things checked into vcs
|
||||
- intented behaviour matches the implemented behaviour
|
||||
- we help you capture intendede behaviour and match it to the implemented behaviour.
|
||||
- it's about correctness, coherence,
|
||||
|
||||
Control theory inspiration:
|
||||
|
||||
Instructors break down how a system measures its current state, compares it to a desired goal, and adjusts its actions to reduce the difference.
|
||||
|
||||
|
||||
|
||||
## Guides > Explore and idea
|
||||
|
||||
I think in this section we should mention:
|
||||
|
||||
This is about exploring the problem space, figuring out what problems you care about and diving deeper into them.
|
||||
|
||||
It was designed with a very different philiosphy in mind of giving you the freedom to explore the problem space and jump around to different ideas and sections.
|
||||
|
||||
It serves a similar purpose to other newer entrees in the fields like superpowers or matt pocock's skills.
|
||||
|
||||
We often do see people combining explore with
|
||||
|
||||
Often this is a matter of UX and personal preference. There is no single best skill or method to getting to
|
||||
aligment with your agent.
|
||||
|
||||
Some people prefer a conversing with a thoughtful design partner, others might prefer being asked questions till they have a good understanding of a problem.
|
||||
|
||||
Feel free to customize the explore skills to your needs.
|
||||
|
||||
Unrelated to docs:
|
||||
|
||||
How do we solve the problem for PM's?
|
||||
How do we give them a good home? - what is their job to be done?
|
||||
How we efficiently help them achieve that?
|
||||
|
||||
- they're basically turning it into tickets?
|
||||
|
||||
|
||||
What do we want to get across the line this week?
|
||||
|
||||
- The spec drift agent?
|
||||
- The dashboard?
|
||||
|
||||
- figure out how we use agent session and traces better
|
||||
|
||||
|
||||
## From docs-lab drafting (2026-08-19, project-config page)
|
||||
|
||||
Product issue, not docs: the installed skills in this repo are stale against the current
|
||||
templates. `.claude/skills/openspec-archive-change/SKILL.md` has no `openspec instructions`
|
||||
call at all, while `src/core/templates/workflows/archive-change.ts:40` instructs one; the
|
||||
installed apply skill also doesn't mention the `context`/`operationGuidance` fields in the
|
||||
JSON it reads. So config injection reaches the CLI output, but a stale skill never tells
|
||||
the agent to consume it. Running `openspec update` should refresh them.
|
||||
|
||||
|
||||
## From docs-lab drafting (2026-08-19, schemas page)
|
||||
|
||||
Product issues found while verifying the schema system (all file refs current as of today):
|
||||
|
||||
- `schema init` next-steps output prints a command that doesn't exist in that form:
|
||||
"Use with: openspec new --schema <name>" (schema.ts:999); real syntax is
|
||||
`openspec new change <name> --schema <name>`.
|
||||
- `openspec new change` spinner prints the hardcoded default schema, not the resolved one
|
||||
(new-change.ts:118): "Creating change 'x' with schema 'spec-driven'..." then "Schema: lite".
|
||||
- `schema fork` re-serializes schema.yaml (literal `instruction: |` becomes folded `>`,
|
||||
comments dropped), so diffing a fork against upstream is noisy (schema.ts:706-712).
|
||||
- All `openspec schema` subcommands plus `openspec schemas`/`templates` use process.cwd()
|
||||
and take no --store; they silently see nothing when run from a subdirectory, unlike
|
||||
root-resolved commands (schema.ts:383/485/634/768).
|
||||
- `suggestSchemas` fuzzy "did you mean" helper exists but is wired to nothing
|
||||
(project-config.ts:420).
|
||||
|
||||
Docs follow-up: the community schema catalog lives only in legacy docs/customization.md
|
||||
(#community-schemas); customize/schemas.md links to it on GitHub. When the old docs tree
|
||||
retires, the catalog needs a docs-lab home.
|
||||
@@ -1,294 +0,0 @@
|
||||
# docs-lab: parallel rebuild of the OpenSpec docs
|
||||
|
||||
**Status: prose is landing page by page; the rest are skeletons** (real headings plus a
|
||||
one-line `>` job statement the site lifts into the page description). The live site
|
||||
builds from this tree: `website/docs.sync.config.mjs` maps these files to published
|
||||
pages, and the old `docs/` tree is no longer used by the site.
|
||||
|
||||
This README owns the structure: which pages exist and which page teaches what. The
|
||||
reverse view, from a job or message to the page that owns it, is
|
||||
[message-map.md](message-map.md). How to
|
||||
write them (style, voice, formatting) is the `write-openspec-docs` skill's
|
||||
[writing.md](../.agents/skills/write-openspec-docs/writing.md).
|
||||
|
||||
## The bar for every page
|
||||
|
||||
Every page in docs-lab is written by hand, from scratch. The old `docs/` tree is source
|
||||
material for facts, never text to carry over.
|
||||
|
||||
What we're after is that the reader gets the idea: every page reads well and makes sense
|
||||
to anyone, whatever their level of skill, and above all it is simple. The worst thing we
|
||||
can ship is documentation that is cognitively expensive to understand, and that cost
|
||||
comes from complicated words, metaphors that don't make sense, random terminology that
|
||||
isn't explained, and formatting that gets in the way of reading. Every sentence has a
|
||||
purpose and is easy to read and comprehend. If a sentence doesn't pass that test, rewrite
|
||||
it or cut it.
|
||||
|
||||
## Structure rules
|
||||
|
||||
**Folders are the areas.** Every page lives in its area's folder (`start/`,
|
||||
`guides/`, `customize/`, `multi-repo/`, `reference/`, `help/`); the root holds only this
|
||||
README, `message-map.md`, and `sources.md`. Most folders publish as one
|
||||
sidebar group; `guides/` publishes as the Guides group, holding three collapsible
|
||||
subgroups (Understanding OpenSpec, Using OpenSpec, Adopting OpenSpec), all expanded
|
||||
by default (held back from the site until the pages are drafted: the whole section is
|
||||
commented out in `website/docs.sync.config.mjs`, and links to a guide fall back to its
|
||||
source on GitHub until it's re-listed). Reference holds three nested
|
||||
folders (`reference/architecture/`, `reference/schemas/`, and
|
||||
`reference/configuration/`), each publishing as a collapsible group with `index.md` as
|
||||
its landing page; the spec-driven schema publishes as a single page
|
||||
(`reference/schemas/spec-driven/index.md`) inside the Schemas group. Labels and URLs come from
|
||||
`website/docs.sync.config.mjs`, so moving a file never moves a URL.
|
||||
|
||||
**Teach once.** The loop (propose, review, apply, archive) has one teacher; every other
|
||||
page links, never re-teaches:
|
||||
|
||||
- `start/quickstart.md` teaches it as UX: how a human moves a change through the
|
||||
lifecycle, including what archive does on disk.
|
||||
- `start/overview.md` shows it as pitch: copy only, no explanation.
|
||||
- `guides/concepts.md` stays out of it: the page explains the artifacts (specs, changes,
|
||||
the delta) and links to the quickstart for the loop. Disk paths appear inline with the
|
||||
concept that owns them, never as a layout section.
|
||||
- `start/installation.md` owns install; `start/setup.md` owns init and what it writes.
|
||||
The quickstart opens with one prerequisite line linking both and starts at explore.
|
||||
|
||||
**Guides vs reference.** `reference/skills.md` holds each skill's contract: arguments,
|
||||
what it creates, and what it responds with. Guide pages
|
||||
(the Using and Adopting subgroups) own the human judgment for a task, including when
|
||||
to reach for each skill, may span several skills, and never restate skill mechanics.
|
||||
`reference/architecture/` is the one exception to Reference's look-it-up bar: it's
|
||||
explanation content, housed here as a pragmatic home while it's three pages. If it
|
||||
grows (say, by absorbing contributor internals), consider giving it its own folder
|
||||
and tab.
|
||||
|
||||
**Reference is lookup, and named for it.** `reference/schemas/` and
|
||||
`reference/configuration/` are contracts: keys, values, types, defaults, and
|
||||
locations, on tables and fences. Anything explanatory (what a schema is, what
|
||||
to put in config.yaml) lives in Customize or Guides and is linked, never
|
||||
restated. Naming follows three rules. A reference folder's landing
|
||||
page is titled "Overview"; the folder label already names the group, and
|
||||
repeating it double-nests the sidebar. A page documenting one file carries
|
||||
concept and filename in the title, concept first, where the concept names the
|
||||
file's use, never just its scope ("Project configuration (config.yaml)", "CLI
|
||||
settings (config.json)"): the left edge is what the eye disambiguates in the
|
||||
sidebar, and the filename keeps the title matching what readers search for and
|
||||
see on disk. A file whose name is the term readers use keeps the filename
|
||||
alone as the title (`schema.yaml`), and a page owning one product term takes
|
||||
that term as the title (`spec-driven`), and
|
||||
a page covering several files takes the concept alone (Stores), naming its
|
||||
files in the job line.
|
||||
|
||||
**FAQ is one-liners.** Every FAQ entry is a short answer, a few lines at most, or a
|
||||
router link to the page that owns the topic. How-to content never lives in the FAQ:
|
||||
when an answer outgrows a one-liner, it moves to a guide or reference page and the FAQ
|
||||
entry becomes a pointer.
|
||||
|
||||
## Page index: every page's job
|
||||
|
||||
Each goal below is the page's `>` blockquote verbatim, so the promise here is the promise
|
||||
readers see. A page delivers exactly its goal: content that outgrows it means splitting
|
||||
the page or rewriting the goal in both places, never letting them drift.
|
||||
|
||||
### Start: from "what is this?" to your first archived change
|
||||
|
||||
| Page | Goal |
|
||||
|---|---|
|
||||
| [Overview](start/overview.md) | _TODO: emptied 2026-08-21 for a from-scratch rewrite and pulled from the site (`/docs` redirects to Installation meanwhile); the old goal line was dropped as too weak a pitch. Brief in Notes.md._ |
|
||||
| [Installation](start/installation.md) | Install the `openspec` CLI on your machine, update it, and uninstall it. |
|
||||
| [Set up your project](start/setup.md) | Add OpenSpec to a project: run init, see what it wrote, and adjust it. |
|
||||
| [Quickstart](start/quickstart.md) | Your first change in a new or existing project, from idea to archived. |
|
||||
|
||||
### Guides: understand the system, use it well, bring it to your codebase and team
|
||||
|
||||
| Page | Goal |
|
||||
|---|---|
|
||||
| [Understanding › Concepts](guides/concepts.md) | What the two artifacts are, and how a change describes a diff against current specs. |
|
||||
| [Using › Explore an idea](guides/explore.md) | Think it through with the agent before you commit to a proposal. |
|
||||
| [Using › Review the plan](guides/review-the-plan.md) | The two-minute pass that catches wrong turns before they're code. |
|
||||
| [Using › Apply a change](guides/apply.md) | Run the plan: pacing, context windows, and picking up where you left off. |
|
||||
| [Using › Change course](guides/change-course.md) | Revise a change in flight, or decide it's cleaner to start fresh. |
|
||||
| [Adopting › Existing codebases](guides/existing-codebases.md) | Bring OpenSpec to a codebase with a lot of code and no specs: where to start, what to backfill, and how specs grow from there. |
|
||||
| [Adopting › Teams](guides/teams.md) | Run OpenSpec as a team: what to commit, how a change rides its PR, and when to archive. |
|
||||
|
||||
### Customize: make the workflows fit your project
|
||||
|
||||
| Page | Goal |
|
||||
|---|---|
|
||||
| [Overview](customize/overview.md) | Your options for customizing OpenSpec. |
|
||||
| [Profiles](customize/profiles.md) | Choose which workflows are installed, and whether they install as skills, commands, or both. |
|
||||
| [Project configuration](customize/project-config.md) | Make the workflows plan changes the way you want with a few lines in config.yaml. |
|
||||
| [Schemas](customize/schemas.md) | Change what OpenSpec produces: the artifacts, their order, and their templates. |
|
||||
|
||||
### Multi-repo (beta): plan across repository boundaries
|
||||
|
||||
| Page | Goal |
|
||||
|---|---|
|
||||
| [Stores (beta)](multi-repo/stores.md) | Plan changes that span repositories: one store, many repos. |
|
||||
| [Worksets (beta)](multi-repo/worksets.md) | Open the store and the repos that use it in one editor window, so your agent sees both. |
|
||||
|
||||
### Reference: look it up, exact and complete
|
||||
|
||||
| Page | Goal |
|
||||
|---|---|
|
||||
| [Skills](reference/skills.md) | Every OpenSpec skill: arguments, what it creates, and what it responds with. |
|
||||
| [CLI](reference/cli.md) | The `openspec` terminal commands. |
|
||||
| [Schemas](reference/schemas/index.md) | Every available workflow schema and the artifacts it defines. |
|
||||
| [Schemas › schema.yaml](reference/schemas/schema-yaml.md) | Every field of a schema definition, for reading or writing one. |
|
||||
| [Schemas › spec-driven](reference/schemas/spec-driven/index.md) | The default workflow's artifacts: their order, their formats, and the change folder they produce. |
|
||||
| [Configuration](reference/configuration/index.md) | Every file and setting that changes how OpenSpec behaves, and where each lives. |
|
||||
| [Configuration › Project configuration (config.yaml)](reference/configuration/config-yaml.md) | Every field of openspec/config.yaml: the schema, context, and rules this project plans with. |
|
||||
| [Configuration › Change metadata (.openspec.yaml)](reference/configuration/change-metadata.md) | The supported fields and validation rules for the metadata stored with each change. |
|
||||
| [Configuration › CLI settings (config.json)](reference/configuration/config-json.md) | Every field of config.json: how the openspec CLI behaves on your machine. |
|
||||
| [Configuration › Environment variables](reference/configuration/environment-variables.md) | Every environment variable OpenSpec reads. |
|
||||
| [Configuration › Stores](reference/configuration/stores.md) | The files behind multi-repo stores: registry.yaml and store.yaml, and which root a command uses. |
|
||||
| [Supported tools](reference/supported-tools.md) | Which AI coding tools OpenSpec supports, and each one's command syntax. |
|
||||
| [Glossary](reference/glossary.md) | Every OpenSpec term, one line each. |
|
||||
| [Architecture](reference/architecture/index.md) (held back from the site until drafted) | How OPSX is built: internals for the curious. |
|
||||
| [Architecture › Workflow runs](reference/architecture/workflow-runs.md) | How a workflow run executes, from invocation to written artifacts. |
|
||||
| [Architecture › Design decisions](reference/architecture/design-decisions.md) | Why OPSX works the way it does. |
|
||||
|
||||
### Help: get unstuck (held back from the site until drafted, see Open TODOs)
|
||||
|
||||
| Page | Goal |
|
||||
|---|---|
|
||||
| [FAQ](help/faq.md) | Short answers to the questions that don't need a page. |
|
||||
| [Troubleshooting](help/troubleshooting.md) | When OpenSpec doesn't do what you expected: symptoms and their fixes. |
|
||||
|
||||
### Legacy: land the old workflow safely (held back from the site until drafted, see Open TODOs)
|
||||
|
||||
| Page | Goal |
|
||||
|---|---|
|
||||
| [Migrating from the legacy workflow](help/legacy/migration.md) | Moving from the legacy `/openspec:*` commands to OPSX. |
|
||||
|
||||
## Old docs
|
||||
|
||||
The `docs/` tree is legacy, and the plan is to remove it once docs-lab covers what it
|
||||
owns. It has become a bit of an AI slop mess, so nothing from it is carried over as text
|
||||
(see The bar for every page). Until it's removed it stays untouched: fixes land in
|
||||
docs-lab, never in `docs/`.
|
||||
|
||||
[`sources.md`](sources.md) maps every current `docs/` page to its destination here: the
|
||||
source material while drafting, the redirect list at cutover. Cutover steps are in that
|
||||
file's [Cutover](sources.md#cutover) section.
|
||||
|
||||
## Open TODOs
|
||||
|
||||
- Not started: the Architecture pages (`reference/architecture/index.md`,
|
||||
`workflow-runs.md`, `design-decisions.md`). All three are headings only, so we hid the
|
||||
group from the site on 2026-08-21 (folder entry commented out in
|
||||
`website/docs.sync.config.mjs`). The files stay on disk with a WIP comment. Published
|
||||
pages that link to them (`reference/glossary.md` to the Overview,
|
||||
`customize/project-config.md` to Workflow runs) fall back to the GitHub source until
|
||||
the group is re-listed.
|
||||
- Not started: the Help and Legacy pages (`help/faq.md`, `help/troubleshooting.md`,
|
||||
`help/legacy/migration.md`). FAQ has one answer and the other two are headings only, so
|
||||
we hid both sections from the site on 2026-08-21 (commented out in
|
||||
`website/docs.sync.config.mjs`, same mechanism as Guides). The files stay on disk with
|
||||
a WIP comment. Published pages that link to them (`start/setup.md` to FAQ,
|
||||
`reference/glossary.md` to Migration) fall back to the GitHub source until the
|
||||
sections are re-listed.
|
||||
- Not started: `start/overview.md` is empty on purpose. We cleared the skeleton
|
||||
(headings, narrative beats, diagram gallery) on 2026-08-21 to rewrite the landing page
|
||||
from scratch. The old pitch ("a shared, reviewable plan before code is written")
|
||||
undersells OpenSpec now that plan mode is everywhere; the rewrite should sell keeping
|
||||
larger features on track and aligned (teams, git-native, intended vs implemented
|
||||
behavior, control-loop framing). Brief in `Notes.md` ("Start > Overview"); the diagram
|
||||
candidates went with the gallery and live in git history. Until the rewrite lands the
|
||||
page is off the site: its entry is commented out in `website/docs.sync.config.mjs` and
|
||||
`/docs` redirects to Installation (`website/public/_redirects` plus a fallback in the
|
||||
docs page route). Restoring it is one uncomment plus removing the two redirects. The
|
||||
Teach-once rule still applies: the loop appears here as pitch only.
|
||||
- Product feedback, not a docs task: spec-driven's design `instruction` lists six
|
||||
sections (including Migration Plan and Open Questions) but
|
||||
`schemas/spec-driven/templates/design.md` carries only four headers. The docs show
|
||||
both verbatim; the mismatch belongs upstream. Noted 2026-08-14 while consolidating
|
||||
the spec-driven page.
|
||||
- Product feedback, not a docs task: `openspec store setup --remote` writes the URL
|
||||
into `store.yaml` but never configures a git `origin`, so "setup --remote, then
|
||||
`git push -u origin main`" fails as written; the Stores page shows `git remote add`
|
||||
instead. The pasteable missing-store fix in `openspec doctor` is powered by
|
||||
`references:` remotes, not `store.yaml`. Noted 2026-08-21 while porting the Stores
|
||||
page.
|
||||
- Style guide follow-up (`.agents/skills/write-openspec-docs/writing.md`), from the
|
||||
Stores page's review rounds, 2026-08-21: never use a term the page hasn't shown
|
||||
(say "the `store:` line", not "the pointer"; define by showing the artifact first);
|
||||
when behavior depends on the reader's starting state, enumerate the states and walk
|
||||
each to its outcome; sentence subjects are you, OpenSpec, or your agent, never an
|
||||
implementation unit ("the resolver picks") or a class of things ("store-only
|
||||
projects make..."); when a defined term is reused a section later, re-gloss it in
|
||||
one parenthetical at the point of use.
|
||||
- Fence convention follow-up, 2026-08-21: the Stores page puts commands in `bash`
|
||||
fences with a one-line `#` comment and OpenSpec output in a separate `yaml` fence.
|
||||
`customize/schemas.md` still uses `console` fences with `$` prompts (lines 78, 114,
|
||||
137, 145; prompts at 24 and 115); the style guide should name the convention and
|
||||
that page should adopt it.
|
||||
- Monorepo: message-map row 37 is still a Gap. "Packages treated as separate repos"
|
||||
may land on the Stores page later; not part of the current page.
|
||||
|
||||
- `reference/cli.md` is fully drafted: the command table plus one section per real
|
||||
command, facts captured from working-tree runs (2026-08-11). The `delivery` key that
|
||||
start/setup.md's "Skills, commands, or both" section sets appears there only as
|
||||
command output; its field-level home, `reference/configuration/config-json.md`, is
|
||||
drafted (2026-08-14).
|
||||
- Telemetry is undocumented. `OPENSPEC_TELEMETRY=0` appears nowhere in the tree; the
|
||||
Deno install command grants `--allow-net=edge.openspec.dev` with no explanation (the
|
||||
telemetry gloss was deliberately pulled pending a real home). The home now exists:
|
||||
write `reference/configuration/environment-variables.md` (the env var, what's
|
||||
collected, the opt-out, the CI auto-disable), then have the Deno section link to it
|
||||
to explain the flag. Noted 2026-08-07; home settled 2026-08-10.
|
||||
- Product feedback, not a docs task: init doesn't say when the global profile changed what
|
||||
it wrote. A machine with `profile: custom` silently installs a different workflow set
|
||||
than a stock machine, and nothing in the init output names the profile that shaped it.
|
||||
Noted 2026-08-05 while verifying installation.md; track upstream, don't paper over in prose.
|
||||
- Product feedback, not a docs task: drop the sync-specs skill from the default set; its
|
||||
job reads as reference content, not a workflow, and it pads the skill list every reader
|
||||
scans. Noted 2026-08-08 while writing start/setup.md's workflow tree.
|
||||
- Product feedback, not a docs task: make the shared `.agents/` folder the default install
|
||||
target for every tool, with tool-specific folders (`.claude/`, ...) the exception. The
|
||||
docs already prefer `.agents/` in examples; the product should match. Noted 2026-08-08.
|
||||
- `help/troubleshooting.md`'s skeleton has no section for install-time failures
|
||||
(`command not found`, wrong Node version, PATH). Old `docs/troubleshooting.md` covered
|
||||
them; `start/installation.md` carries caveats inline but there is no symptom-to-fix
|
||||
home. Add a section or an installation.md anchor. Noted 2026-08-10 during the old-docs
|
||||
message audit.
|
||||
- Missing guide: the iterative flow. new/continue/fast-forward have no owner for the
|
||||
judgment: what the flow is, when to pick it over propose, and ff vs continue. Old
|
||||
`docs/workflows.md` covered it (Two Modes, When to Use What); `sources.md` routes that
|
||||
page's mechanics to `guides/apply.md` and contracts to `reference/skills.md`, so the
|
||||
choice itself landed nowhere. Likely a Guides › Using page slotted between Explore and
|
||||
Review the plan, with a pointer to `customize/profiles.md` (the skills are optional
|
||||
workflows outside the core set). Salvage only the ff-vs-continue rule of thumb; the rest of
|
||||
workflows.md is unverified. Noted 2026-08-11. Related: message-map row 29 words
|
||||
apply.md's pacing question as drafting-time pacing, the same creation-stage choice;
|
||||
fix that row's wording or owner when this guide lands. Noted 2026-08-14.
|
||||
- Missing guide: working with git. OpenSpec never touches git, so every git decision
|
||||
lands on the reader with no page to answer it: do you branch before or after propose,
|
||||
does a task get its own commit, what goes in the PR, where does the archive commit
|
||||
land. `guides/teams.md` owns the archive-vs-PR ordering; the rest is unowned. Likely a
|
||||
`guides/` file in the Adoption group. Noted 2026-08-08.
|
||||
- `customize/skills.md` is parked: the skeleton stays on disk but is out of the page
|
||||
index, the sidebar, and the sync config. Editing installed skill prompts has no good
|
||||
answer yet (`openspec update` overwrites edits); the message map keeps the question as
|
||||
a Gap. Revive when the product has a real story for surviving updates. Parked 2026-08-14.
|
||||
- `guides/examples.md` is parked: the skeleton stays on disk but is out of the page
|
||||
index, the sidebar, and the sync config. Contrived examples teach the wrong lesson for
|
||||
this product; revive the page when real archived changes from actual usage can fill it.
|
||||
The content plan (weak-vs-reviewed pairs, archived-changes gallery) is in the file's
|
||||
comment. Parked 2026-08-11.
|
||||
- Product feedback, not a docs task: "expanded" survives in product strings and the
|
||||
update workflow is unlabeled in the picker. The only stored profile values are core
|
||||
and custom, but `src/core/templates/workflows/update-change.ts` says "expanded-profile
|
||||
workflow", and `WORKFLOW_PROMPT_META` (`src/commands/config.ts`) has no `update` entry,
|
||||
so the `openspec config` workflow picker renders a core workflow as raw `update` /
|
||||
"Workflow: update". Docs standardized on core/custom with "expand the set" as a verb
|
||||
(2026-08-12). Noted 2026-08-12 during the glossary product sweep.
|
||||
- Product feedback, not a docs task: converge on skills only, soon. A workflow's skill and
|
||||
command are the same instructions, Claude Code has already merged commands into skills
|
||||
upstream, and setup spends a whole subsection explaining why two forms exist. Every page
|
||||
gets simpler when commands go. Noted 2026-08-08 while writing start/setup.md.
|
||||
- Website QOL backlog, site build not prose: i18n; AI search layered on the stock keyword
|
||||
search (an ask-the-docs answer box, not just matching); proper light/dark themes that
|
||||
carry the Survey palette (DESIGN.md tokens) into both modes instead of a stock dark
|
||||
theme. Candidates to bundle in the same pass: `llms.txt` plus a per-page "copy as
|
||||
Markdown" button so agents can ingest pages, copy buttons on code blocks, and
|
||||
"edit this page on GitHub" links. Noted 2026-08-11.
|
||||
@@ -1,32 +0,0 @@
|
||||
# Overview
|
||||
|
||||
> Your options for customizing OpenSpec.
|
||||
|
||||
OpenSpec supports multiple customization options. This page shows what each one changes and when to use it.
|
||||
|
||||
## What you can customize
|
||||
|
||||
| Option | What it changes | Use it when |
|
||||
|---|---|---|
|
||||
| [Profiles](profiles.md) | Which workflows are installed, and whether as skills, commands, or both | You want additional workflows and working patterns, or to remove workflows you don't need |
|
||||
| [Project configuration](project-config.md) | The instructions injected into every workflow run: context, rules, and operation guidance (`config.yaml`) | You want changes planned your way, like tasks always including Playwright tests |
|
||||
| [Schemas](schemas.md) | What OpenSpec produces: the artifacts, their order, and their templates | Changes should produce different planning files, sections, or formats |
|
||||
|
||||
## Not sure which to use?
|
||||
|
||||
Config and schemas are two levels of customization. Pick by how hands-on you want to get:
|
||||
|
||||
- **Start with [project configuration](project-config.md)**: it's lighter, and for most projects it's enough. You keep the standard artifacts and add your own context and rules on top.
|
||||
- **Fork a [schema](schemas.md) when adding isn't enough**: config only adds on top of the core workflow. It can add a rule like "tasks always include tests," but it can't drop the design doc or rename a file. That's schema territory. Forking gives you your own copy to edit.
|
||||
|
||||
*"Fork" here means the `openspec schema fork` command, not forking a git repo. [Schemas](schemas.md) has the details.*
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
a["The workflows should know my stack and conventions"] --> config
|
||||
b["One artifact needs an extra rule, like tasks always including tests"] --> config
|
||||
c["Different artifacts, file names, or document structure"] --> schema
|
||||
d["The built-in instructions say things my team does differently"] --> schema
|
||||
config["Project configuration<br/>(config.yaml)"]
|
||||
schema["Fork a schema<br/>(openspec schema fork)"]
|
||||
```
|
||||
@@ -1,88 +0,0 @@
|
||||
# Profiles
|
||||
|
||||
> Choose which workflows are installed, and whether they install as skills, commands, or both.
|
||||
|
||||
A profile is your preference for which OpenSpec workflows (the [skills and commands](../start/setup.md#the-workflow-files-skills-and-commands) in your AI tool) are installed across your machine. The default profile is `core`. Include or exclude workflows and your selection is saved as the `custom` profile.
|
||||
|
||||
## The core set
|
||||
|
||||
The `core` profile installs six workflows, covering the whole loop from idea to archive:
|
||||
|
||||
| Workflow | What it's for |
|
||||
|---|---|
|
||||
| [`explore`](../reference/skills.md#openspec-explore) | Think through an idea before it becomes a change proposal |
|
||||
| [`propose`](../reference/skills.md#openspec-propose) | Create a change proposal and generate all its planning artifacts in one step |
|
||||
| [`apply`](../reference/skills.md#openspec-apply-change) | Implement a change proposal's tasks |
|
||||
| [`update`](../reference/skills.md#openspec-update-change) | Revise a change proposal's existing planning artifacts |
|
||||
| [`sync`](../reference/skills.md#openspec-sync-specs) | Merge a change proposal's spec updates into `specs/` without archiving it |
|
||||
| [`archive`](../reference/skills.md#openspec-archive-change) | Move a finished change proposal to the archive |
|
||||
|
||||
Each links to its full contract: arguments, what it creates, and what it responds with.
|
||||
|
||||
## Expanding the set: optional workflows
|
||||
|
||||
Six more workflows are available beyond the core set. Three of them (`new`, `continue`, `ff`) create a change proposal artifact by artifact, instead of all at once like `propose`.
|
||||
|
||||
| Workflow | What it's for |
|
||||
|---|---|
|
||||
| [`new`](../reference/skills.md#openspec-new-change) | Start a change proposal as an empty scaffold |
|
||||
| [`continue`](../reference/skills.md#openspec-continue-change) | Create the next planning artifact in a change proposal, one at a time |
|
||||
| [`ff`](../reference/skills.md#openspec-ff-change) | Create a change proposal and every planning artifact implementation needs, in one pass |
|
||||
| [`verify`](../reference/skills.md#openspec-verify-change) | Check that the implementation matches the change proposal's artifacts |
|
||||
| [`bulk-archive`](../reference/skills.md#openspec-bulk-archive-change) | Archive several change proposals at once |
|
||||
| [`onboard`](../reference/skills.md#openspec-onboard) | Learn the workflow by doing one real change proposal end to end |
|
||||
|
||||
To change the set, run the interactive picker:
|
||||
|
||||
```bash
|
||||
openspec config profile
|
||||
```
|
||||
|
||||
The picker asks what to configure ([delivery](#delivery-skills-commands-or-both), workflows, or both), then lists all twelve workflows as checkboxes, with the installed ones checked. Any selection that isn't exactly the core six is saved as the `custom` profile, so you can also uncheck core workflows you don't use.
|
||||
|
||||
## Delivery: skills, commands, or both
|
||||
|
||||
Delivery is a profile setting that lets you choose to have only skills or only commands installed. The default is `both`. [Set up your project](../start/setup.md#the-workflow-files-skills-and-commands) explains the two forms and why both exist. The field's exact contract is in [CLI settings (config.json)](../reference/configuration/config-json.md#delivery).
|
||||
|
||||
Two ways to change it:
|
||||
|
||||
**Interactively**: run `openspec config profile` and choose "Delivery only". Here's switching to skills only:
|
||||
|
||||
```
|
||||
Current profile settings
|
||||
Delivery: both
|
||||
|
||||
? What do you want to configure? Delivery only
|
||||
? Delivery mode (how workflows are installed): Skills only
|
||||
|
||||
Config changes:
|
||||
delivery: both -> skills
|
||||
? Apply changes to this project now? (Y/n) y
|
||||
```
|
||||
|
||||
**Directly**: one command, no prompts:
|
||||
|
||||
```bash
|
||||
openspec config set delivery skills # or: both, commands
|
||||
```
|
||||
|
||||
Delivery never changes the profile name. `core` and `custom` describe the workflow set only, and switching back to `core` keeps your delivery setting.
|
||||
|
||||
## Switching profiles
|
||||
|
||||
Switching is two steps: change the profile on your machine, then update each project to apply it.
|
||||
|
||||
1. Change the profile:
|
||||
|
||||
```bash
|
||||
openspec config profile # interactive
|
||||
openspec config profile core # reset to the core six (keeps delivery)
|
||||
```
|
||||
|
||||
2. Run the update in each project you work in:
|
||||
|
||||
```bash
|
||||
openspec update
|
||||
```
|
||||
|
||||
When your current directory is an existing OpenSpec project, the interactive flow offers to run step 2 there for you.
|
||||
@@ -1,122 +0,0 @@
|
||||
# Project configuration
|
||||
|
||||
> Make the workflows plan changes the way you want with a few lines in config.yaml.
|
||||
|
||||
`openspec/config.yaml` tells the workflows how you want changes planned.
|
||||
|
||||
For example, the following configuration updates the creation rules for the [tasks.md](../reference/schemas/spec-driven/index.md) artifact:
|
||||
|
||||
```yaml
|
||||
rules:
|
||||
tasks:
|
||||
- End every task with a commit
|
||||
```
|
||||
|
||||
When the agent runs, it pulls from these rules and ensures every task ends with a commit step.
|
||||
|
||||
Keep rules short. Everything here lands in the agent's context, and verbose rules can make the output worse.
|
||||
|
||||
## How it works
|
||||
|
||||
config.yaml holds instructions the agent receives when it creates artifacts or works through the workflow.
|
||||
|
||||
Here's what happens on every run:
|
||||
|
||||
1. You run a workflow (e.g. `/openspec-propose`).
|
||||
2. The agent calls the [`openspec instructions`](../reference/cli.md) command.
|
||||
3. The command reads your context and rules from config.yaml.
|
||||
4. OpenSpec's built-in instructions and your customizations are combined into a single prompt for the agent.
|
||||
5. The agent follows that prompt to write the artifact.
|
||||
|
||||
For example, with a `context` field and the rule from the top of this page, here's what [`openspec instructions`](../reference/cli.md) returns for tasks.md (trimmed and annotated):
|
||||
|
||||
```xml
|
||||
<artifact id="tasks" change="add-dark-mode" schema="spec-driven">
|
||||
|
||||
<!-- From your config.yaml: context -->
|
||||
<project_context>
|
||||
Tech stack: TypeScript, Node.js
|
||||
Domain: e-commerce platform
|
||||
</project_context>
|
||||
|
||||
<!-- From your config.yaml: rules for tasks -->
|
||||
<rules>
|
||||
- End every task with a commit
|
||||
</rules>
|
||||
|
||||
<!-- From OpenSpec: the built-in guidance -->
|
||||
<instruction>
|
||||
...how to write a good tasks.md...
|
||||
</instruction>
|
||||
|
||||
<template>
|
||||
...the tasks.md structure to fill in...
|
||||
</template>
|
||||
|
||||
</artifact>
|
||||
```
|
||||
|
||||
Your config arrives first, then OpenSpec's built-in instruction and template. Rules add to the built-ins and never replace them. Edits to config.yaml reach the agent on the next run.
|
||||
|
||||
## The fields
|
||||
|
||||
Three fields shape what the agent receives. Each field's exact contract (types, limits, validation) is in [Project configuration (config.yaml)](../reference/configuration/config-yaml.md).
|
||||
|
||||
| Field | What it does | Injected into |
|
||||
|---|---|---|
|
||||
| `context` | Instructions the agent always receives | Everything: every artifact, `apply`, `archive` |
|
||||
| `rules` | Extra instructions for one artifact | Only that artifact's creation |
|
||||
| `operations` | Guidance for how a workflow step is carried out | Only `apply` and `archive` |
|
||||
|
||||
config.yaml's other fields (`schema`, `store`, `references`) select which schema and which OpenSpec root a project uses. The contract page covers them.
|
||||
|
||||
The last column is exact, so a field reaches only the steps listed there. In particular, `verify` never receives `rules`. It checks the implementation against the artifacts as written.
|
||||
|
||||
### context
|
||||
|
||||
`context` is what the agent should know up front when planning a change, whether it's creating an artifact, applying tasks, or archiving:
|
||||
|
||||
```yaml
|
||||
context: |
|
||||
We ship cross-platform; designs and tasks must cover Windows, macOS, and Linux
|
||||
Tech stack: TypeScript, Node.js, Commander.js
|
||||
We use conventional commits
|
||||
```
|
||||
|
||||
This is planning context, not project documentation. Add a fact when it should shape every plan, like the cross-platform line above. Leave out anything the agent can learn by reading the code.
|
||||
|
||||
**Another language**: because context reaches every artifact, it's also how you change the output language. One line, like `Write all artifacts in Spanish.`, switches every proposal, spec, and tasks file the workflows write.
|
||||
|
||||
### rules
|
||||
|
||||
`rules` attach to one artifact, keyed by artifact id. Each line is added to that artifact's built-in guidance:
|
||||
|
||||
```yaml
|
||||
rules:
|
||||
proposal:
|
||||
- Keep proposals under 500 words
|
||||
tasks:
|
||||
- Every UI task includes a Playwright test
|
||||
```
|
||||
|
||||
Proposals now stay short and tasks.md always plans browser tests. Every other artifact is untouched.
|
||||
|
||||
### operations
|
||||
|
||||
`operations` guides how the agent carries out `apply` and `archive`, rather than what artifacts say:
|
||||
|
||||
```yaml
|
||||
operations:
|
||||
apply:
|
||||
guidance:
|
||||
- Run the linter before marking a task complete
|
||||
archive:
|
||||
guidance:
|
||||
- Summarize what shipped before archiving
|
||||
```
|
||||
|
||||
During apply, the agent lints as it completes tasks. During archive, it closes with a summary.
|
||||
|
||||
## When config.yaml isn't enough
|
||||
|
||||
Config adds instructions on top of the standard workflow, but it can't change which artifacts exist or how they're structured. When you want that level of control, or rules aren't steering behavior consistently, [fork a schema](schemas.md).
|
||||
@@ -1,164 +0,0 @@
|
||||
# Schemas
|
||||
|
||||
> 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](../reference/schemas/spec-driven/index.md), 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.
|
||||
|
||||
## Where schemas live
|
||||
|
||||
OpenSpec looks for a schema in three places, in order, and uses the first one it finds:
|
||||
|
||||
1. **Your project**: `openspec/schemas/`, committed with the repo so your whole team gets it.
|
||||
2. **Your machine**: `~/.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.
|
||||
3. **The package**: the built-ins, like `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
|
||||
```
|
||||
|
||||
## What's in a schema
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
- **schema.yaml**: declares each artifact, the file it generates, the template it starts from, what it requires first, and the instruction the agent receives when creating it. Every field's contract is in [schema.yaml](../reference/schemas/schema-yaml.md).
|
||||
- **templates/**: one markdown skeleton per artifact, which the agent fills in.
|
||||
|
||||
Here's the tasks artifact's entry in schema.yaml, trimmed:
|
||||
|
||||
```yaml
|
||||
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.
|
||||
|
||||
## Creating your own custom schema
|
||||
|
||||
There are two ways to get your own schema:
|
||||
|
||||
1. **Fork an existing schema** and edit your copy. Start here when an existing schema is close to what you want, because everything in it already works.
|
||||
2. **Start from scratch** when none of them fit, scaffolding an empty schema with `openspec schema init`.
|
||||
|
||||
### Fork an existing schema
|
||||
|
||||
1. Fork the schema you want to start from, running from your project root:
|
||||
|
||||
```console
|
||||
$ 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.
|
||||
|
||||
2. Edit the copy: schema.yaml and the templates. [Editing your fork](#editing-your-fork) covers what to change.
|
||||
|
||||
3. Validate it:
|
||||
|
||||
```bash
|
||||
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.
|
||||
|
||||
4. Point your project at it in openspec/config.yaml. This step is yours to do because fork leaves config.yaml untouched:
|
||||
|
||||
```yaml
|
||||
schema: spec-driven-custom
|
||||
```
|
||||
|
||||
5. 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](#where-schemas-live) explains.
|
||||
|
||||
### Start from scratch
|
||||
|
||||
`openspec schema init` scaffolds a new schema instead of copying one:
|
||||
|
||||
```console
|
||||
$ 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.
|
||||
|
||||
## Editing your fork
|
||||
|
||||
A fork has two kinds of files to edit:
|
||||
|
||||
- **templates/** change the skeleton of each document. Add a section to the tasks template and every new tasks.md starts with it. Keep the `#` title on the first line: the artifact inherits it, so every generated file opens as a titled document.
|
||||
- **schema.yaml** changes the workflow itself: which artifacts exist, what each one requires first, and the instruction the agent gets when creating it.
|
||||
|
||||
For example, to drop the design document for a leaner flow:
|
||||
|
||||
1. Delete the `design` entry from schema.yaml.
|
||||
2. Remove `design` from the `requires` list of `tasks`.
|
||||
3. Validate:
|
||||
|
||||
```console
|
||||
$ openspec schema validate spec-driven-custom
|
||||
|
||||
✓ Schema 'spec-driven-custom' is valid
|
||||
```
|
||||
|
||||
Skip step 2 and validate catches it:
|
||||
|
||||
```console
|
||||
✗ 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.
|
||||
|
||||
## A fork is a snapshot
|
||||
|
||||
`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 schemas
|
||||
|
||||
Sharing a schema means copying its folder.
|
||||
|
||||
- **With your team**: commit `openspec/schemas/` and everyone on the repo uses it.
|
||||
- **Across your projects**: put the folder in the user-level directory from [Where schemas live](#where-schemas-live).
|
||||
- **From the community**: the [community catalog](https://github.com/Fission-AI/OpenSpec/blob/main/docs/customization.md#community-schemas) lists shared schemas. Copy one into `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.
|
||||
@@ -1,14 +0,0 @@
|
||||
# Customizing skills
|
||||
|
||||
> Edit the installed skill prompts directly: what you can change, and what update overwrites.
|
||||
|
||||
<!-- PARKED 2026-08-14 (README TODO): out of the page index, sidebar, and sync config.
|
||||
No good answer yet for edits surviving `openspec update`; the message map keeps
|
||||
"How should a user edit the installed skill prompts?" as a Gap. Skeleton below is
|
||||
the shape to revive. The honest page for the update-clobber caveat. -->
|
||||
|
||||
## What you can change
|
||||
|
||||
## What openspec update overwrites
|
||||
|
||||
## Supported alternatives
|
||||
@@ -1,11 +0,0 @@
|
||||
# Apply a change
|
||||
|
||||
> Run the plan: pacing, context windows, and picking up where you left off.
|
||||
|
||||
<!-- Skeleton: headings only. Promoted out of examples.md in review round 2. -->
|
||||
|
||||
## Task by task or all at once
|
||||
|
||||
## Managing the context window
|
||||
|
||||
## Continue and fast-forward
|
||||
@@ -1,11 +0,0 @@
|
||||
# Change course
|
||||
|
||||
> Revise a change in flight, or decide it's cleaner to start fresh.
|
||||
|
||||
<!-- Skeleton: headings only. -->
|
||||
|
||||
## Update or start fresh?
|
||||
|
||||
## Revising artifacts with openspec-update-change
|
||||
|
||||
## Advanced: revising mid-implementation
|
||||
@@ -1,9 +0,0 @@
|
||||
# Concepts
|
||||
|
||||
> What the two artifacts are, and how a change describes a diff against current specs.
|
||||
|
||||
<!-- Skeleton: headings only. Narrowed in review round 3 (dedup pass). The quickstart's archive file-steps absorbed the loop mechanics this page once planned to own, so the loop section is gone: the quickstart is the loop's only teacher, and core-vs-optional moved to customize/profiles.md. The fixed-vs-shapeable section was cut entirely (customize/overview.md dropped that framing in review, 2026-08-14: it opens straight on the options and never says what can't be changed). What remains is the one explanation this page owns: the artifacts. Specs absorbs "What a spec is"; Changes owns the delta concept: one worked delta block (ADDED/MODIFIED/REMOVED, from docs/concepts.md's core) showing a change as a diff against current specs; the file-format rules live in reference/schemas/spec-driven/index.md (Delta specs section). Disk paths appear inline with the concept that owns them (specs/ under Specs, changes/ under Changes), never as a layout section. Close with link lines: quickstart for the loop, customize/overview for the customization options. When to archive relative to a branch or PR stays in guides/teams.md. -->
|
||||
|
||||
## Specs: the system as built
|
||||
|
||||
## Changes: a folder of deltas
|
||||
@@ -1,16 +0,0 @@
|
||||
# Examples
|
||||
|
||||
> See what a good change looks like: real drafts, what review caught, and the fixes.
|
||||
|
||||
<!-- Skeleton: headings only. PARKED 2026-08-11: out of the README index and sync config. Contrived examples teach the wrong lesson for this product; the page waits for real archived changes from actual usage. Plan when revived: weak-vs-reviewed pairs (4) plus an archived-changes gallery. Earlier decisions still hold: slimmed in review round 2, purely example pairs; apply technique lives in guides/apply.md. -->
|
||||
|
||||
|
||||
## Adding a feature to an undocumented codebase
|
||||
|
||||
## Changing an API without breaking clients
|
||||
|
||||
## A behavior-preserving refactor
|
||||
|
||||
## A database migration with rollback
|
||||
|
||||
## Real archived changes
|
||||
@@ -1,13 +0,0 @@
|
||||
# Existing codebases
|
||||
|
||||
> Bring OpenSpec to a codebase with a lot of code and no specs: where to start, what to backfill, and how specs grow from there.
|
||||
|
||||
<!-- Skeleton: headings only. Rescoped 2026-08-11: the page is the adoption guide for legacy codebases (a lot of code, no specs), not just the backfill task; "Specs for existing code" is now one section. The opening section owns "you don't need specs first": the quickstart runs on an existing repo as-is, and specs accumulate through changes. Source: docs/existing-projects.md. When prose lands, reshape to the Guides skeleton (one-line what, quickstart link, 80% path, Advanced). -->
|
||||
|
||||
## Start with a change
|
||||
|
||||
## Specs for existing code
|
||||
|
||||
## Working from a PRD
|
||||
|
||||
## Organizing specs as they grow
|
||||
@@ -1,17 +0,0 @@
|
||||
# Explore an idea
|
||||
|
||||
> Think it through with the agent before you commit to a proposal.
|
||||
|
||||
<!-- Skeleton: headings only. -->
|
||||
|
||||
## When to explore first
|
||||
|
||||
## A real explore session
|
||||
|
||||
## From exploration to proposal
|
||||
|
||||
## Advanced
|
||||
|
||||
### Exploring mid-change
|
||||
|
||||
### Challenging a draft plan
|
||||
@@ -1,15 +0,0 @@
|
||||
# Review the plan
|
||||
|
||||
> The two-minute pass that catches wrong turns before they're code.
|
||||
|
||||
<!-- Skeleton: headings only. -->
|
||||
|
||||
## The two-minute pass
|
||||
|
||||
## What good requirements look like
|
||||
|
||||
## What good scenarios look like
|
||||
|
||||
## Pushing back
|
||||
|
||||
## Advanced: verify after apply
|
||||
@@ -1,17 +0,0 @@
|
||||
# Teams
|
||||
|
||||
> Run OpenSpec as a team: what to commit, how a change rides its PR, and when to archive.
|
||||
|
||||
<!-- Skeleton: headings only. Retitled from "Teams & parallel changes" 2026-08-11: the page's job is running OpenSpec in a team; parallel changes stays as the touching-one-spec section, and the general parallel-changes answer (solo included) remains an unowned gap in message-map.md. Expanded in review: this page owns the git/PR conventions (the quickstart's archive step shows the mechanism; this page owns timing). Source for all three new sections: docs/team-workflow.md. "A change is a branch and a PR": one branch carries the change folder and the code, so the PR shows the plan and the diff together. "Review in pull requests": reviewer order proposal → spec delta → code; approach disagreements land on the proposal, not across 300 lines of diff. "When to archive": after the PR merges (recommended, specs/ only advances with shipped work) vs inside the PR (simpler, noisier diff); pick one and be consistent. Proposal-first PRs (plan reviewed before implementation starts) go under Advanced. -->
|
||||
|
||||
## Checking openspec/ into git
|
||||
|
||||
## A change is a branch and a PR
|
||||
|
||||
## Review in pull requests
|
||||
|
||||
## When to archive
|
||||
|
||||
## Parallel changes touching one spec
|
||||
|
||||
## Advanced: conventions for larger teams
|
||||
@@ -1,24 +0,0 @@
|
||||
# FAQ
|
||||
|
||||
> Short answers to the questions that don't need a page.
|
||||
|
||||
<!-- WIP, on the todo list: this page is not written yet and is held back from the
|
||||
site (its section is commented out in website/docs.sync.config.mjs, 2026-08-21). The
|
||||
file stays so the structure and inbound links survive; re-list it in the sync config
|
||||
once the prose lands. -->
|
||||
|
||||
<!-- Every entry is a one-liner: a short answer or a router link to the page that owns the topic; how-to content never lives here (README's "FAQ is one-liners" rule). Update/uninstall moved to installation.md; the skills-missing fix and Getting help live in troubleshooting.md; the git question is a one-line yes routing to guides/teams.md, which owns the team conventions. Unfilled headings are skeletons. -->
|
||||
|
||||
## Should openspec/ be checked into git?
|
||||
|
||||
## What runs in the terminal, and what in chat?
|
||||
|
||||
## Does OpenSpec work with my tool?
|
||||
|
||||
If it has a row in the [support matrix](../reference/supported-tools.md), yes.
|
||||
Pick its id at init. If it isn't listed but reads the shared `.agents/skills/`
|
||||
folder, pick **Other / Universal** (`--tools agents`), covered by the support
|
||||
matrix's Other / Universal section. If neither, request it in the
|
||||
[OpenSpec repo](https://github.com/Fission-AI/OpenSpec/issues).
|
||||
|
||||
## Where did the old /openspec:* commands go?
|
||||
@@ -1,18 +0,0 @@
|
||||
# Migrating from the legacy workflow
|
||||
|
||||
> Moving from the legacy `/openspec:*` commands to OPSX.
|
||||
|
||||
<!-- WIP, on the todo list: this page is not written yet and is held back from the
|
||||
site (its section is commented out in website/docs.sync.config.mjs, 2026-08-21). The
|
||||
file stays so the structure and inbound links survive; re-list it in the sync config
|
||||
once the prose lands. -->
|
||||
|
||||
<!-- Skeleton: headings only. -->
|
||||
|
||||
## What changed and why
|
||||
|
||||
## Command mapping
|
||||
|
||||
## Migrating a project
|
||||
|
||||
## Behavior differences
|
||||
@@ -1,20 +0,0 @@
|
||||
# Troubleshooting
|
||||
|
||||
> When OpenSpec doesn't do what you expected: symptoms and their fixes.
|
||||
|
||||
<!-- WIP, on the todo list: this page is not written yet and is held back from the
|
||||
site (its section is commented out in website/docs.sync.config.mjs, 2026-08-21). The
|
||||
file stays so the structure and inbound links survive; re-list it in the sync config
|
||||
once the prose lands. -->
|
||||
|
||||
<!-- Skeleton: headings only. Canonical home for symptom-to-fix, including the skills-missing checklist. -->
|
||||
|
||||
## Skills don't appear in chat
|
||||
|
||||
## The agent ignores the workflow
|
||||
|
||||
## Validation failures
|
||||
|
||||
## Sync and archive issues
|
||||
|
||||
## Getting help
|
||||
@@ -1,65 +0,0 @@
|
||||
# Message map: the questions the docs must answer, and where
|
||||
|
||||
The [README](README.md) index runs page to job. This file runs the other way: one flat
|
||||
list of the questions we need the docs to answer, each pointing at the group and page
|
||||
that owns the answer. Status says whether that answer exists yet: **Answered** (the
|
||||
owning page's prose has landed), **Skeleton** (owner assigned, page is headings only),
|
||||
**Gap** (no owner), **Off-site** (answered outside these docs by decision). Flip a row
|
||||
to Answered when its page's prose lands. Rows follow the sidebar order of the owning
|
||||
page; gaps sit where their proposed home would fall, and off-site rows go last. Keep
|
||||
rows coarse (question to page, never sentence to section) so this stays cheap to
|
||||
maintain.
|
||||
|
||||
| Question | Answered by | Status |
|
||||
|---|---|---|
|
||||
| How do we pitch the core idea (keeping larger features on track and aligned, not just a plan before code)? | [Start › Overview](start/overview.md) (emptied 2026-08-21 for a from-scratch rewrite and pulled from the site until then; brief in Notes.md) | Skeleton |
|
||||
| How does someone decide OpenSpec is worth their time? | [Start › Overview](start/overview.md) (emptied 2026-08-21, see row above) | Skeleton |
|
||||
| How should a user install the CLI, update it, uninstall it? | [Start › Installation](start/installation.md) | Answered |
|
||||
| How can a user hand install and setup to their AI assistant? | [Start › Installation](start/installation.md), the install.md prompt | Answered |
|
||||
| How should a user add OpenSpec to their repo? | [Start › Set up your project](start/setup.md) | Answered |
|
||||
| How do the workflows get into a user's tool, and why skills and commands both? | [Start › Set up your project](start/setup.md) | Answered |
|
||||
| How do we teach the loop: propose, review, apply, archive? | [Start › Quickstart](start/quickstart.md) | Answered |
|
||||
| How should a user run their first change end to end? | [Start › Quickstart](start/quickstart.md) | Answered |
|
||||
| How does a user know which prompts go in the AI chat and which commands in the terminal? | [Start › Quickstart](start/quickstart.md) inline with each step, then [Help › FAQ](help/faq.md) | Answered |
|
||||
| How do we explain what specs and changes are? | [Guides › Understanding › Concepts](guides/concepts.md) | Skeleton |
|
||||
| How should a user think through an idea before proposing? | [Guides › Using › Explore an idea](guides/explore.md) | Skeleton |
|
||||
| How should a user review a plan? | [Guides › Using › Review the plan](guides/review-the-plan.md) | Skeleton |
|
||||
| How does a user check the implementation matches the plan before archiving? | [Guides › Using › Review the plan](guides/review-the-plan.md), the verify pass | Skeleton |
|
||||
| How should a user run a plan across sessions and context limits? | [Guides › Using › Apply a change](guides/apply.md) | Skeleton |
|
||||
| How should a user pace the plan: draft everything at once, or artifact by artifact? | [Guides › Using › Apply a change](guides/apply.md), continue and fast-forward | Skeleton |
|
||||
| How do we explain the standard flow (propose drafts every artifact in one step) vs the iterative flow (new creates the change, continue drafts the next artifact, fast-forward catches up)? | [Start › Quickstart](start/quickstart.md) teaches only the standard flow; [Guides › Using › Apply a change](guides/apply.md) owns pacing once a change exists; [Reference › Skills](reference/skills.md) holds the new/continue/ff contracts; [Customize › Profiles](customize/profiles.md) covers installing them; a [README](README.md) TODO proposes a Using guide | Gap |
|
||||
| How should a user change direction mid-change, or bail out? | [Guides › Using › Change course](guides/change-course.md) | Skeleton |
|
||||
| How should a team run OpenSpec together? | [Guides › Adopting › Teams](guides/teams.md) | Skeleton |
|
||||
| How should a user work on several changes at once? | [Guides › Adopting › Teams](guides/teams.md) owns the touching-one-spec collision case; the general answer (solo included, not just teams) has no owner yet | Gap |
|
||||
| How should a user handle git across the loop: branching, commits, PRs? | Only archive-vs-PR ordering is owned, by [Guides › Adopting › Teams](guides/teams.md); README TODO proposes a guide | Gap |
|
||||
| What does a good change look like? | `guides/examples.md` is parked until real archived changes can fill it (README TODO); no published owner | Gap |
|
||||
| How should a user adopt OpenSpec on code that already exists? | [Guides › Adopting › Existing codebases](guides/existing-codebases.md) | Skeleton |
|
||||
| How should a user run OpenSpec in a monorepo? | Legacy `docs/existing-projects.md` owned it (one `openspec/` at the repo root, domains map to packages); likely home is [Guides › Adopting › Existing codebases](guides/existing-codebases.md), with [Multi-repo › Stores](multi-repo/stores.md) taking packages treated as separate repos | Gap |
|
||||
| How do we explain what's customizable in OpenSpec? | [Customize › Overview](customize/overview.md) | Answered |
|
||||
| How does a user pick the right customization level, and when should they escalate from config to schemas? | [Customize › Overview](customize/overview.md), the "Not sure which to use?" section | Answered |
|
||||
| How should a user choose which workflows are installed? | [Customize › Profiles](customize/profiles.md) | Answered |
|
||||
| How does a user switch to skills only or commands only? | [Customize › Profiles](customize/profiles.md), Delivery section; [Start › Set up your project](start/setup.md) owns why both forms exist | Answered |
|
||||
| How does a user make the workflows plan changes their way: context, rules, and guidance? | [Customize › Project configuration](customize/project-config.md) | Answered |
|
||||
| How does a user get artifacts written in a language other than English? | [Customize › Project configuration](customize/project-config.md), the context section's "Another language" note | Answered |
|
||||
| How should a user change what OpenSpec produces? | [Customize › Schemas](customize/schemas.md), with the fork walkthrough in "Creating your own custom schema" | Answered |
|
||||
| How should a user edit the installed skill prompts? | No owner: `customize/skills.md` is parked (README TODO) until there's a good answer to `openspec update` overwriting edits | Gap |
|
||||
| How should a user run OpenSpec across multiple repos? | [Multi-repo › Stores](multi-repo/stores.md); [Start › Set up your project](start/setup.md) routes there from "Pick where OpenSpec lives" | Answered |
|
||||
| How should a user plan a change that spans repos? | [Multi-repo › Stores](multi-repo/stores.md) | Answered |
|
||||
| What does each skill do, and when should a user reach for it? | [Reference › Skills](reference/skills.md) | Answered |
|
||||
| Where does a user look up a terminal command? | [Reference › CLI](reference/cli.md) | Answered |
|
||||
| How does a user learn what telemetry is collected, and opt out? | [Reference › Configuration › Environment variables](reference/configuration/environment-variables.md) owns the facts (was a README-TODO gap); [Help › FAQ](help/faq.md) routes searchers there | Skeleton |
|
||||
| Where does a user look up an artifact's format, or a schema definition's fields? | [Reference › Schemas](reference/schemas/index.md) | Answered |
|
||||
| Where does a user look up a setting or a file that changes OpenSpec's behavior? | [Reference › Configuration](reference/configuration/index.md) | Answered |
|
||||
| Which openspec/ tree does a command operate on? | [Reference › Configuration › Stores](reference/configuration/stores.md) owns the whole resolution ladder, including the everyday case (nearest openspec/ wins); readers reach it from the Stores row of the [Configuration overview](reference/configuration/index.md) map | Skeleton |
|
||||
| How should a user run a change with no spec impact, or retire a capability outright? | [Reference › Configuration › Change metadata](reference/configuration/change-metadata.md) owns the `skip_specs` and `retire_capabilities` contracts; [Reference › Schemas › spec-driven](reference/schemas/spec-driven/index.md), Delta specs section, owns their effect on deltas and archive; neither half has a guide owner | Gap |
|
||||
| What is an initiative, and how does a change join one? | No owner: the `initiative` field's contract sits on [Reference › Configuration › Change metadata](reference/configuration/change-metadata.md), but no page teaches initiatives (multi-repo has only Stores) | Gap |
|
||||
| What is a workset, and how does a user open one in their editor? | [Multi-repo › Worksets](multi-repo/worksets.md); the `openers` field's contract stays on [Reference › Configuration › CLI settings](reference/configuration/config-json.md) | Answered |
|
||||
| Which AI tools work, and what's each one's syntax? | [Reference › Supported tools](reference/supported-tools.md) | Answered |
|
||||
| My tool isn't listed, can I still use OpenSpec? | [Help › FAQ](help/faq.md) routes: the shared `.agents` target or an issue; [Reference › Supported tools](reference/supported-tools.md), Per-tool notes, holds the shared target's contract | Answered |
|
||||
| Where does a user look up a term? | [Reference › Glossary](reference/glossary.md) | Answered |
|
||||
| How is OPSX built? | [Reference › Architecture](reference/architecture/index.md) | Skeleton |
|
||||
| How do we explain that the workflow is fluid, actions not phases? | [Start › Overview](start/overview.md) will carry the pitch once rewritten (the "shared map, not a plan up front" framing was in the cleared skeleton); [sources.md](sources.md) routes opsx.md's explanation to [Guides › Understanding › Concepts](guides/concepts.md), but that page narrowed to artifacts only in review round 3; likely home is Guides › Understanding, widening [Concepts](guides/concepts.md) or adding a sibling page, with [Reference › Architecture › Design decisions](reference/architecture/design-decisions.md) keeping the why | Gap |
|
||||
| What should a user do when OpenSpec doesn't do what they expected? | [Help › Troubleshooting](help/troubleshooting.md), then [Help › FAQ](help/faq.md) | Skeleton |
|
||||
| Where does a user go for help or to report a bug? | [Help › Troubleshooting](help/troubleshooting.md), Getting help | Skeleton |
|
||||
| How should a user move off the legacy `/openspec:*` commands? | [Help › Migration](help/legacy/migration.md) | Skeleton |
|
||||
| How does a script or CI drive the CLI programmatically? | Off-site by decision: repo-side contributor docs, per [sources.md](sources.md) | Off-site |
|
||||
@@ -1,341 +0,0 @@
|
||||
# Stores (beta)
|
||||
|
||||
> Plan changes that span repositories: one store, many repos.
|
||||
|
||||
OpenSpec normally lives inside one repo: an `openspec/` folder next to the code it plans. A store moves that folder into a repository of its own, and several code repos can share it.
|
||||
|
||||
After a one-time setup on each machine, commands like `status`, `new change`, and `archive` can work in the store from any directory.
|
||||
|
||||
```
|
||||
team-plans (a store: OpenSpec in its own repo)
|
||||
├── .openspec-store/store.yaml the store's name
|
||||
└── openspec/
|
||||
├── specs/
|
||||
└── changes/
|
||||
▲
|
||||
│ set up once on each machine,
|
||||
│ shared by pushing and cloning like any repo
|
||||
┌─────────────┼─────────────┐
|
||||
│ │ │
|
||||
web-app api-server mobile-app
|
||||
(code repo) (code repo) (code repo)
|
||||
```
|
||||
|
||||
You share a store with git, the same way you share code: commit, push, pull, and review it yourself. Specs and changes get branches and pull requests the same way code does.
|
||||
|
||||
## When you need one
|
||||
|
||||
Two common reasons to use a store:
|
||||
|
||||
- **Frontend and backend in separate repos**: one feature touches both, and the plan needs a single home instead of two halves.
|
||||
|
||||
```
|
||||
shop-plans (store)
|
||||
└── openspec/changes/add-discounts/ one plan for the feature
|
||||
▲
|
||||
┌─────────┴─────────┐
|
||||
│ │
|
||||
storefront api
|
||||
(frontend repo) (backend repo)
|
||||
```
|
||||
|
||||
- **One product, several client repos**: Android, iOS, and web ship from their own repos but share one expected behavior. A spec describes behavior, not implementation, so one spec serves all three.
|
||||
|
||||
```
|
||||
product-specs (store)
|
||||
└── openspec/specs/checkout/spec.md the expected behavior
|
||||
▲
|
||||
┌─────────────┼─────────────┐
|
||||
│ │ │
|
||||
android-app ios-app web-app
|
||||
(code repo) (code repo) (code repo)
|
||||
```
|
||||
|
||||
You can have more than one store, though we recommend keeping the count low.
|
||||
|
||||
## Set up a store
|
||||
|
||||
One person creates the store, then everyone else joins it.
|
||||
|
||||
1. **Create the store** (one person, once per team). Run `openspec store setup` and answer the prompts:
|
||||
|
||||
```bash
|
||||
# run from anywhere; it asks what to create and where
|
||||
openspec store setup
|
||||
```
|
||||
|
||||
It asks three questions:
|
||||
|
||||
- **Store name**: `team-plans`
|
||||
- **Where should this store live?**: pre-filled with `~/openspec/<name>`, press Enter to accept it or type another path
|
||||
- **Create this store?**: shows what it's about to make, answer `Yes`
|
||||
|
||||
Then it reports what it created:
|
||||
|
||||
```yaml
|
||||
Store ready: team-plans
|
||||
Location: ~/openspec/team-plans
|
||||
OpenSpec root: ready
|
||||
Registry: registered
|
||||
|
||||
Next: run normal OpenSpec commands against this store, for example:
|
||||
openspec new change <change-id> --store team-plans
|
||||
Share this store by committing and pushing it like any Git repo.
|
||||
```
|
||||
|
||||
2. **Push it to your git host.** Create an empty `team-plans` repo on your host first. Setup doesn't add a git remote, so connect the store to that repo, then push:
|
||||
|
||||
```bash
|
||||
# connect the store to the empty repo on your git host
|
||||
cd ~/openspec/team-plans
|
||||
git remote add origin git@github.com:acme/team-plans.git
|
||||
|
||||
# publish it
|
||||
git push -u origin main
|
||||
```
|
||||
|
||||
3. **Join the store** (every teammate, once per machine):
|
||||
|
||||
```bash
|
||||
# get the store onto your machine
|
||||
git clone git@github.com:acme/team-plans.git ~/openspec/team-plans
|
||||
|
||||
# tell OpenSpec where it lives
|
||||
openspec store register ~/openspec/team-plans
|
||||
```
|
||||
|
||||
```yaml
|
||||
Store registered: team-plans
|
||||
Location: /Users/you/openspec/team-plans
|
||||
OpenSpec root: ready
|
||||
Registry: registered
|
||||
```
|
||||
|
||||
Registering tells your machine where this store lives. The store's name is already committed inside it, in `.openspec-store/store.yaml`. Setup registered the creator's copy, so only cloned copies need this step.
|
||||
|
||||
4. **Confirm it worked**, from any directory:
|
||||
|
||||
```bash
|
||||
# any OpenSpec command reaches the store by name
|
||||
openspec status --store team-plans
|
||||
```
|
||||
|
||||
```yaml
|
||||
Using OpenSpec root: team-plans (/Users/you/openspec/team-plans)
|
||||
No active changes. Create one with: openspec new change <name> --store team-plans
|
||||
```
|
||||
|
||||
## Types of setups
|
||||
|
||||
OpenSpec has three setups. The rest of this page uses these names:
|
||||
|
||||
- **repo-local**: OpenSpec inside your repo, no store. The default.
|
||||
- **store-only**: your repo keeps no specs or changes of its own. Everything lives in the store.
|
||||
- **store-optional**: your project has its own `openspec/` folder and also reaches a store when you ask.
|
||||
|
||||
### The default: OpenSpec inside your repo (`repo-local`)
|
||||
|
||||
`openspec init` puts an `openspec/` folder next to your code, and that repo's specs and changes live there. No store is involved. This is the setup [Set up your project](../start/setup.md) teaches, and most projects never need another.
|
||||
|
||||
```
|
||||
web-app (code repo)
|
||||
└── openspec/
|
||||
├── specs/
|
||||
└── changes/
|
||||
```
|
||||
|
||||
### OpenSpec outside your repo, in a store (`store-only`)
|
||||
|
||||
The repo keeps no specs or changes of its own. Everything it plans lives in the store, and one line in the repo's config connects the two.
|
||||
|
||||
Common when one team builds all the repos and plans in one place. The [examples above](#when-you-need-one) all have this shape.
|
||||
|
||||
```
|
||||
team-plans (store)
|
||||
└── openspec/
|
||||
├── specs/ the repo's specs live here
|
||||
└── changes/ its changes too
|
||||
▲
|
||||
│ store: team-plans (the connecting line)
|
||||
web-app (code repo)
|
||||
└── openspec/
|
||||
└── config.yaml nothing else
|
||||
```
|
||||
|
||||
### OpenSpec in your repo and in a store (`store-optional`)
|
||||
|
||||
The repo stays repo-local for its own work, while the store holds the shared specs and changes. Inside the repo, OpenSpec uses your project's `openspec/` folder, and reaches the store only when you pass `--store`.
|
||||
|
||||
Common when a repo used OpenSpec before the store existed, or when a mostly independent repo only occasionally touches shared work.
|
||||
|
||||
```
|
||||
team-plans (store)
|
||||
└── openspec/ the shared specs and changes
|
||||
▲
|
||||
│ only when you pass --store team-plans
|
||||
web-app (code repo)
|
||||
└── openspec/ this repo's own
|
||||
├── config.yaml
|
||||
├── specs/
|
||||
└── changes/
|
||||
```
|
||||
|
||||
A repo can start repo-local and move its specs and changes into the store later. [Move a repo's specs and changes into the store](#move-a-repos-specs-and-changes-into-the-store) shows how.
|
||||
|
||||
## Where artifacts get created when using stores
|
||||
|
||||
When you use a store, OpenSpec also has to decide where the artifacts get created. It depends on your setup:
|
||||
|
||||
- **store-only** (your project only writes to the store): every artifact is created in the store. The `store:` line below records that.
|
||||
- **store-optional** (your project has its own `openspec/` folder and also uses a store): artifacts are created in your project, unless you name the store in your request or pass `--store` for that change. Your agent then carries the flag through the rest of the workflow.
|
||||
|
||||
OpenSpec writes artifacts to one of two places: your project's `openspec/` folder, or the store's. It picks in this order, and the first option that applies wins:
|
||||
|
||||
1. **`--store <id>` on a command.** Always wins, from any directory.
|
||||
2. **Your project's `openspec/` folder.** If your project has its own `specs/` or `changes/` folders, OpenSpec uses them.
|
||||
3. **The `store:` line in your project.** How a store-only project records its store.
|
||||
4. **`defaultStore` on your machine.** The fallback when none of the above applies.
|
||||
|
||||
When OpenSpec selects a store, it prints `Using OpenSpec root: ...` before the command output.
|
||||
|
||||
### The `store:` line (store-only projects)
|
||||
|
||||
Add one line to your project's `openspec/config.yaml`:
|
||||
|
||||
```yaml
|
||||
# web-app/openspec/config.yaml
|
||||
store: team-plans
|
||||
```
|
||||
|
||||
Everything you or your agent run inside your project now uses the store, with no flag to type:
|
||||
|
||||
```bash
|
||||
# inside web-app, connected
|
||||
openspec status
|
||||
```
|
||||
|
||||
```yaml
|
||||
Using OpenSpec root: team-plans (/Users/you/openspec/team-plans)
|
||||
No active changes. Create one with: openspec new change <name> --store team-plans
|
||||
```
|
||||
|
||||
- **Without the line**: run a plain command in a store-only project and OpenSpec stops with an error listing your registered stores.
|
||||
- **Commit it**: teammates who clone your project get the line too. They still need the store registered on their machine ([step 3 of Set up a store](#set-up-a-store)), or OpenSpec errors and tells them to register it.
|
||||
- **Next to real folders**: if your project also has `specs/` or `changes/` folders, OpenSpec uses those and ignores the line, with a warning.
|
||||
|
||||
### `defaultStore` on your machine
|
||||
|
||||
Set it once if every project you work in uses the same store. OpenSpec falls back to it when it finds no flag, no local `openspec/` folder, and no `store:` line:
|
||||
|
||||
```bash
|
||||
# use team-plans whenever nothing else names a store
|
||||
openspec config set defaultStore team-plans
|
||||
|
||||
# undo it
|
||||
openspec config unset defaultStore
|
||||
```
|
||||
|
||||
**Commands that stay local.** `init`, `update`, `templates`, `schemas`, and the `openspec schema` subcommands act on the current directory only and take no `--store`.
|
||||
|
||||
## Move a repo's specs and changes into the store
|
||||
|
||||
To take a repo from repo-local to store-only:
|
||||
|
||||
1. Move everything in the repo's `openspec/specs/` and `openspec/changes/` into the same folders in the store.
|
||||
2. Delete the now-empty folders, so the repo's `openspec/` folder holds only `config.yaml`.
|
||||
3. Add the `store:` line to that `config.yaml`.
|
||||
|
||||
`openspec status` inside the repo now starts with `Using OpenSpec root: team-plans`.
|
||||
|
||||
## Work in the store
|
||||
|
||||
The workflows don't change, for you or for your agent. Propose, apply, and archive run the way they always do. The only difference is where the artifacts get created, and [the section above](#where-artifacts-get-created-when-using-stores) covers that.
|
||||
|
||||
Create a change from inside a store-only repo and it lands in the store:
|
||||
|
||||
```bash
|
||||
# inside web-app; the store: line routes this to team-plans
|
||||
openspec new change add-login
|
||||
```
|
||||
|
||||
```yaml
|
||||
Using OpenSpec root: team-plans (/Users/you/openspec/team-plans)
|
||||
Created change 'add-login' at /Users/you/openspec/team-plans/openspec/changes/add-login/
|
||||
Schema: spec-driven
|
||||
Next: openspec status --change add-login --store team-plans
|
||||
```
|
||||
|
||||
- **Where it went**: into the store repo, not next to your code.
|
||||
- **Sharing it**: the change exists only in your checkout until you commit and push the store repo. Teammates see it when they pull. The same goes for every artifact the workflows write.
|
||||
- **Paths in the docs**: wherever the docs show an `openspec/` path, in a store setup that folder is the store's.
|
||||
|
||||
When artifacts get created somewhere you didn't expect, `openspec doctor` checks your setup without changing anything and prints a fix for each finding:
|
||||
|
||||
```bash
|
||||
# check the current root and its stores
|
||||
openspec doctor
|
||||
```
|
||||
|
||||
```yaml
|
||||
Doctor
|
||||
|
||||
Root
|
||||
Location: /Users/you/openspec/team-plans
|
||||
OpenSpec root: ok
|
||||
Store: team-plans (metadata ok)
|
||||
|
||||
References
|
||||
(none declared)
|
||||
```
|
||||
|
||||
`openspec context` lists the root and stores your current directory works with, when you want the same picture without the checks.
|
||||
|
||||
To open the store and a repo in one editor window, so your agent can read both, see [Worksets (beta)](worksets.md).
|
||||
|
||||
## Read specs from another store
|
||||
|
||||
Your repo can keep its own `openspec/` folder and still let your agent read another store's specs. Declare that store under `references:` in the repo's `openspec/config.yaml`:
|
||||
|
||||
```yaml
|
||||
# api-server/openspec/config.yaml
|
||||
references:
|
||||
- team-plans
|
||||
```
|
||||
|
||||
References are read-only. Your work stays in your repo, and the reference only changes what your agent is told.
|
||||
|
||||
When a workflow creates an artifact, its instructions gain an index of the referenced store's specs, each with a one-line summary and the exact command to fetch it:
|
||||
|
||||
```xml
|
||||
<referenced_stores>
|
||||
<!-- Read-only upstream context. Fetch what you need; cite what you use. -->
|
||||
Store team-plans (/Users/you/openspec/team-plans):
|
||||
- payments: Rules for charging and refunding customers.
|
||||
Fetch: openspec show <spec-id> --type spec --store team-plans
|
||||
</referenced_stores>
|
||||
```
|
||||
|
||||
A reference can also carry the store's clone URL, for machines that don't have that store yet:
|
||||
|
||||
```yaml
|
||||
references:
|
||||
- team-plans
|
||||
- { id: design-system, remote: "git@github.com:acme/design-system.git" }
|
||||
```
|
||||
|
||||
With the URL declared, `openspec doctor` turns a missing store into a pasteable fix:
|
||||
|
||||
```yaml
|
||||
# output wrapped to fit
|
||||
References
|
||||
- team-plans: ok (/Users/you/openspec/team-plans)
|
||||
- design-system: Referenced store 'design-system' is not registered on this machine.
|
||||
Fix: git clone -- git@github.com:acme/design-system.git '/Users/you/openspec/design-system' &&
|
||||
openspec store register '/Users/you/openspec/design-system' --id design-system
|
||||
```
|
||||
|
||||
## Beta limits
|
||||
|
||||
- **The shape may change**: command names, flags, and file formats can change between releases. Re-read this page after upgrading.
|
||||
- **No sync, by design**: OpenSpec never clones, pulls, or pushes. A stale checkout shows stale specs until you pull, and references are read from whatever is on disk.
|
||||
- **One checkout per store name**: registering a second folder under a name that's already registered fails, with a hint to run `openspec store unregister` first.
|
||||
@@ -1,62 +0,0 @@
|
||||
# Worksets (beta)
|
||||
|
||||
> Open the store and the repos that use it in one editor window, so your agent sees both.
|
||||
|
||||
With a store, the context your agent needs is split across folders. The specs and changes live in the store, and the code lives in each repo. An agent started in one repo can read and grep that repo and nothing else, so it works from half the picture.
|
||||
|
||||
Worksets are the utility OpenSpec provides for this. A workset is a saved, named list of folders you open together. This page assumes the store is already set up and registered on your machine. [Stores (beta)](stores.md) covers that.
|
||||
|
||||
## How it works
|
||||
|
||||
- **What it is**: a named list of folders, saved on your machine only. Nothing is written into the member folders, and nothing is committed.
|
||||
- **What opening does**: OpenSpec generates a `.code-workspace` file from the list and launches your editor on it. Every member folder sits in one window.
|
||||
- **What you get**: your editor's search, and any agent you run inside that window, can read every member folder. The agent can grep the store's specs and the repo's code in one session.
|
||||
- **What it doesn't change**: which `openspec/` folder a command uses. That still follows [Where artifacts get created](stores.md#where-artifacts-get-created-when-using-stores).
|
||||
|
||||
## Set it up
|
||||
|
||||
1. **Save the workset** (once per machine). List the repo and the store as members, and the tool to open them with:
|
||||
|
||||
```bash
|
||||
# save a named list of folders you open together
|
||||
openspec workset create platform \
|
||||
--member ~/src/web-app \
|
||||
--member ~/openspec/team-plans \
|
||||
--tool code
|
||||
```
|
||||
|
||||
```yaml
|
||||
Saved workset 'platform' (2 members) to your machine.
|
||||
Open it any time with: openspec workset open platform
|
||||
```
|
||||
|
||||
2. **Open it** whenever you start work:
|
||||
|
||||
```bash
|
||||
# open every member in one VS Code window
|
||||
openspec workset open platform
|
||||
```
|
||||
|
||||
`openspec workset list` shows what you saved, and `openspec workset remove <name>` deletes a workset without touching the member folders:
|
||||
|
||||
```yaml
|
||||
platform (opens in VS Code)
|
||||
web-app /Users/you/src/web-app
|
||||
team-plans /Users/you/openspec/team-plans
|
||||
```
|
||||
|
||||
## Use it: one change, two folders
|
||||
|
||||
Say the `add-login` change lives in the `team-plans` store, and the code for it lives in `web-app`. Open the `platform` workset and ask your agent to implement the change. In that one session it can:
|
||||
|
||||
- read `team-plans/openspec/changes/add-login/` and the specs next to it
|
||||
- edit the code in `web-app/`
|
||||
- run `openspec` commands from inside `web-app`
|
||||
|
||||
Without the workset, the agent only sees whichever folder it was started in.
|
||||
|
||||
## Tools out of the box
|
||||
|
||||
- **VS Code** (`--tool code`) and **Cursor** (`--tool cursor`): built in. Each opens one window with every member folder.
|
||||
- **Claude Code and Codex in the terminal**: temporarily disabled as workset openers while that flow is reworked. `--tool claude` or `--tool codex` stops with an error that says so and points you to VS Code or Cursor.
|
||||
- **Other editors**: add them under the `openers` key in [CLI settings (config.json)](../reference/configuration/config-json.md).
|
||||
@@ -1,11 +0,0 @@
|
||||
# Design decisions
|
||||
|
||||
> Why OPSX works the way it does.
|
||||
|
||||
<!-- WIP, on the todo list: this page is not written yet and is held back from the
|
||||
site (its entry is commented out in website/docs.sync.config.mjs, 2026-08-21). The file
|
||||
stays so the structure and inbound links survive; re-list it in the sync config once the
|
||||
prose lands. -->
|
||||
|
||||
<!-- Skeleton: heading only. Split from reference/architecture.md on 2026-08-10.
|
||||
message-map.md routes "the workflow is fluid, actions not phases" here. -->
|
||||
@@ -1,19 +0,0 @@
|
||||
# Overview
|
||||
|
||||
> How OPSX is built: internals for the curious.
|
||||
|
||||
<!-- WIP, on the todo list: this page is not written yet and is held back from the
|
||||
site (its entry is commented out in website/docs.sync.config.mjs, 2026-08-21). The file
|
||||
stays so the structure and inbound links survive; re-list it in the sync config once the
|
||||
prose lands. -->
|
||||
|
||||
<!-- Skeleton: headings only. Moved out of Legacy in review round 2 (it documents
|
||||
the current system); split from a single architecture.md page into this folder
|
||||
on 2026-08-10. -->
|
||||
|
||||
The pages in this section:
|
||||
|
||||
- [Workflow runs](workflow-runs.md): how a workflow run executes, from invocation to written artifacts.
|
||||
- [Design decisions](design-decisions.md): why OPSX works the way it does.
|
||||
|
||||
## How the pieces fit
|
||||
@@ -1,10 +0,0 @@
|
||||
# Workflow runs
|
||||
|
||||
> How a workflow run executes, from invocation to written artifacts.
|
||||
|
||||
<!-- WIP, on the todo list: this page is not written yet and is held back from the
|
||||
site (its entry is commented out in website/docs.sync.config.mjs, 2026-08-21). The file
|
||||
stays so the structure and inbound links survive; re-list it in the sync config once the
|
||||
prose lands. -->
|
||||
|
||||
<!-- Skeleton: heading only. Split from reference/architecture.md on 2026-08-10. -->
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,62 +0,0 @@
|
||||
# Change metadata (.openspec.yaml)
|
||||
|
||||
> The supported fields and validation rules for the metadata stored with each change.
|
||||
|
||||
## Location
|
||||
|
||||
Each change keeps its metadata at `openspec/changes/<change-name>/.openspec.yaml`, next to its artifacts. Creating a change writes the file with `schema` and `created` filled in.
|
||||
|
||||
## Fields
|
||||
|
||||
| Key | Type | Required | Effect |
|
||||
| --- | --- | --- | --- |
|
||||
| `schema` | string | Yes | The workflow schema this change follows |
|
||||
| `created` | string, YYYY-MM-DD | No | Records the date the change was created |
|
||||
| `goal` | string | No | Records what the change sets out to do |
|
||||
| `affected_areas` | list of strings | No | Records the areas the change expects to touch |
|
||||
| `initiative` | map: `store` and `id` | No | Records the initiative this change belongs to |
|
||||
| `skip_specs` | boolean | No | Declares the change makes no spec deltas, so zero deltas validate |
|
||||
| `retire_capabilities` | boolean | No | Authorizes archive to delete a capability this change empties |
|
||||
|
||||
### schema
|
||||
|
||||
The workflow schema this change follows. It is set when the change is created and wins over the project config, so a change keeps its schema even if `openspec/config.yaml` changes afterwards. Run [`openspec schemas`](../cli.md#openspec-schemas) to list the available schema names.
|
||||
|
||||
### initiative
|
||||
|
||||
The initiative this change belongs to, as a store id and an initiative id, both kebab-case:
|
||||
|
||||
```yaml
|
||||
initiative:
|
||||
store: platform-specs
|
||||
id: unify-billing
|
||||
```
|
||||
|
||||
Keys other than `store` and `id` are rejected. No command reads the link today.
|
||||
|
||||
### skip_specs
|
||||
|
||||
Declares the change intentionally makes no spec deltas: a pure refactor, tooling, or docs change. With it set, validation accepts zero deltas, and artifacts that would generate spec files count as complete. Setting it while spec files exist under specs/ is a validation error.
|
||||
|
||||
### retire_capabilities
|
||||
|
||||
Authorizes archive to retire a capability. When this change's REMOVED deltas take away the last requirement a capability has, archive deletes that capability's main spec instead of stopping. The flag exists because the deletion is only recoverable from git, so it stays the author's call.
|
||||
|
||||
## Example
|
||||
|
||||
A filled-in .openspec.yaml:
|
||||
|
||||
```yaml
|
||||
schema: spec-driven
|
||||
created: 2026-08-14
|
||||
goal: Add magic-link login to the API
|
||||
affected_areas:
|
||||
- auth
|
||||
- api
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
The file is validated whenever a command writes or reads it. A write that fails validation throws and writes nothing. Reading an existing file fails on invalid YAML, a field that breaks its contract, or a schema name that is not available. A missing file is not an error, and the change is treated as having no metadata.
|
||||
|
||||
Unlike [config.yaml](config-yaml.md), bad values are never dropped with a warning. A metadata error stops the command. The one exception is unknown top-level keys, which are ignored rather than rejected.
|
||||
@@ -1,97 +0,0 @@
|
||||
# CLI settings (config.json)
|
||||
|
||||
> Every field of config.json: how the openspec CLI behaves on your machine.
|
||||
|
||||
## Location
|
||||
|
||||
The CLI keeps its machine-level settings at `~/.config/openspec/config.json` on macOS and Linux, and `%APPDATA%\openspec\config.json` on Windows. `$XDG_CONFIG_HOME` wins on every platform when set. The `openspec config` command reads and edits it.
|
||||
|
||||
## Fields
|
||||
|
||||
| Key | Type | Required | Effect |
|
||||
| --- | --- | --- | --- |
|
||||
| `profile` | string: `core` or `custom` | No | Picks the workflow set `openspec init` installs |
|
||||
| `delivery` | string: `both`, `skills`, or `commands` | No | Whether init installs skills, slash commands, or both |
|
||||
| `workflows` | list of strings | No | The workflow list a `custom` profile installs |
|
||||
| `featureFlags` | map: flag → boolean | No | Boolean feature toggles |
|
||||
| `defaultStore` | string | No | Machine-level fallback store for root resolution |
|
||||
| `openers` | map: tool id → settings | No | The tools worksets open in, and how each is launched |
|
||||
| `telemetry` | map | No | Telemetry opt-out, anonymous id, and notice-seen state |
|
||||
|
||||
### profile
|
||||
|
||||
Which workflow set `openspec init` installs. Defaults to `core`: propose, explore, apply, update, sync, and archive. Setting `custom` installs exactly the `workflows` list instead.
|
||||
|
||||
### delivery
|
||||
|
||||
Whether init installs workflows as skills, as slash commands, or both. Defaults to `both`.
|
||||
|
||||
### workflows
|
||||
|
||||
The workflows a `custom` profile installs; ignored when the profile is `core`. Valid ids: `propose`, `explore`, `new`, `continue`, `apply`, `update`, `ff`, `sync`, `archive`, `bulk-archive`, `verify`, `onboard`.
|
||||
|
||||
### featureFlags
|
||||
|
||||
Boolean toggles keyed by flag name, set with `openspec config set featureFlags.<flag> true`. No flag is read by the CLI today.
|
||||
|
||||
### defaultStore
|
||||
|
||||
The machine-level fallback store id for root resolution, consulted only when no `--store` flag, local `openspec/`, or project `store:` pointer resolves. The full ladder is [Root resolution](../../multi-repo/stores.md#where-artifacts-get-created-when-using-stores).
|
||||
|
||||
### openers
|
||||
|
||||
The tools a workset can open in, keyed by tool id. Edit `openers` in the global `config.json` with `openspec config edit` in your terminal.
|
||||
|
||||
| Field | Contract |
|
||||
| --- | --- |
|
||||
| `style` | `workspace-file` or `attach-dirs`. Required for a new tool; optional for a built-in. |
|
||||
| `label` | Non-empty string shown in the tool picker. Defaults to the id for a new tool. |
|
||||
| `command` | Non-empty executable name or path. Defaults to the id for a new tool. Put arguments in `args`, not in this string. |
|
||||
| `args` | Array of strings passed before the workspace file or attach flags. Defaults to `[]` for a new tool. |
|
||||
| `attach_flag` | Non-empty string paired with each member path for `attach-dirs`. Defaults to `--add-dir` for a new tool. Ignored for `workspace-file`. |
|
||||
|
||||
**Built-in overrides:** `code`, `cursor`, `claude`, and `codex` retain any fields you omit. Setting `args` replaces the entire argument list; `[]` clears it.
|
||||
|
||||
**Launch styles:** `workspace-file` passes the generated `.code-workspace` path to the executable. `attach-dirs` passes one flag/path pair per member, including the primary member.
|
||||
|
||||
**Availability:** `attach-dirs` openers, including Claude Code and Codex, are disabled by default. You cannot select or save them with `--tool`, and OpenSpec refuses to open a workset that already names one. Configuration overrides do not enable the `attach-dirs` launch style.
|
||||
|
||||
**Validation:** unknown fields, invalid types, and a new tool without `style` fail when a workset command reads the opener table.
|
||||
|
||||
This example adds VS Code Insiders and passes `--new-window` whenever the built-in VS Code opener launches:
|
||||
|
||||
```json
|
||||
{
|
||||
"openers": {
|
||||
"code-insiders": {
|
||||
"style": "workspace-file",
|
||||
"label": "VS Code Insiders"
|
||||
},
|
||||
"code": {
|
||||
"args": ["--new-window"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The corresponding `code-insiders` or `code` executable must be installed and available on `PATH`.
|
||||
|
||||
### telemetry
|
||||
|
||||
The CLI stores your anonymous id and whether the first-run notice was shown. Set `telemetry.enabled` to `false` to disable telemetry. You can also opt out with `OPENSPEC_TELEMETRY=0` or `DO_NOT_TRACK=1` in your environment.
|
||||
|
||||
## Example
|
||||
|
||||
A filled-in config.json:
|
||||
|
||||
```json
|
||||
{
|
||||
"profile": "core",
|
||||
"delivery": "both",
|
||||
"featureFlags": {},
|
||||
"telemetry": {
|
||||
"anonymousId": "5f8a2c1e-4b6d-4f9a-9c3d-7e1b2a8d4c6f",
|
||||
"noticeSeen": true
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,102 +0,0 @@
|
||||
# Project configuration (config.yaml)
|
||||
|
||||
> Every field of openspec/config.yaml: the schema, context, and rules this project plans with.
|
||||
|
||||
## Location
|
||||
|
||||
Each OpenSpec project keeps its config file at `openspec/config.yaml`, in the project root.
|
||||
|
||||
## Fields
|
||||
|
||||
| Key | Type | Required | Effect |
|
||||
| --- | --- | --- | --- |
|
||||
| `schema` | string | Yes | The workflow schema this project's changes follow |
|
||||
| `context` | string | No | Injected into every artifact's instructions |
|
||||
| `rules` | map: artifact ID → list of strings | No | Extra rules added to one artifact's built-in guidance |
|
||||
| `operations` | map: operation → guidance list | No | Advisory guidance for apply and archive work |
|
||||
| `store` | string | No | Fallback OpenSpec root when this openspec/ is config-only |
|
||||
| `references` | list | No | Stores whose specs are indexed into instructions |
|
||||
|
||||
Invalid fields never fail a command. Each field is validated on its own, and a bad value is dropped with a warning.
|
||||
|
||||
What to write in these fields is covered in [Project configuration](../../customize/project-config.md).
|
||||
|
||||
### schema
|
||||
|
||||
The workflow schema every change in this project follows. Valid values are `spec-driven` or a schema name the project defines. Run [`openspec schemas`](../cli.md#openspec-schemas) to list the available schema names.
|
||||
|
||||
### context
|
||||
|
||||
Free text injected into every artifact's instructions. The limit is 50KB, and a larger value is ignored with a warning.
|
||||
|
||||
### rules
|
||||
|
||||
Extra rules for one artifact, added to the schema's built-in guidance:
|
||||
|
||||
```yaml
|
||||
rules:
|
||||
proposal:
|
||||
- Keep proposals under 500 words
|
||||
```
|
||||
|
||||
Artifact IDs are not restricted to the built-in names, so artifacts from custom schemas work as keys.
|
||||
|
||||
### operations
|
||||
|
||||
Advisory guidance for how apply and archive work is conducted, separate from artifact rules:
|
||||
|
||||
```yaml
|
||||
operations:
|
||||
apply:
|
||||
guidance:
|
||||
- Keep test summaries concise
|
||||
```
|
||||
|
||||
Only `apply` and `archive` are read.
|
||||
|
||||
### store
|
||||
|
||||
A store id used as the OpenSpec root, consulted only when this openspec/ directory is config-only (no specs/ or changes/). It is a fallback, never an override. The full ladder is [Root resolution](../../multi-repo/stores.md#where-artifacts-get-created-when-using-stores).
|
||||
|
||||
### references
|
||||
|
||||
Store ids whose specs this project's work draws on. An index of each store's specs (id, summary, fetch command) is added to instructions output. Spec content is never inlined, and root resolution is never affected. An entry is a store id or a map with `id` and an optional `remote` clone source:
|
||||
|
||||
```yaml
|
||||
references:
|
||||
- platform-specs
|
||||
- id: billing-specs
|
||||
remote: git@github.com:acme/billing-specs.git
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
A filled-in config.yaml:
|
||||
|
||||
```yaml
|
||||
schema: spec-driven
|
||||
|
||||
context: |
|
||||
Tech stack: TypeScript, React, Node.js
|
||||
We use conventional commits
|
||||
Domain: e-commerce platform
|
||||
|
||||
rules:
|
||||
proposal:
|
||||
- Keep proposals under 500 words
|
||||
- Always include a "Non-goals" section
|
||||
tasks:
|
||||
- Break tasks into chunks of max 2 hours
|
||||
|
||||
operations:
|
||||
apply:
|
||||
guidance:
|
||||
- Keep test summaries concise
|
||||
archive:
|
||||
guidance:
|
||||
- Summarize the archive outcome before finishing
|
||||
```
|
||||
|
||||
## Legacy names
|
||||
|
||||
`openspec/config.yml` is read as an alias when `config.yaml` does not exist. When both files exist, `config.yaml` wins and `config.yml` is ignored. `openspec init` creates `config.yaml`.
|
||||
@@ -1,14 +0,0 @@
|
||||
# Environment variables
|
||||
|
||||
> Every environment variable OpenSpec reads.
|
||||
|
||||
<!-- Skeleton: headings only. This page is the telemetry opt-out's home
|
||||
(README TODO): OPENSPEC_TELEMETRY=0, DO_NOT_TRACK=1, auto-disabled in CI, plus
|
||||
what's collected. start/installation.md's Deno section links here to explain
|
||||
its network-permission flag. XDG vars move the config/data directories. -->
|
||||
|
||||
## OPENSPEC_TELEMETRY
|
||||
|
||||
## DO_NOT_TRACK
|
||||
|
||||
## XDG_CONFIG_HOME and XDG_DATA_HOME
|
||||
@@ -1,11 +0,0 @@
|
||||
# Overview
|
||||
|
||||
> Every file and setting that changes how OpenSpec behaves, and where each lives.
|
||||
|
||||
| File | Lives at | Controls |
|
||||
| --- | --- | --- |
|
||||
| [Project configuration (config.yaml)](config-yaml.md) | `openspec/config.yaml` | The schema, context, and rules this project plans with |
|
||||
| [Change metadata (.openspec.yaml)](change-metadata.md) | `openspec/changes/<name>/.openspec.yaml` | The workflow schema, goal, scope, and spec exceptions for one change |
|
||||
| [CLI settings (config.json)](config-json.md) | `~/.config/openspec/config.json` (Windows varies) | How the openspec CLI behaves on your machine |
|
||||
| Environment variables | Your shell or CI environment | Telemetry opt-out, and where the config and data directories live |
|
||||
| Stores | `~/.local/share/openspec/stores/` (Windows varies) | The registry and metadata behind multi-repo stores |
|
||||
@@ -1,22 +0,0 @@
|
||||
# Stores
|
||||
|
||||
> The files behind multi-repo stores: registry.yaml and store.yaml, and which root a command uses.
|
||||
|
||||
<!-- Skeleton: headings only. Beta, like the multi-repo group. Machine-maintained
|
||||
rather than hand-edited; documented so readers can inspect and repair them. The
|
||||
concept and workflow live in multi-repo/stores.md. Root resolution is the
|
||||
contract from src/core/root-selection.ts: --store flag, else nearest ancestor
|
||||
openspec/, else a config-only openspec/'s store: pointer, else the global
|
||||
defaultStore, else error. This page owns the whole ladder including the
|
||||
everyday case (nearest openspec/ wins); the section's Overview only links
|
||||
here. Locations (store/foundation.ts): registry.yaml at <dataDir>/stores/
|
||||
(~/.local/share/openspec/stores/); store.yaml at .openspec-store/store.yaml
|
||||
inside each checkout. The glossary's "OpenSpec root" row links here. -->
|
||||
|
||||
## registry.yaml
|
||||
|
||||
## store.yaml
|
||||
|
||||
## Locations
|
||||
|
||||
## Root resolution
|
||||
@@ -1,40 +0,0 @@
|
||||
# Glossary
|
||||
|
||||
> Every OpenSpec term, one line each.
|
||||
|
||||
OpenSpec reuses words that mean something else in git, CI, and agent tooling. Each row gives the OpenSpec meaning. The last column links to more detail where available.
|
||||
|
||||
| Term | Definition | More |
|
||||
|---|---|---|
|
||||
| **Apply** | Implement the tasks in a change proposal. Skill: `openspec-apply-change`. | [Apply a change](skills.md#openspec-apply-change) |
|
||||
| **Archive** | Complete a change proposal: merge its deltas into the main specs and move its folder to `openspec/changes/archive/`. | [Quickstart](../start/quickstart.md) |
|
||||
| **Artifact** | A planning document inside a change proposal: `proposal.md`, delta specs, `design.md`, `tasks.md`. Not a build output. | [Artifacts](schemas/spec-driven/index.md#artifacts) |
|
||||
| **Capability** | One behavior area of your system. Each has one spec at `openspec/specs/<capability>/spec.md`. | [Capabilities](schemas/spec-driven/index.md#proposalmd) |
|
||||
| **Change proposal** | One unit of work: a folder under `openspec/changes/<name>/` holding its planning artifacts. Often shortened to "change". Not a git commit. | [Propose](../start/quickstart.md#step-2-propose) |
|
||||
| **Command** | A typed entry point for a workflow. Spelling varies per tool (`/opsx:propose`, `/opsx-propose`). The docs name workflows by skill instead. | [Supported tools](supported-tools.md) |
|
||||
| **Continue** | Create the next planning artifact for an existing change proposal. Skill: `openspec-continue-change`. | [Skills](skills.md) |
|
||||
| **Delivery** | How workflows are installed: as skills, commands, or both. | [Set up your project](../start/setup.md) |
|
||||
| **Delta spec** | A spec inside a change proposal listing only what changes, under `ADDED`, `MODIFIED`, `REMOVED`, and `RENAMED` headers. | [Delta specs](schemas/spec-driven/index.md#delta-specs-specmd) |
|
||||
| **Explore** | Think an idea through with the agent before proposing. Writes no code. Skill: `openspec-explore`. | [Explore an idea](skills.md#openspec-explore) |
|
||||
| **Fast-forward** | Create a change proposal with every planning artifact in one pass, ready to implement. Skill: `openspec-ff-change`. Not a git fast-forward. | [Skills](skills.md) |
|
||||
| **Legacy workflow** | The pre-OPSX `/openspec:*` commands. | |
|
||||
| **Loop** | The cycle a change proposal moves through: explore, propose, review, apply, archive. | [Quickstart](../start/quickstart.md) |
|
||||
| **Main specs** | The `openspec/specs/` tree: the current, agreed behavior of your system. Archiving merges deltas into it. A capability with no spec yet gets one from its `ADDED` requirements. | [Archive](../start/quickstart.md#step-5-archive) |
|
||||
| **OpenSpec root** | The `openspec/` tree a command resolves to and operates on: your repo's, or a store's. | [Stores](../multi-repo/stores.md#where-artifacts-get-created-when-using-stores) |
|
||||
| **OPSX** | The current OpenSpec workflow system, and the command prefix it installs (`/opsx:`). | |
|
||||
| **Profile** | Which workflows init installs: `core` or `custom`. | [Profiles](../customize/profiles.md) |
|
||||
| **Propose** | Create a change proposal and generate all its planning artifacts in one step. Skill: `openspec-propose`. | [Quickstart](../start/quickstart.md) |
|
||||
| **Registry** | The machine-level list of registered stores, in `registry.yaml`. Not a package registry. | [CLI](cli.md#openspec-store) |
|
||||
| **Requirement** | One behavior the system must have, written with SHALL: `### Requirement:` in a spec. | [Delta specs](schemas/spec-driven/index.md#delta-specs-specmd) |
|
||||
| **Scenario** | A testable example under a requirement, in WHEN/THEN form. | [Delta specs](schemas/spec-driven/index.md#delta-specs-specmd) |
|
||||
| **Schema** | The definition of which artifacts a change proposal produces, and in what order. Not JSON Schema. | [Schemas](schemas/index.md) |
|
||||
| **Skill** | A workflow's instructions, installed where your AI tool reads them (`.agents/skills/`, ...). | [Skills](skills.md) |
|
||||
| **Spec** | A file describing how one capability behaves today, at `openspec/specs/<capability>/spec.md`. | [Archive](../start/quickstart.md#step-5-archive) |
|
||||
| **spec-driven** | The default schema: proposal, then delta specs, then design, then tasks. | [spec-driven](schemas/spec-driven/index.md) |
|
||||
| **Store** | A standalone OpenSpec repo registered on your machine, for planning that spans repositories. Not a data store. | [Stores (beta)](../multi-repo/stores.md) |
|
||||
| **Sync** | Merge implemented deltas into the main specs without archiving. Skill: `openspec-sync-specs`. | [Skills](skills.md) |
|
||||
| **Template** | The starting content a schema gives each artifact. | [Schemas](../customize/schemas.md) |
|
||||
| **Update** | As a skill (`openspec-update-change`): revise a change proposal's planning artifacts. As a CLI command (`openspec update`): refresh OpenSpec's installed files. | [Update a change](skills.md#openspec-update-change), [CLI](cli.md) |
|
||||
| **Verify** | Check the implementation matches a change proposal's artifacts before archiving. Skill: `openspec-verify-change`. | [Skills](skills.md) |
|
||||
| **Workflow** | A named OpenSpec action (propose, apply, archive, ...), installed into your AI tool as a skill or command. | [Set up your project](../start/setup.md) |
|
||||
| **Workset** | A personal, local group of folders opened together in one tool. Not a store, and nothing is shared. | [Worksets (beta)](../multi-repo/worksets.md) |
|
||||
@@ -1,20 +0,0 @@
|
||||
# Overview
|
||||
|
||||
> Every available workflow schema and the artifacts it defines.
|
||||
|
||||
<!-- This group states the formats. How schemas shape artifacts and how to
|
||||
change or write one is customize/schemas.md's job. -->
|
||||
|
||||
A schema defines which artifacts a change proposal produces, and in what order. On disk it's a folder with a schema.yaml in it. Every field of that file is on the [schema.yaml](schema-yaml.md) page.
|
||||
|
||||
## Available schemas
|
||||
|
||||
One schema ships with the CLI:
|
||||
|
||||
| Schema | Artifacts |
|
||||
|---|---|
|
||||
| [spec-driven](spec-driven/index.md) (default) | `proposal`, `specs`, `design`, `tasks` |
|
||||
|
||||
A project can add its own schemas, and a machine can override globally. Where those folders live and which copy wins is in schema.yaml's [Location](schema-yaml.md#location) section.
|
||||
|
||||
In your terminal, [`openspec schemas`](../cli.md#openspec-schemas) prints every schema your project can see.
|
||||
@@ -1,228 +0,0 @@
|
||||
# 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>/`:
|
||||
|
||||
```text
|
||||
openspec/schemas/review-first/
|
||||
├── schema.yaml
|
||||
└── templates/
|
||||
├── proposal.md
|
||||
└── tasks.md
|
||||
```
|
||||
|
||||
OpenSpec 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`](../configuration/change-metadata.md#schema). If the `name` field differs from the directory name, OpenSpec still uses the directory name for lookup.
|
||||
|
||||
[`openspec schema which <name>`](../cli.md#openspec-schema-which) 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](#artifact-fields). |
|
||||
| `apply` | Optional [apply settings](#apply-fields). With no block, OpenSpec uses the [apply defaults](#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`:
|
||||
|
||||
```yaml
|
||||
generates: proposal.md
|
||||
```
|
||||
|
||||
The artifact goes here:
|
||||
|
||||
```text
|
||||
openspec/changes/add-auth/proposal.md
|
||||
```
|
||||
|
||||
A glob can match several files:
|
||||
|
||||
```yaml
|
||||
generates: specs/**/*.md
|
||||
```
|
||||
|
||||
This matches Markdown files below `openspec/changes/add-auth/specs/`.
|
||||
|
||||
OpenSpec recognizes these glob forms in `generates`:
|
||||
|
||||
- **Wildcards and character classes**: values containing `*`, `?`, or `[`, such as `specs/**/*.md` and `review-[ab].md`.
|
||||
- **Brace expansions**: alternatives such as `review-{api,ui}.md` and ranges such as `file-{1..3}.md`.
|
||||
- **Extglobs**: patterns such as `@(proposal|design).md`, `+(proposal|design).md`, and `!(proposal|design).md`.
|
||||
|
||||
**Literal filenames**: a leading `!` alone does not make a glob. Use `generates: '!review.md'` to name that file. Plain parentheses such as `(proposal|design).md` and single-element braces such as `review-{api}.md` also remain literal.
|
||||
|
||||
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:
|
||||
|
||||
```yaml
|
||||
template: proposal.md
|
||||
```
|
||||
|
||||
OpenSpec reads this file:
|
||||
|
||||
```text
|
||||
openspec/schemas/review-first/templates/proposal.md
|
||||
```
|
||||
|
||||
OpenSpec 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 `requires` must 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 `artifacts` decides 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 or glob for Markdown task files 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:
|
||||
|
||||
```text
|
||||
openspec/changes/add-auth/tasks.md
|
||||
```
|
||||
|
||||
A glob such as `tracks: "**/tasks.md"` reads every matching file, such as `backend/tasks.md` and `frontend/tasks.md`. OpenSpec combines their tasks and progress. Use the same value for an artifact's `generates` field so status and list track the same files.
|
||||
|
||||
Apply stays blocked if no file matches or the matched files contain no checkbox with task text. OpenSpec counts these checkbox forms:
|
||||
|
||||
```markdown
|
||||
- [ ] Pending task
|
||||
- [x] Completed task
|
||||
* [X] Completed task
|
||||
+ [ ] Pending task
|
||||
1. [ ] Pending task
|
||||
2) [x] Completed task
|
||||
```
|
||||
|
||||
Any 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](spec-driven/index.md#tasksmd) defines the stricter format produced by the default schema.
|
||||
|
||||
The tracked files drive the apply state:
|
||||
|
||||
- **`blocked`**: no file matches, or no readable file has a checkbox with task text.
|
||||
- **`ready`**: at least one task is pending, or a matched file could not be read while another provides tasks.
|
||||
- **`all_done`**: every tracked task is checked and every matched file was read.
|
||||
|
||||
If a matched file cannot be read, apply keeps the tasks and progress from readable files but does not mark the change `all_done`. [Apply JSON output](../cli.md#openspec-instructions) identifies each unavailable file and the reason.
|
||||
|
||||
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
|
||||
|
||||
```yaml
|
||||
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>`](../cli.md#openspec-schema-validate) checks:
|
||||
|
||||
- Field types and required fields
|
||||
- Relative paths
|
||||
- Artifact IDs, dependencies, and cycles
|
||||
- `apply.requires` IDs: 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. |
|
||||
@@ -1,476 +0,0 @@
|
||||
# spec-driven
|
||||
|
||||
> The default workflow's artifacts: their order, their formats, and the change folder they produce.
|
||||
|
||||
`spec-driven` is OpenSpec's built-in default schema. [schema.yaml](../schema-yaml.md) defines the fields it sets.
|
||||
|
||||
## Artifacts
|
||||
|
||||
The workflow drafts four artifacts:
|
||||
|
||||
| Artifact | File | Purpose |
|
||||
|---|---|---|
|
||||
| [`proposal`](#proposalmd) | `proposal.md` | Why the change is needed |
|
||||
| [`specs`](#delta-specs-specmd) | `specs/<capability-path>/spec.md`, one per capability | What behavior changes |
|
||||
| [`design`](#designmd) | `design.md` | How to build it |
|
||||
| [`tasks`](#tasksmd) | `tasks.md` | The implementation checklist |
|
||||
|
||||
## Drafting order
|
||||
|
||||
```text
|
||||
┌─ specs ──┐
|
||||
proposal ────┤ ├── tasks ── apply
|
||||
└─ design ─┘
|
||||
```
|
||||
|
||||
Proposal comes first. Specs and design follow in either order, and tasks needs both. Implementation ([apply](#apply)) starts once `tasks.md` is in place.
|
||||
|
||||
Two artifacts can be skipped:
|
||||
|
||||
- **`design`**: when none of [its conditions](#designmd) apply, the agent leaves it out and drafts `tasks` anyway.
|
||||
- **`specs`**: set [`skip_specs: true`](../../configuration/change-metadata.md#skip_specs) in the change's `.openspec.yaml`.
|
||||
|
||||
## Example change folder
|
||||
|
||||
A change named `add-user-auth`, with every artifact drafted:
|
||||
|
||||
```text
|
||||
openspec/changes/add-user-auth/
|
||||
├── .openspec.yaml change metadata, written when the change is created
|
||||
├── proposal.md
|
||||
├── specs/
|
||||
│ └── user-auth/
|
||||
│ └── spec.md one delta spec per capability
|
||||
├── design.md
|
||||
└── tasks.md
|
||||
```
|
||||
|
||||
## proposal.md
|
||||
|
||||
Establishes why the change is needed.
|
||||
|
||||
### Structure
|
||||
|
||||
The template the agent receives as the output format ([templates/proposal.md](https://github.com/Fission-AI/OpenSpec/blob/main/schemas/spec-driven/templates/proposal.md)):
|
||||
|
||||
```md
|
||||
# Proposal
|
||||
|
||||
## Why
|
||||
|
||||
<!-- Explain the motivation for this change. What problem does this solve? Why now? -->
|
||||
|
||||
## What Changes
|
||||
|
||||
<!-- Describe what will change. Be specific about new capabilities, modifications, or removals. -->
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
<!-- Capabilities being introduced. Use kebab-case for path segments you introduce
|
||||
(e.g., user-auth or identity/user-auth) that follow the project's existing
|
||||
spec organization. Each creates specs/<capability-path>/spec.md. -->
|
||||
- `<capability-path>`: <brief description of what this capability covers>
|
||||
|
||||
### Modified Capabilities
|
||||
<!-- Existing capabilities whose REQUIREMENTS are changing (not just implementation).
|
||||
Only list here if spec-level behavior changes. Each needs a delta spec file.
|
||||
Use the exact existing path under openspec/specs/. Leave empty if no requirement
|
||||
changes. A change with no capabilities at all (pure refactor, tooling, docs)
|
||||
must set `skip_specs: true` in its .openspec.yaml - openspec validate rejects
|
||||
a zero-delta change without that marker. Do not invent a requirement just to
|
||||
satisfy validation. -->
|
||||
- `<existing-capability-path>`: <what requirement is changing>
|
||||
|
||||
## Impact
|
||||
|
||||
<!-- Affected code, APIs, dependencies, systems -->
|
||||
```
|
||||
|
||||
### Instructions
|
||||
|
||||
The instruction sent to the agent when it drafts this artifact (from [schema.yaml](https://github.com/Fission-AI/OpenSpec/blob/main/schemas/spec-driven/schema.yaml)):
|
||||
|
||||
```md
|
||||
Create the proposal document that establishes WHY this change is needed.
|
||||
|
||||
Sections:
|
||||
- **Why**: 1-2 sentences on the problem or opportunity. What problem does this solve? Why now?
|
||||
- **What Changes**: Bullet list of changes. Be specific about new capabilities, modifications, or removals. Mark breaking changes with **BREAKING**.
|
||||
- **Capabilities**: Identify which specs will be created or modified:
|
||||
- **New Capabilities**: List capabilities being introduced. Each becomes a new `specs/<capability-path>/spec.md`. Use kebab-case for path segments you introduce (e.g., `user-auth` or `identity/user-auth`) and follow the project's existing spec organization.
|
||||
- **Modified Capabilities**: List existing capabilities whose REQUIREMENTS are changing. Only include if spec-level behavior changes (not just implementation details). Each needs a delta spec file. Use the exact existing path under `openspec/specs/`. Leave empty if no requirement changes.
|
||||
- **Impact**: Affected code, APIs, dependencies, or systems.
|
||||
|
||||
IMPORTANT: The Capabilities section is critical. It creates the contract between
|
||||
proposal and specs phases. Research existing specs before filling this in:
|
||||
run `openspec list --specs` for the project's capability inventory, then
|
||||
`openspec show "<spec-id>" --type spec --json --no-scenarios` for any that
|
||||
look related - that returns a capability's purpose and requirement texts
|
||||
without pulling whole spec files into context. Append `--store "<id>"` to
|
||||
both commands only for a registered standalone store, and keep `--type
|
||||
spec`: a change and a spec sharing a name is otherwise an ambiguous-item
|
||||
error. `openspec list` without `--specs` lists in-flight changes, not
|
||||
specs - it never shows what the project already covers. Reuse an existing
|
||||
capability's exact path instead of introducing a near-duplicate name.
|
||||
The filtered read is only an overview. Before deciding what is already
|
||||
covered or what should change, read each relevant spec in full, including
|
||||
scenarios, with `openspec show "<spec-id>" --type spec` (same `--store` rule).
|
||||
Each capability listed here will need a corresponding spec file.
|
||||
|
||||
Every change must either declare at least one capability (new or
|
||||
modified) or explicitly opt out of specs: `openspec validate` rejects a
|
||||
change with zero deltas unless the change's `.openspec.yaml` sets
|
||||
`skip_specs: true`. Use `skip_specs: true` only when no spec-level
|
||||
behavior changes (pure refactor, tooling, docs) - specs describe
|
||||
behavior, so if behavior does not change, no spec should change either.
|
||||
Do not invent a requirement just to satisfy validation.
|
||||
|
||||
Keep it concise (1-2 pages). Focus on the "why" not the "how" -
|
||||
implementation details belong in design.md.
|
||||
|
||||
This is the foundation - specs, design, and tasks all build on this.
|
||||
```
|
||||
|
||||
## Delta specs (spec.md)
|
||||
|
||||
Defines what behavior changes, with one delta spec per capability the proposal lists.
|
||||
|
||||
Each delta spec is the `spec.md` inside its capability folder. `openspec validate` and `openspec archive` reject delta sections written in any other file under `specs/`, such as `specs/user-auth.md`, because archive never merges them.
|
||||
|
||||
### Structure
|
||||
|
||||
The template the agent receives as the output format ([templates/spec.md](https://github.com/Fission-AI/OpenSpec/blob/main/schemas/spec-driven/templates/spec.md)):
|
||||
|
||||
```md
|
||||
# Spec Delta
|
||||
|
||||
## Purpose
|
||||
<!-- New capabilities only: one or two sentences (50+ characters) on what this capability is for. Delete this section for an existing capability. -->
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: <!-- requirement name -->
|
||||
<!-- requirement text -->
|
||||
|
||||
#### Scenario: <!-- scenario name -->
|
||||
- **WHEN** <!-- condition -->
|
||||
- **THEN** <!-- expected outcome -->
|
||||
```
|
||||
|
||||
### Instructions
|
||||
|
||||
The instruction sent to the agent when it drafts this artifact (from [schema.yaml](https://github.com/Fission-AI/OpenSpec/blob/main/schemas/spec-driven/schema.yaml)):
|
||||
|
||||
````md
|
||||
Create specification files that define WHAT the system should do.
|
||||
|
||||
A spec is a behavior contract, not an implementation plan.
|
||||
|
||||
Good spec content:
|
||||
- Observable behavior users or downstream systems rely on
|
||||
- Inputs, outputs, and error conditions
|
||||
- External constraints (security, privacy, reliability, compatibility)
|
||||
- Scenarios that can be tested or explicitly validated
|
||||
|
||||
Avoid in specs:
|
||||
- Internal class/function names
|
||||
- Library or framework choices
|
||||
- Step-by-step implementation details
|
||||
- Detailed execution plans (those belong in design.md or tasks.md)
|
||||
|
||||
Quick test: if the implementation can change without changing externally
|
||||
visible behavior, it likely does not belong in the spec.
|
||||
|
||||
Create one spec file per capability listed in the proposal's Capabilities section.
|
||||
`<capability-path>` is the spec directory relative to `specs/` (for example,
|
||||
`user-auth` or `identity/user-auth`). Preserve the full path:
|
||||
- New capabilities: use the exact path from the proposal at `specs/<capability-path>/spec.md`. Any path segment newly introduced in the proposal must be kebab-case. Follow the project's existing organization; do not add a new domain level when the project uses a flat layout.
|
||||
- Modified capabilities: use the exact existing path from `openspec/specs/<capability-path>/` when creating the delta at `specs/<capability-path>/spec.md`. Run `openspec list --specs` to confirm that path before writing the delta, appending `--store "<id>"` only for a registered standalone store - a mistyped or invented path targets a capability that does not exist rather than the one you meant. Do not move or rename the capability.
|
||||
|
||||
There must be at least one spec file unless the change's `.openspec.yaml`
|
||||
sets `skip_specs: true` (no spec-level behavior change) - `openspec validate`
|
||||
rejects a zero-delta change without that marker. If the proposal lists no
|
||||
capabilities and `skip_specs` is not set, revisit the proposal first.
|
||||
|
||||
Delta operations (use ## headers):
|
||||
- **ADDED Requirements**: New capabilities
|
||||
- **MODIFIED Requirements**: Changed behavior - MUST include full updated content
|
||||
- **REMOVED Requirements**: Deprecated features - MUST include **Reason** and **Migration**
|
||||
- **RENAMED Requirements**: Name changes only - use FROM:/TO: format
|
||||
|
||||
Format requirements:
|
||||
- Each requirement: `### Requirement: <name>` followed by description
|
||||
- Use SHALL/MUST for normative requirements (avoid should/may)
|
||||
- Each scenario: `#### Scenario: <name>` with WHEN/THEN format
|
||||
- **CRITICAL**: Scenarios MUST use exactly 4 hashtags (`####`). Using 3 hashtags or bullets will fail silently.
|
||||
- Every requirement MUST have at least one scenario.
|
||||
|
||||
New capabilities only: the delta spec's first section is `## Purpose` -
|
||||
one or two sentences (50+ characters, or `openspec validate --strict`
|
||||
reports it as too brief) describing what the capability is for. Archive
|
||||
copies it into the main spec it creates; without it the new main spec is
|
||||
left with a `TBD ... Update Purpose after archive` placeholder to fill in
|
||||
by hand. Do NOT add `## Purpose` to a delta for an existing capability -
|
||||
that spec already has one and the delta's is ignored. To change an
|
||||
existing capability's Purpose - including a leftover `TBD` placeholder -
|
||||
edit `<planningHome.root>/openspec/specs/<capability-path>/spec.md`
|
||||
directly. `planningHome.root` comes from the `openspec instructions ...
|
||||
--json` response. Always use it rather than a repo-relative path: it
|
||||
resolves to the store whenever the change lives in one - whether that
|
||||
came from `--store`, a project `store:` pointer, or a global default
|
||||
store - and to the current repository otherwise. Do not try to work out
|
||||
which case applies; the field already has.
|
||||
|
||||
MODIFIED requirements workflow:
|
||||
1. Locate the existing requirement in `<planningHome.root>/openspec/specs/<capability-path>/spec.md` (the same store-aware root as above)
|
||||
2. Copy the ENTIRE requirement block (from `### Requirement:` through all scenarios)
|
||||
3. Paste under `## MODIFIED Requirements` and edit to reflect new behavior
|
||||
4. Ensure header text matches exactly (whitespace-insensitive)
|
||||
|
||||
Common pitfall: Using MODIFIED with partial content loses detail at archive time.
|
||||
If adding new concerns without changing existing behavior, use ADDED instead.
|
||||
|
||||
Example (a new capability, so its first section is `## Purpose`):
|
||||
```
|
||||
# Spec Delta
|
||||
|
||||
## Purpose
|
||||
|
||||
Lets users take their data out of the product in a portable format.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: User can export data
|
||||
The system SHALL allow users to export their data in CSV format.
|
||||
|
||||
#### Scenario: Successful export
|
||||
- **WHEN** user clicks "Export" button
|
||||
- **THEN** system downloads a CSV file with all user data
|
||||
|
||||
## REMOVED Requirements
|
||||
|
||||
### Requirement: Legacy export
|
||||
**Reason**: Replaced by new export system
|
||||
**Migration**: Use new export endpoint at /api/v2/export
|
||||
```
|
||||
|
||||
Specs should be testable - each scenario is a potential test case.
|
||||
````
|
||||
|
||||
## design.md
|
||||
|
||||
Explains how to implement the change. Drafted only when the change needs one.
|
||||
|
||||
### Structure
|
||||
|
||||
The template the agent receives as the output format ([templates/design.md](https://github.com/Fission-AI/OpenSpec/blob/main/schemas/spec-driven/templates/design.md)):
|
||||
|
||||
```md
|
||||
# Design
|
||||
|
||||
## Context
|
||||
|
||||
<!-- Current state and constraints that shape the approach. See proposal.md for motivation - don't restate it -->
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
<!-- What this design aims to achieve -->
|
||||
|
||||
**Non-Goals:**
|
||||
<!-- What is explicitly out of scope -->
|
||||
|
||||
## Decisions
|
||||
|
||||
<!-- Key design decisions with rationale and alternatives considered -->
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
<!-- Known risks and trade-offs -->
|
||||
```
|
||||
|
||||
### Instructions
|
||||
|
||||
The instruction sent to the agent when it drafts this artifact (from [schema.yaml](https://github.com/Fission-AI/OpenSpec/blob/main/schemas/spec-driven/schema.yaml)):
|
||||
|
||||
```md
|
||||
Create the design document that explains HOW to implement the change.
|
||||
|
||||
When to include design.md (create only if any apply):
|
||||
- Cross-cutting change (multiple services/modules) or new architectural pattern
|
||||
- New external dependency or significant data model changes
|
||||
- Security, performance, or migration complexity
|
||||
- Ambiguity that benefits from technical decisions before coding
|
||||
|
||||
Sections:
|
||||
- **Context**: Only the current state and constraints needed to explain the approach. Reference the proposal for motivation instead of restating it (e.g., "See proposal.md - Why").
|
||||
- **Goals / Non-Goals**: What this design achieves and explicitly excludes. Don't restate the proposal's scope - add only design-level boundaries.
|
||||
- **Decisions**: Key technical choices with rationale (why X over Y?). Include alternatives considered for each decision.
|
||||
- **Risks / Trade-offs**: Known limitations, things that could go wrong. Format: [Risk] → Mitigation
|
||||
- **Migration Plan**: Steps to deploy, rollback strategy (if applicable)
|
||||
- **Open Questions**: Unknowns that can safely be answered later without
|
||||
changing the specs, the approach, or the task breakdown. Omit if none.
|
||||
|
||||
Open questions are for genuinely deferrable unknowns, not decisions you
|
||||
skipped. If a question would change the specs, the chosen approach, or
|
||||
the task breakdown, resolve it now - ask the user instead of guessing.
|
||||
|
||||
Focus on architecture and approach, not line-by-line implementation.
|
||||
The proposal covers why and what; design covers how. Reference the
|
||||
proposal for motivation and, once written, the specs for requirements -
|
||||
if a section would only restate them, point to them instead.
|
||||
|
||||
Good design docs explain the "why" behind technical decisions.
|
||||
```
|
||||
|
||||
## tasks.md
|
||||
|
||||
Breaks the implementation into checkable tasks. [apply](#apply) tracks progress here.
|
||||
|
||||
### Structure
|
||||
|
||||
The template the agent receives as the output format ([templates/tasks.md](https://github.com/Fission-AI/OpenSpec/blob/main/schemas/spec-driven/templates/tasks.md)):
|
||||
|
||||
```md
|
||||
# Tasks
|
||||
|
||||
## 1. <!-- Task Group Name -->
|
||||
|
||||
- [ ] 1.1 <!-- Task description -->
|
||||
- [ ] 1.2 <!-- Task description -->
|
||||
|
||||
## 2. <!-- Task Group Name -->
|
||||
|
||||
- [ ] 2.1 <!-- Task description -->
|
||||
- [ ] 2.2 <!-- Task description -->
|
||||
```
|
||||
|
||||
### Instructions
|
||||
|
||||
The instruction sent to the agent when it drafts this artifact (from [schema.yaml](https://github.com/Fission-AI/OpenSpec/blob/main/schemas/spec-driven/schema.yaml)):
|
||||
|
||||
````md
|
||||
Create the task list that breaks down the implementation work.
|
||||
|
||||
Before writing tasks, check design.md for Open Questions. If any of them
|
||||
would change what gets built, resolve them with the user first - do not
|
||||
bake an unstated assumption into the task list.
|
||||
|
||||
**IMPORTANT: Follow the template below exactly.** The apply phase parses
|
||||
checkbox format to track progress. A box holding only `x` counts as done,
|
||||
upper or lower case and with any spacing, so `- [ x]` is done too. Every
|
||||
other marker, including `- [~]`, `- [-]` and an empty `- []`, reads as
|
||||
unfinished. A line with no checkbox is not tracked at all.
|
||||
|
||||
Guidelines:
|
||||
- Group related tasks under ## numbered headings
|
||||
- Each task MUST be a checkbox: `- [ ] X.Y Task description`
|
||||
- Tasks should be small enough to complete in one session
|
||||
- Order tasks by dependency (what must be done first?)
|
||||
- Each task MUST state how to verify completion (a test, command,
|
||||
observable behavior, or delivered artifact). Put the verification in
|
||||
that task's checkbox description. Use a separate verification task only
|
||||
when it checks broader integration or system behavior that spans
|
||||
multiple implementation tasks.
|
||||
- Each task group MUST land the tests and documentation its own work
|
||||
calls for. Do NOT collect testing or documentation into a final group -
|
||||
when a late group first exercises work from an early one, the failures
|
||||
cascade back through every group in between and force rework. A group
|
||||
whose work calls for neither, such as scaffolding or dependency setup,
|
||||
carries neither. A final group is for integration checks only, not for
|
||||
the tests and docs an earlier group owed.
|
||||
|
||||
Example:
|
||||
```
|
||||
# Tasks
|
||||
|
||||
## 1. Setup
|
||||
|
||||
- [ ] 1.1 Create new module structure and verify expected files are present
|
||||
- [ ] 1.2 Add dependencies to package.json and verify package installation succeeds
|
||||
|
||||
## 2. Core Implementation
|
||||
|
||||
- [ ] 2.1 Implement data export function and verify the export test passes
|
||||
- [ ] 2.2 Add CSV formatting utilities and verify unit tests cover quoting and delimiters
|
||||
- [ ] 2.3 Document the export API in docs/export.md and verify the documented command runs as written
|
||||
```
|
||||
|
||||
Reference specs for what needs to be built, design for how to build it.
|
||||
````
|
||||
|
||||
## Apply
|
||||
|
||||
The handoff from planning to implementation. Apply is the phase that works through `tasks.md`, not an artifact.
|
||||
|
||||
- **Starts**: once `tasks.md` exists and lists at least one task.
|
||||
- **Tracks**: the checkboxes in `tasks.md`. Checking them off is the progress record.
|
||||
- **Ends**: every checkbox checked. OpenSpec then suggests archiving the change.
|
||||
|
||||
### Settings
|
||||
|
||||
The apply settings (from [schema.yaml](https://github.com/Fission-AI/OpenSpec/blob/main/schemas/spec-driven/schema.yaml)):
|
||||
|
||||
```yaml
|
||||
apply:
|
||||
requires: [tasks]
|
||||
tracks: tasks.md
|
||||
# instruction: shown below
|
||||
```
|
||||
|
||||
### Instructions
|
||||
|
||||
The instruction sent to the agent when implementation starts (from [schema.yaml](https://github.com/Fission-AI/OpenSpec/blob/main/schemas/spec-driven/schema.yaml)):
|
||||
|
||||
```md
|
||||
Read context files, work through pending tasks, mark complete as you go.
|
||||
Pause if you hit blockers or need clarification.
|
||||
```
|
||||
|
||||
## schema.yaml
|
||||
|
||||
The complete [schema.yaml](https://github.com/Fission-AI/OpenSpec/blob/main/schemas/spec-driven/schema.yaml), with instruction bodies elided. Each is shown in full in its section above.
|
||||
|
||||
```yaml
|
||||
name: spec-driven
|
||||
version: 1
|
||||
description: Default OpenSpec workflow - proposal → specs → design → tasks
|
||||
artifacts:
|
||||
- id: proposal
|
||||
generates: proposal.md
|
||||
description: Initial proposal document outlining the change
|
||||
template: proposal.md
|
||||
# instruction: shown in full under proposal.md above
|
||||
requires: []
|
||||
|
||||
- id: specs
|
||||
generates: "specs/**/*.md"
|
||||
description: Detailed specifications for the change
|
||||
template: spec.md
|
||||
# instruction: shown in full under Delta specs above
|
||||
requires:
|
||||
- proposal
|
||||
|
||||
- id: design
|
||||
generates: design.md
|
||||
description: Technical design document with implementation details
|
||||
template: design.md
|
||||
# instruction: shown in full under design.md above
|
||||
requires:
|
||||
- proposal
|
||||
|
||||
- id: tasks
|
||||
generates: tasks.md
|
||||
description: Implementation checklist with trackable tasks
|
||||
template: tasks.md
|
||||
# instruction: shown in full under tasks.md above
|
||||
requires:
|
||||
- specs
|
||||
- design
|
||||
|
||||
apply:
|
||||
requires: [tasks]
|
||||
tracks: tasks.md
|
||||
# instruction: shown in full under Apply above
|
||||
```
|
||||
@@ -1,185 +0,0 @@
|
||||
# Skills
|
||||
|
||||
> Every OpenSpec skill: arguments, what it creates, and what it responds with.
|
||||
|
||||
<!-- Drafted 2026-08-11 via one subagent per entry, each verifying every claim against
|
||||
its workflow template in src/core/templates/workflows/; assembled and uniformity-passed
|
||||
by the main session. Terminology: "change proposal", never bare "change" (user call,
|
||||
2026-08-11). Shape (user-reviewed): intro bullets define Core/Optional, then ONE index
|
||||
table (Skill / Job / Type) and a flat run of H2 entries matching
|
||||
cli.md's shape - no group sections. Recipe per entry: one-line job sentence, then a
|
||||
two-column key-value table (header row "Contract | Description", uniform across
|
||||
entries) holding the pure input/output contract,
|
||||
one row per fact: Arguments (what you pass; each cell self-contains its
|
||||
optional/ambiguous behavior) / Creates (exact paths written; always states the code
|
||||
boundary) / Response (what the agent reports back and where it stops). No judgment
|
||||
rows: no when-to-use beyond the job sentence, no Not-for routing, no guide links
|
||||
(guides link here, not the reverse). The ff job says "create a change proposal"
|
||||
because its template unconditionally scaffolds a new one (redirects if the name
|
||||
exists), contradicting the old "remaining artifacts" framing. Paths shown are the
|
||||
default single-repo layout, stated without a caveat: reference pages state defaults,
|
||||
and the store-moves-the-planning-home fact is multi-repo/stores.md's to teach (the
|
||||
per-tool command spelling story likewise stays with setup.md and supported-tools.md;
|
||||
user cut the NOTE carrying both, 2026-08-11). H2 entries double as the site's
|
||||
right-rail TOC and the anchors guides deep-link. No frontmatter in source: sync-docs.mjs lifts H1 to title and the > line to
|
||||
description (README pins the > line verbatim in its page index). Deliberately
|
||||
excluded, each with an owner elsewhere: per-tool command spellings and syntax
|
||||
(reference/supported-tools.md), example transcripts (quickstart and guides), tips and
|
||||
when-to-use judgment (guides own it), troubleshooting (help/troubleshooting.md),
|
||||
legacy /openspec:* commands (help/legacy/migration.md). Source: old docs/commands.md
|
||||
maps here per sources.md; its unsupported claims (apply "runs tests", bulk-archive
|
||||
name arguments, fixed tasks.md filename) were checked against templates and dropped.
|
||||
Skill names from WORKFLOW_TO_SKILL_DIR (src/core/profile-sync-drift.ts) and the
|
||||
templates in src/core/templates/workflows/; core set src/core/profiles.ts:14. "Optional"
|
||||
is the docs' set label (was "Expanded"; renamed 2026-08-12: the product's only stored
|
||||
profile values are core and custom, so "expanded" reads as a third profile). -->
|
||||
|
||||
The skills come in two sets:
|
||||
|
||||
- **Core**: installed by default, the main planning loop.
|
||||
- **Optional**: installed only when you add them, via [Profiles](../customize/profiles.md).
|
||||
|
||||
Every skill expects a project that already uses OpenSpec. Before its first step that writes anything, a skill checks for a resolved root. What happens when there is none depends on how the skill was reached:
|
||||
|
||||
- **Auto-selected**: your agent picked the skill on its own, without you naming OpenSpec. It drops OpenSpec and answers your request normally, the way it would with OpenSpec not installed.
|
||||
- **Explicit OpenSpec request**: you named OpenSpec, named the skill, or ran its command. It stops before writing and asks how to proceed: run `openspec init` here, target a store with `--store <id>`, or continue without OpenSpec. It waits for your answer.
|
||||
|
||||
Commands are always the second case. A project whose `openspec/config.yaml` names a store this machine cannot resolve (not registered, or a malformed `store:` line) is not treated as uninitialized: the skill stops and shows the store error with its fix. No skill creates an `openspec/` directory on its own in either case. The entries below describe what each skill does once a root is in place.
|
||||
|
||||
| Skill | Job | Type |
|
||||
|---|---|---|
|
||||
| [openspec-explore](#openspec-explore) | Think through an idea before it becomes a change proposal | Core |
|
||||
| [openspec-propose](#openspec-propose) | Create a change proposal with all its planning artifacts in one step | Core |
|
||||
| [openspec-apply-change](#openspec-apply-change) | Implement a change proposal's tasks | Core |
|
||||
| [openspec-update-change](#openspec-update-change) | Revise a change proposal's plan | Core |
|
||||
| [openspec-sync-specs](#openspec-sync-specs) | Merge a change proposal's spec updates into `specs/` | Core |
|
||||
| [openspec-archive-change](#openspec-archive-change) | Move a finished change proposal to the archive | Core |
|
||||
| [openspec-new-change](#openspec-new-change) | Start a change proposal as an empty scaffold | Optional |
|
||||
| [openspec-continue-change](#openspec-continue-change) | Create the next planning artifact, one at a time | Optional |
|
||||
| [openspec-ff-change](#openspec-ff-change) | Create a change proposal with every artifact implementation needs, in one pass | Optional |
|
||||
| [openspec-verify-change](#openspec-verify-change) | Check the implementation matches the plan | Optional |
|
||||
| [openspec-bulk-archive-change](#openspec-bulk-archive-change) | Archive several change proposals at once | Optional |
|
||||
| [openspec-onboard](#openspec-onboard) | Learn the workflow by doing one real change proposal end to end | Optional |
|
||||
|
||||
Each entry below names the skill that owns the next step. When your profile leaves that skill out, the installed files never name it: the handoff becomes the equivalent `openspec` command, or a plain request to you, and a line that exists only to point at a missing skill is not written at all. So the skills you have always hand off to skills you have. Which set you get is [Profiles](../customize/profiles.md).
|
||||
|
||||
## openspec-explore
|
||||
|
||||
Think through an idea before it becomes a change proposal.
|
||||
|
||||
| Contract | Description |
|
||||
|---|---|
|
||||
| **Arguments** | A topic: an idea, a problem, a comparison, or the name of an existing change proposal to explore in context. With nothing given it enters explore mode. |
|
||||
| **Creates** | Nothing by default. It reads and investigates only. On request it captures insights: a new change proposal under `openspec/changes/<name>/`, or updates to an existing one's proposal, design, specs, or tasks. Never code. |
|
||||
| **Response** | An open conversation with no required output. When thinking crystallizes it summarizes the problem, approach, open questions, and next steps, and offers to capture them. You decide. Implementation never starts here. |
|
||||
|
||||
## openspec-propose
|
||||
|
||||
Create a change proposal and generate all its planning artifacts in one step.
|
||||
|
||||
| Contract | Description |
|
||||
|---|---|
|
||||
| **Arguments** | A kebab-case name (`add-dark-mode`) or a plain description. Asks if you give neither. |
|
||||
| **Creates** | `openspec/changes/<name>/` with every artifact the schema defines, in dependency order (spec-driven: proposal, spec deltas, design, tasks). Never code. |
|
||||
| **Response** | The created artifacts, ready for review, and the next step. Stops there; implementation waits for `openspec-apply-change`. |
|
||||
|
||||
## openspec-apply-change
|
||||
|
||||
Implement a change proposal's tasks, working through the list until done or blocked.
|
||||
|
||||
| Contract | Description |
|
||||
|---|---|
|
||||
| **Arguments** | A change proposal name (`add-auth`), optional. If the target is ambiguous it lists the active change proposals and asks you to pick. |
|
||||
| **Creates** | Code: the minimal changes each task calls for, in your project files. In the change proposal it touches only the tasks file, checking off each finished task (`- [ ]` to `- [x]`). |
|
||||
| **Response** | Progress per task, then an overall count (N/M tasks complete). All done: suggests `openspec-archive-change`. Blocked by missing artifacts: points to `openspec-continue-change`, or to `openspec status` and `openspec instructions` when that skill is not installed (the core profile leaves it out). Unclear tasks or errors: pauses and asks. |
|
||||
|
||||
## openspec-update-change
|
||||
|
||||
Revise a change proposal's existing planning artifacts and keep them coherent with each
|
||||
other.
|
||||
|
||||
| Contract | Description |
|
||||
|---|---|
|
||||
| **Arguments** | A change proposal name, optional, plus the revision you want. With no revision stated it runs a coherence review: artifacts checked against each other for contradictions, gaps, and duplication. |
|
||||
| **Creates** | Edits artifact files that already exist. One exception: for an artifact written as a glob, such as `specs/**/*.md`, that already has at least one file, it can add a missing companion file once you confirm the path. An artifact with no files yet is `openspec-continue-change`'s job. Without that skill (the core profile leaves it out), it points to `openspec status` and `openspec instructions` instead. Never code. |
|
||||
| **Response** | Shows each proposed revision and writes it only after you confirm, one artifact at a time. Ends with what was revised and the next step; implementation waits for `openspec-apply-change`. |
|
||||
|
||||
## openspec-sync-specs
|
||||
|
||||
Merge a change proposal's spec updates into `specs/` without archiving it.
|
||||
|
||||
| Contract | Description |
|
||||
|---|---|
|
||||
| **Arguments** | A change proposal name, optional. You can also name a subset of its delta specs, and only those sync. |
|
||||
| **Creates** | Edits or creates `openspec/specs/<capability-path>/spec.md` for each delta spec, merging added, modified, removed, and renamed requirements into the main spec. Never code. |
|
||||
| **Response** | A per-capability summary of requirements added, modified, removed, or renamed, after the updated specs validate. The change proposal stays active; archiving waits for `openspec-archive-change`. |
|
||||
|
||||
## openspec-archive-change
|
||||
|
||||
Move a finished change proposal to the archive.
|
||||
|
||||
| Contract | Description |
|
||||
|---|---|
|
||||
| **Arguments** | A change proposal name, optional. |
|
||||
| **Creates** | Moves the change proposal folder to `openspec/changes/archive/YYYY-MM-DD-<name>/` (no date added if the name already starts with one). With your approval it first syncs outstanding delta specs via `openspec-sync-specs`. Never code. |
|
||||
| **Response** | Warns and asks before archiving with incomplete artifacts or tasks, and asks whether to sync when delta specs exist. Ends with a summary: name, schema, archive location, spec sync status, and any warnings. |
|
||||
|
||||
## openspec-new-change
|
||||
|
||||
Start a change proposal as an empty scaffold.
|
||||
|
||||
| Contract | Description |
|
||||
|---|---|
|
||||
| **Arguments** | A kebab-case name (`add-user-auth`) or a plain description, plus a schema name only for a non-default workflow. Asks what you want to build if you give neither. |
|
||||
| **Creates** | `openspec/changes/<name>/` as an empty scaffold: no artifacts yet, never code. |
|
||||
| **Response** | The scaffold's name and location, the workflow's artifact sequence, status (0/N complete), and the first artifact's template. Drafting artifacts waits for `openspec-continue-change`. |
|
||||
|
||||
## openspec-continue-change
|
||||
|
||||
Create the next planning artifact in a change proposal, one at a time.
|
||||
|
||||
| Contract | Description |
|
||||
|---|---|
|
||||
| **Arguments** | A change proposal name, optional. If still ambiguous it asks you to pick from the most recently modified. |
|
||||
| **Creates** | The single next ready artifact in the schema's sequence, written into the change proposal folder. One artifact per run, never code. |
|
||||
| **Response** | The created artifact, progress (N of M complete), and which artifacts that unlocked. When planning is complete it says so; implementation moves to `openspec-apply-change`. |
|
||||
|
||||
## openspec-ff-change
|
||||
|
||||
Create a change proposal and every planning artifact implementation needs, in one pass.
|
||||
|
||||
| Contract | Description |
|
||||
|---|---|
|
||||
| **Arguments** | A kebab-case name or a plain description. Asks if you give neither. If the named change proposal already exists it suggests continuing it instead. |
|
||||
| **Creates** | `openspec/changes/<name>/` and every planning artifact implementation requires, in dependency order (spec-driven: proposal, specs, design, tasks), leaving out only artifacts marked skipped or conditional. Never code. |
|
||||
| **Response** | The change proposal's name and location, each artifact created, and any conditional artifact skipped and why. Stops there; implementation waits for `openspec-apply-change`. |
|
||||
|
||||
## openspec-verify-change
|
||||
|
||||
Check that the implementation matches the change proposal's artifacts.
|
||||
|
||||
| Contract | Description |
|
||||
|---|---|
|
||||
| **Arguments** | A change proposal name, optional. When ambiguous it asks, listing change proposals that have a tasks artifact. |
|
||||
| **Creates** | Nothing. It reads the change proposal's artifacts and the codebase. Verification is report-only. |
|
||||
| **Response** | A report: a scorecard for Completeness, Correctness, and Coherence, then CRITICAL, WARNING, and SUGGESTION issues with recommendations, and a final archive-readiness assessment. It changes nothing and does not archive. |
|
||||
|
||||
## openspec-bulk-archive-change
|
||||
|
||||
Archive several change proposals at once.
|
||||
|
||||
| Contract | Description |
|
||||
|---|---|
|
||||
| **Arguments** | None. It lists the active change proposals and asks you to select any number, with an option for all. If none are active it says so and stops. |
|
||||
| **Creates** | `openspec/changes/archive/YYYY-MM-DD-<name>/` per archived change proposal (already-dated names keep their prefix). Each one's spec deltas sync first via `openspec-sync-specs`. Never code. |
|
||||
| **Response** | A status table per change proposal and one confirmation for the whole batch, then a summary of archived, skipped, and failed, plus spec sync results. When two change proposals touch the same spec it checks the codebase and syncs implemented deltas oldest first. |
|
||||
|
||||
## openspec-onboard
|
||||
|
||||
Learn the workflow by doing one real change proposal end to end.
|
||||
|
||||
| Contract | Description |
|
||||
|---|---|
|
||||
| **Arguments** | None. It scans your codebase for small starter tasks and asks you to pick one or describe your own. |
|
||||
| **Creates** | A real change proposal for the chosen task, one artifact at a time, then real code once you confirm implementation. Archives the change proposal at the end. |
|
||||
| **Response** | A narrated walkthrough of the full cycle with pauses for your input: explore, create, build each artifact, implement, archive. Ends with a recap and a pointer to `openspec-propose`. Takes about 15 to 20 minutes. |
|
||||
@@ -1,144 +0,0 @@
|
||||
# Supported tools
|
||||
|
||||
> Which AI coding tools OpenSpec supports, and each one's command syntax.
|
||||
|
||||
Every tool in the matrix runs the same OpenSpec workflows. A skill and its command are
|
||||
the same workflow instructions. The only difference is what you type. Which form init
|
||||
installs is the delivery setting, covered in
|
||||
[Set up your project](../start/setup.md#the-workflow-files-skills-and-commands).
|
||||
|
||||
## Support matrix
|
||||
|
||||
Invocations are shown for the apply workflow. Every workflow follows the same shape.
|
||||
The id goes to `openspec init --tools <id>` to skip the picker ([CLI](cli.md)).
|
||||
|
||||
| Tool | `--tools` id | Skills | Skill invocation | Commands | Command invocation |
|
||||
|---|---|---|---|---|---|
|
||||
| Amazon Q Developer | `amazon-q` | `.amazonq/skills/` | `/openspec-apply-change` | `.amazonq/prompts/` | `@opsx-apply` |
|
||||
| Antigravity | `antigravity` | `.agents/skills/` | `/openspec-apply-change` | `.agents/workflows/` | `/opsx-apply` |
|
||||
| Auggie (Augment CLI) | `auggie` | `.augment/skills/` | `/openspec-apply-change` | `.augment/commands/` | `/opsx-apply` |
|
||||
| Bob Shell | `bob` | `.bob/skills/` | `/openspec-apply-change` | `.bob/commands/` | `/opsx-apply` |
|
||||
| Claude Code | `claude` | `.claude/skills/` | `/openspec-apply-change` | `.claude/commands/opsx/` | `/opsx:apply` |
|
||||
| Cline | `cline` | `.cline/skills/` | `/openspec-apply-change` | `.clinerules/workflows/` | `/opsx-apply` |
|
||||
| CodeArts | `codeartsagent` | `.codeartsdoer/skills/` | `/openspec-apply-change` | none | none |
|
||||
| CodeBuddy Code (CLI) | `codebuddy` | `.codebuddy/skills/` | `/openspec-apply-change` | `.codebuddy/commands/opsx/` | `/opsx:apply` |
|
||||
| Codex | `codex` | `.agents/skills/` | `$openspec-apply-change` | none | none |
|
||||
| Continue | `continue` | `.continue/skills/` | `/openspec-apply-change` | `.continue/prompts/` | `/opsx-apply` |
|
||||
| CoStrict | `costrict` | `.cospec/skills/` | `/openspec-apply-change` | `.cospec/openspec/commands/` | `/opsx-apply` |
|
||||
| Crush | `crush` | `.crush/skills/` | `/openspec-apply-change` | `.crush/commands/opsx/` | `/opsx:apply` |
|
||||
| Cursor | `cursor` | `.cursor/skills/` | `/openspec-apply-change` | `.cursor/commands/` | `/opsx-apply` |
|
||||
| Devin Desktop (formerly Windsurf) | `devin` | `.devin/skills/` | `/openspec-apply-change` | `.devin/workflows/` | `/opsx-apply` |
|
||||
| Factory Droid | `factory` | `.factory/skills/` | `/openspec-apply-change` | `.factory/commands/` | `/opsx-apply` |
|
||||
| ForgeCode | `forgecode` | `.forge/skills/` | `/openspec-apply-change` | none | none |
|
||||
| Gemini CLI | `gemini` | `.gemini/skills/` | `/openspec-apply-change` | `.gemini/commands/opsx/` | `/opsx:apply` |
|
||||
| GitHub Copilot | `github-copilot` | `.github/skills/` | `/openspec-apply-change` | `.github/prompts/` | `/opsx-apply` |
|
||||
| Hermes Agent | `hermes` | `.hermes/skills/` | `/openspec-apply-change` | none | none |
|
||||
| iFlow | `iflow` | `.iflow/skills/` | `/openspec-apply-change` | `.iflow/commands/` | `/opsx-apply` |
|
||||
| Junie | `junie` | `.junie/skills/` | `/openspec-apply-change` | `.junie/commands/` | `/opsx-apply` |
|
||||
| Kilo Code | `kilocode` | `.kilocode/skills/` | `/openspec-apply-change` | `.kilo/command/` | `/opsx-apply` |
|
||||
| Kimi Code | `kimi` | `.kimi-code/skills/` | `/skill:openspec-apply-change` | none | none |
|
||||
| Kiro | `kiro` | `.kiro/skills/` | `/openspec-apply-change` | `.kiro/prompts/` | `/opsx-apply` |
|
||||
| Lingma | `lingma` | `.lingma/skills/` | `/openspec-apply-change` | `.lingma/commands/opsx/` | `/opsx:apply` |
|
||||
| MiniMax Code | `minimax-code` | `~/.minimax/skills/` (global) | `/openspec-apply-change` | none | none |
|
||||
| Mistral Vibe | `vibe` | `.vibe/skills/` | `/openspec-apply-change` | none | none |
|
||||
| Oh My Pi | `oh-my-pi` | `.omp/skills/` | `/openspec-apply-change` | `.omp/commands/` | `/opsx-apply` |
|
||||
| OpenCode | `opencode` | `.opencode/skills/` | `/openspec-apply-change` | `.opencode/commands/` | `/opsx-apply` |
|
||||
| Pi | `pi` | `.pi/skills/` | `/openspec-apply-change` | `.pi/prompts/` | `/opsx-apply` |
|
||||
| Qoder | `qoder` | `.qoder/skills/` | `/openspec-apply-change` | `.qoder/commands/opsx/` | `/opsx:apply` |
|
||||
| Qwen Code | `qwen` | `.qwen/skills/` | `/openspec-apply-change` | `.qwen/commands/` | `/opsx-apply` |
|
||||
| Trae | `trae` | `.trae/skills/` | `/openspec-apply-change` | `.trae/commands/` | `/opsx-apply` |
|
||||
| ZCode | `zcode` | `.zcode/skills/` | `/openspec-apply-change` | `.zcode/commands/opsx/` | `/opsx:apply` |
|
||||
| Zoo Code | `roocode` | `.roo/skills/` | `/openspec-apply-change` | `.roo/commands/` | `/opsx-apply` |
|
||||
| Other / Universal | `agents` | `.agents/skills/` | `/openspec-apply-change` | none | none |
|
||||
|
||||
- **Skill invocation**: whether a tool registers skills as typed entries is the tool's
|
||||
own behavior. The column shows the spelling OpenSpec uses in generated files and in
|
||||
the hint init prints. Check your tool's docs if typing it does nothing.
|
||||
- **Command file formats**: most tools take `.md` command files. Gemini CLI takes
|
||||
`.toml`, Continue `.prompt`, Kiro and GitHub Copilot `.prompt.md`. The spelling you
|
||||
type is the same either way.
|
||||
|
||||
## Per-tool notes
|
||||
|
||||
A tool not listed here behaves exactly as its row reads.
|
||||
|
||||
### Antigravity
|
||||
|
||||
- **Current folder**: Antigravity v1.20.5 and later read workspace skills and
|
||||
workflows from `.agents/`.
|
||||
- **Legacy folder**: after OpenSpec writes replacements, it removes equivalent
|
||||
generated files from `.agent/`. Custom files and changed generated files stay in
|
||||
`.agent/` for you to review.
|
||||
- **Shared skills**: Antigravity shares `.agents/skills/` with Codex, Zed Agent, and
|
||||
the `agents` target. OpenSpec writes that skill tree once while still writing
|
||||
Antigravity commands to `.agents/workflows/`.
|
||||
|
||||
### Cline
|
||||
|
||||
Cline reads commands from `.clinerules/workflows/`, not from its `.cline/` folder.
|
||||
Skills stay in `.cline/skills/`.
|
||||
|
||||
### Codex
|
||||
|
||||
- **CLI and IDE extension**: mention `$openspec-propose` with your idea, or run
|
||||
`/skills` to select the skill. Codex does not recognize `/openspec-propose`
|
||||
([upstream issue](https://github.com/openai/codex/issues/11817)).
|
||||
- **Desktop app**: open Skills in the sidebar and select `openspec-propose`.
|
||||
[OpenAI's skills documentation](https://learn.chatgpt.com/docs/build-skills)
|
||||
describes both interfaces.
|
||||
- **No command files**: Codex runs skills directly, so init skips commands even when
|
||||
delivery includes them and prints `Commands skipped for: codex (uses skills)`.
|
||||
- **Shared folder**: Codex skills land in `.agents/skills/`, the same tree Antigravity,
|
||||
Zed Agent, and the `agents` target use. Selecting more than one keeps a single
|
||||
compatible tree, and its handoffs spell both `$openspec-*` and `/openspec-*` when
|
||||
Codex owns it.
|
||||
- **Legacy path**: skills installed under `.codex/skills/` by older versions are
|
||||
migrated on the next `openspec update`.
|
||||
|
||||
### Devin Desktop (formerly Windsurf)
|
||||
|
||||
- **Two agents**: command files in `.devin/workflows/` work only in Devin Desktop.
|
||||
Devin Local runs skills only, so generated skills reference `/openspec-<skill>`,
|
||||
which works in both.
|
||||
- **Rename**: `--tools windsurf` still resolves to `devin`. A project holding
|
||||
OpenSpec files in the legacy `.windsurf/` folder is offered the move on the next
|
||||
`openspec update`.
|
||||
|
||||
### GitHub Copilot
|
||||
|
||||
- **IDE extensions (command delivery)**: VS Code, JetBrains, and Visual Studio load
|
||||
`.github/prompts/opsx-<id>.prompt.md` as `/opsx-<id>`. If a command disappears
|
||||
while its file still exists, restart the IDE.
|
||||
- **Copilot CLI (skill delivery)**: the CLI ignores `.github/prompts/` and loads
|
||||
`.github/skills/openspec-*/SKILL.md` instead. Invoke a skill as
|
||||
`/openspec-<skill>`. If a skill disappears while its file still exists, run
|
||||
`/skills reload`, then `/skills info openspec-propose` to confirm discovery.
|
||||
|
||||
### Hermes Agent
|
||||
|
||||
Hermes loads skills only from `~/.hermes/skills/` by default. Add the project's
|
||||
`.hermes/skills/` folder to `skills.external_dirs` in `~/.hermes/config.yaml`;
|
||||
init prints this reminder after install.
|
||||
|
||||
### MiniMax Code
|
||||
|
||||
- **Global only**: skills go to `~/.minimax/skills/`. Nothing is written inside
|
||||
the repo.
|
||||
- **Safe across projects**: a commands-only delivery leaves the global skills in
|
||||
place, so one project's setting cannot remove skills another project uses.
|
||||
|
||||
### Other / Universal (shared `.agents` skills)
|
||||
|
||||
- **When it fits**: any tool that reads the shared `.agents/skills/` folder,
|
||||
including tools with no row in the matrix. It is the entry to pick when your
|
||||
assistant is not listed. The init picker's search box finds it by `universal`,
|
||||
`other`, `generic`, `custom`, `proprietary`, `unlisted`, `unsupported`,
|
||||
`vendor-neutral`, or `agents.md`.
|
||||
- **Alongside other targets**: Antigravity, Codex, Zed Agent, and this target share
|
||||
one physical skill tree. OpenSpec records one writer in `.openspec-target` and
|
||||
writes the tree once per run. Each tool's separate command files are still
|
||||
generated.
|
||||
- **What OpenSpec claims**: only the `openspec-*` folders and the
|
||||
`.openspec-target` marker. Anything else under `.agents/` is left alone.
|
||||
- **`AGENTS.md`**: not created or edited. The target is the `.agents/` folder, not
|
||||
the file.
|
||||
@@ -1,45 +0,0 @@
|
||||
# Where every current page goes
|
||||
|
||||
The old-to-new mapping: the source material for each `docs-lab/` page while drafting,
|
||||
and the redirect list at cutover. The target structure is the page index in
|
||||
[README.md](README.md).
|
||||
|
||||
| Current (`docs/`) | Destination |
|
||||
|---|---|
|
||||
| README.md (index) | `start/overview.md`, rewritten as pitch and routing |
|
||||
| getting-started.md | `start/quickstart.md` |
|
||||
| installation.md | split: `start/installation.md` (machine-level: matrix, update, uninstall) · `start/setup.md` (project-level: init, what init writes, skills-vs-commands delivery, stores router) |
|
||||
| how-commands-work.md | `start/quickstart.md` (inline labels) · `help/faq.md` · `help/troubleshooting.md` |
|
||||
| existing-projects.md | `guides/existing-codebases.md` ("Existing codebases"); walkthrough half to `start/quickstart.md` |
|
||||
| overview.md | `guides/concepts.md` |
|
||||
| concepts.md | `guides/concepts.md` (core) · delta format to `reference/schemas/spec-driven/index.md` (Delta specs section) · embedded glossary table deleted |
|
||||
| explore.md | `guides/explore.md` |
|
||||
| workflows.md | `guides/apply.md` (execution patterns, continue/ff) · `reference/skills.md` |
|
||||
| opsx.md | split four ways: config to `customize/project-config.md` · commands to `reference/skills.md` · philosophy to `guides/concepts.md` · architecture to `reference/architecture/` |
|
||||
| reviewing-changes.md + writing-specs.md | `guides/review-the-plan.md` (merged) |
|
||||
| editing-changes.md | `guides/change-course.md` |
|
||||
| team-workflow.md | `guides/teams.md` |
|
||||
| examples.md | parked: `guides/examples.md` skeleton kept off the index and sync config until real archived changes exist (see README TODOs) |
|
||||
| customization.md | `customize/project-config.md` + `customize/schemas.md` + `customize/overview.md` (decision ladder) · schema.yaml fields to `reference/schemas/schema-yaml.md` |
|
||||
| multi-language.md | `customize/project-config.md` §context, the "Another language" note |
|
||||
| stores-beta/user-guide.md | `multi-repo/stores.md` · worksets section to `multi-repo/worksets.md` |
|
||||
| commands.md | `reference/skills.md` (legacy `/openspec:*` section removed) |
|
||||
| cli.md | `reference/cli.md` (minus install, which moves to `start/installation.md`) |
|
||||
| supported-tools.md | `reference/supported-tools.md` |
|
||||
| glossary.md | `reference/glossary.md` |
|
||||
| faq.md | `help/faq.md` (unpublished-model claim deleted; update/uninstall to `start/installation.md`) |
|
||||
| troubleshooting.md | `help/troubleshooting.md`, canonical home for all 5 copies, plus Getting help |
|
||||
| migration-guide.md | `help/legacy/migration.md` (demoted) |
|
||||
| agent-contract.md | **off-site**, to repo-side contributor docs |
|
||||
|
||||
New pages with no single current source: `customize/overview.md`, `customize/profiles.md`
|
||||
(today: scattered two-line fragments across 12 pages), and the
|
||||
`reference/schemas/` and `reference/configuration/` sections (which replaced the
|
||||
planned `reference/file-formats.md`).
|
||||
|
||||
## Cutover
|
||||
|
||||
Point `website/docs.sync.config.mjs` here, add old-to-new redirects in
|
||||
`website/public/_redirects`, and verify `llms.txt` / `llms-full.txt` /
|
||||
per-page markdown routes. `docs/` stays in place, untouched. The site just
|
||||
stops reading it.
|
||||
@@ -1,168 +0,0 @@
|
||||
# Installation
|
||||
|
||||
> Install the `openspec` CLI on your machine, update it, and uninstall it.
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
OpenSpec runs on Node.js 20.19.0 or newer. Homebrew installs Node.js as a
|
||||
dependency, and the Nix package includes the runtime. Check your installed version
|
||||
before using another install method.
|
||||
|
||||
In your terminal:
|
||||
|
||||
```bash
|
||||
node --version
|
||||
```
|
||||
|
||||
If that prints `v20.19.0` or higher, you're set. If not, install a newer Node from
|
||||
[nodejs.org](https://nodejs.org) or through your version manager (nvm, fnm, asdf,
|
||||
volta). You can skip this check when you install with Homebrew or Nix.
|
||||
|
||||
The workflow itself runs inside an AI coding tool: Claude Code, Cursor, or any other tool on the [supported list](../reference/supported-tools.md).
|
||||
|
||||
## Install with your AI assistant
|
||||
|
||||
Paste this into your AI chat:
|
||||
|
||||
```text
|
||||
Fetch https://raw.githubusercontent.com/Fission-AI/OpenSpec/main/install.md and follow it.
|
||||
```
|
||||
|
||||
Or, in your terminal, pipe it into a CLI agent (Claude Code shown):
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/Fission-AI/OpenSpec/main/install.md | claude
|
||||
```
|
||||
|
||||
That fetches [install.md at the repo root](https://github.com/Fission-AI/OpenSpec/blob/main/install.md), a prompt written for any agent that can run shell commands (a few IDE integrations can't). Expect your assistant to:
|
||||
|
||||
1. Check your Node version, and stop if it's older than 20.19.0.
|
||||
2. Skip the install if the CLI is already on your machine. Otherwise, show you the install command and wait for your confirmation before running it.
|
||||
3. Verify `openspec` is on your PATH.
|
||||
4. Name the folder it thinks you mean, suggest the AI tool you're already talking to, and ask which others you use, then run `openspec init` there (the [project setup](setup.md) step).
|
||||
5. Report what init created and the exact spelling to invoke OpenSpec in your tool.
|
||||
|
||||
It stops before anything privileged and never edits your shell startup files. The [manual methods below](#install-methods) are the source of truth, and the prompt runs them for you.
|
||||
|
||||
This install method is new and can have varying results depending on model used. Only use if you're comfortable correcting AI mistakes. Otherwise we recommend following the standard method below.
|
||||
|
||||
## Install methods
|
||||
|
||||
Install the CLI globally; [setting up your project](setup.md) comes after.
|
||||
|
||||
In your terminal:
|
||||
|
||||
```npm
|
||||
npm install -g @fission-ai/openspec@latest
|
||||
```
|
||||
|
||||
### Homebrew
|
||||
|
||||
Homebrew installs OpenSpec and its Node.js dependency on macOS or Linux. In your terminal:
|
||||
|
||||
```bash
|
||||
brew install openspec
|
||||
```
|
||||
|
||||
The formula is published in [homebrew-core](https://formulae.brew.sh/formula/openspec), so you don't need to add a tap.
|
||||
|
||||
### Yarn
|
||||
|
||||
`yarn global add` is Yarn Classic (1.x) only. Modern Yarn removed global installs, so use npm, pnpm, or bun instead. A global CLI doesn't have to share your project's package manager.
|
||||
|
||||
### Bun
|
||||
|
||||
Bun installs OpenSpec but doesn't run it, so you still need Node on your machine (the [prerequisite](#prerequisites) above). Without it, every command fails with `env: node: No such file or directory`. Bun treats [every Node CLI](https://bun.com/docs/pm/bunx#shebangs) this way.
|
||||
|
||||
### Deno
|
||||
|
||||
Deno installs the CLI from npm and needs explicit permission flags. In your terminal:
|
||||
|
||||
```bash
|
||||
deno install --global \
|
||||
--allow-read --allow-write --allow-env --allow-sys=cpus,homedir --allow-net=edge.openspec.dev \
|
||||
npm:@fission-ai/openspec@latest
|
||||
```
|
||||
|
||||
Some commands launch another program: [`openspec config edit`](../reference/cli.md) opens your editor. Deno interrupts those with a permission prompt on every run. To stop it asking, add a scoped `--allow-run=<program>` to the install command.
|
||||
|
||||
> [!NOTE]
|
||||
> If Deno can't resolve `@latest`, pin a version range instead: `npm:@fission-ai/openspec@^1.7.0`.
|
||||
|
||||
### Nix
|
||||
|
||||
The OpenSpec repo ships a Nix flake. Install it into your profile. In your terminal:
|
||||
|
||||
```bash
|
||||
nix profile install github:Fission-AI/OpenSpec
|
||||
```
|
||||
|
||||
Or run a one-off command first, without installing:
|
||||
|
||||
```bash
|
||||
nix run github:Fission-AI/OpenSpec -- --version
|
||||
```
|
||||
|
||||
That leaves nothing on your PATH, so there's no install to check afterward.
|
||||
|
||||
To put OpenSpec in a project dev shell instead, add the flake as an input and use its default package; [flake.nix](https://github.com/Fission-AI/OpenSpec/blob/main/flake.nix) lists the outputs.
|
||||
|
||||
The Nix package ships the Bash, Fish, and Zsh completion scripts at the standard
|
||||
locations (`share/bash-completion/completions`, `share/fish/vendor_completions.d`,
|
||||
`share/zsh/site-functions`), so they load with the package and there is no need to run
|
||||
`openspec completion install`.
|
||||
|
||||
### Check it worked
|
||||
|
||||
Whichever method you used, in your terminal:
|
||||
|
||||
```bash
|
||||
openspec --version
|
||||
```
|
||||
|
||||
If that prints a version number, the CLI is on your PATH. It installs once per machine.
|
||||
|
||||
Next, [set up your project](setup.md). If your assistant already ran init, that page shows what it wrote and how to adjust it.
|
||||
|
||||
## Updating
|
||||
|
||||
In your terminal, in each project where you ran init:
|
||||
|
||||
```bash
|
||||
openspec update
|
||||
```
|
||||
|
||||
When a newer CLI is out, [`openspec update`](../reference/cli.md#openspec-update) says so and can install it for you; that upgrade is once per machine. Every run refreshes the project's generated skills and commands, which never update on their own. A current project prints `✓ All 2 tool(s) up to date (v1.7.0)`.
|
||||
|
||||
|
||||
> [!WARNING]
|
||||
> On Homebrew, run `brew upgrade openspec`. On Deno, re-run the [Deno install](#deno) with `-f`; it won't overwrite the installed command without it. On Nix, use `nix profile upgrade openspec`.
|
||||
|
||||
> [!NOTE]
|
||||
> A global npm install belongs to one Node installation. Switch Node versions with nvm and the `openspec` command doesn't come along, so install it again under the new version.
|
||||
|
||||
## Uninstalling
|
||||
|
||||
To uninstall OpenSpec, run through the steps below; none of them touch your source code. You can also point your agent at this section and let it handle the removal.
|
||||
|
||||
**1. Remove [shell completions](../reference/cli.md#openspec-completion)**, if you set them up, while the CLI can still do it. In your terminal:
|
||||
|
||||
```bash
|
||||
openspec completion uninstall
|
||||
```
|
||||
|
||||
**2. Remove the package.** In your terminal:
|
||||
|
||||
```npm
|
||||
npm uninstall -g @fission-ai/openspec
|
||||
```
|
||||
|
||||
On Homebrew: `brew uninstall openspec`. On Deno: `deno uninstall --global openspec`. On Nix: `nix profile remove openspec`. Your shell should no longer find `openspec`.
|
||||
|
||||
**3. Delete what's left, or keep it.**
|
||||
|
||||
- Generated agent files: `openspec-*` skills and `opsx` commands under directories like `.claude/` or `.agents/`, per project. [Supported tools](../reference/supported-tools.md) lists each tool's paths; MiniMax Code keeps skills in `~/.minimax/skills`.
|
||||
- Leftovers from older versions: marker blocks in `CLAUDE.md` or `AGENTS.md` (delete the block, keep the file) and `opsx-*.md` prompts in `~/.codex/prompts`.
|
||||
- The `openspec/` folder: pause first. `specs/` and `changes/archive/` are your record of the system, plain Markdown that reads fine without OpenSpec.
|
||||
- Per-machine state: settings and the telemetry id in `~/.config/openspec/`; schema overrides and store registrations in `~/.local/share/openspec/` (Windows: `%APPDATA%\openspec`, `%LOCALAPPDATA%\openspec`). Registrations are pointers; the store repos they point to are untouched.
|
||||
@@ -1,14 +0,0 @@
|
||||
# Overview
|
||||
|
||||
TODO: this page is being rewritten from scratch.
|
||||
|
||||
<!-- Emptied 2026-08-21. The previous skeleton (section headings, narrative beats, and
|
||||
the diagram-options gallery) was cleared so the page starts clean. The old goal line
|
||||
("OpenSpec gives you and your coding agent a shared, reviewable plan before code is
|
||||
written") was dropped as too weak a pitch: the rewrite should sell keeping larger
|
||||
features on track and aligned (teams, git-native artifacts, intended behavior matching
|
||||
implemented behavior, the control-loop framing). The brief is in docs-lab/Notes.md
|
||||
under "Start > Overview". The diagram candidates (docs-lab/diagrams/) were deleted
|
||||
with the gallery; recover them from git history if the rewrite wants a starting point.
|
||||
README rules that still bind the rewrite: the loop appears here as pitch only, copy and
|
||||
no explanation; the quickstart is its one teacher. -->
|
||||
@@ -1,174 +0,0 @@
|
||||
# Quickstart
|
||||
|
||||
> Your first change, from idea to archived, in a new or existing project.
|
||||
|
||||
Before you start, you need the CLI on your machine ([Installation](installation.md)) and OpenSpec initialized in your project ([Set up your project](setup.md)).
|
||||
|
||||
## Start from an empty project
|
||||
|
||||
You can start without a chosen stack or a complete architecture. Initialize OpenSpec in your project folder, then ask your agent to explore the options with you. In your AI chat:
|
||||
|
||||
```text
|
||||
Help me explore a task tracker from scratch. I have not picked a stack. Compare the options and help me choose the first behavior to build.
|
||||
```
|
||||
|
||||
Decide what the first change needs and leave later architecture choices open. Ask your agent to propose that one change, then follow the steps below. You can revisit the architecture as the project grows.
|
||||
|
||||
## The loop at a glance
|
||||
|
||||
Every change moves through the same five steps: you think the idea through with your agent, it drafts a plan, you correct the plan before any code exists, the agent builds from it, and archiving updates your specs with what shipped.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
explore["1 · Explore<br/>think it through together"] --> propose["2 · Propose<br/>agent drafts the plan"]
|
||||
propose --> review["3 · Review<br/>you correct the plan"]
|
||||
review --> apply["4 · Apply<br/>agent builds, task by task"]
|
||||
apply --> archive["5 · Archive<br/>specs absorb the change"]
|
||||
archive -. "next change" .-> explore
|
||||
```
|
||||
|
||||
Every prompt below goes in your AI chat, the same place you ask for code. The examples use plain language so they work across tools. You can also invoke a skill directly; the syntax varies by tool ([supported tools](../reference/supported-tools.md)).
|
||||
|
||||
## Step 1: Explore
|
||||
|
||||
Think the idea through with your agent before you ask for a plan. In your AI chat:
|
||||
|
||||
```text
|
||||
Help me explore how rate limiting should work in this app.
|
||||
```
|
||||
|
||||
Explore is a thinking mode. The agent investigates your codebase, asks the questions that matter, sketches options, and challenges assumptions. It never writes code. It writes nothing else unless you ask it to capture what you decided, or say yes when it offers. The output is a sharper idea.
|
||||
|
||||
Stay here as long as the problem needs. When the shape feels right, hand it off:
|
||||
|
||||
```text
|
||||
Propose the change we just discussed.
|
||||
```
|
||||
|
||||
That line starts propose for you, carrying everything you settled. Skip the first prompt in step 2.
|
||||
|
||||
## Step 2: Propose
|
||||
|
||||
Propose turns the idea into a reviewable plan. Coming from explore, it's already running. Starting cold, when the change is clear in your head, ask directly. In your AI chat:
|
||||
|
||||
```text
|
||||
Propose a change to add rate limiting.
|
||||
```
|
||||
|
||||
The agent asks what it needs to, then writes a change folder:
|
||||
|
||||
```
|
||||
openspec/changes/add-rate-limiting/
|
||||
├── proposal.md why, and what changes
|
||||
├── specs/ what "done" means, as testable requirements
|
||||
├── design.md technical decisions (only when the change needs one)
|
||||
└── tasks.md the implementation checklist
|
||||
```
|
||||
|
||||
No code yet. Propose stops at the plan.
|
||||
|
||||
## Step 3: Review and correct the plan
|
||||
|
||||
Fix the plan while it's still words and nothing is built yet. Read in this order:
|
||||
|
||||
- **`proposal.md`**: is this the right problem, at the right size?
|
||||
- **`specs/`**: the highest-value read. Would you accept these requirements as done?
|
||||
- **`tasks.md`**: do the tasks cover the specs, and nothing more?
|
||||
|
||||
To fix something, either works:
|
||||
|
||||
- Edit the file yourself. The artifacts are plain markdown, and the files are the plan.
|
||||
- Tell your agent what's wrong ("the spec is missing the unauthenticated case"). It revises the artifacts.
|
||||
|
||||
## Step 4: Apply
|
||||
|
||||
Apply turns the plan into code. Start a fresh chat session, since implementation goes better on a clean context window. In your AI chat:
|
||||
|
||||
```text
|
||||
Apply the add-rate-limiting change.
|
||||
```
|
||||
|
||||
The agent reads the change folder, then works through `tasks.md`, checking off each task as it lands.
|
||||
|
||||
- **Interrupted, or out of context?** Open a new session and ask it to apply again. It resumes at the first unchecked task.
|
||||
- **Plan turned out wrong?** Fix the artifacts (either way from step 3), then continue applying.
|
||||
- **Progress** lives in the `tasks.md` checkboxes. There is no hidden state.
|
||||
|
||||
## Step 5: Archive
|
||||
|
||||
Archiving does two things: it updates your main specs with the change's requirements, and it moves the change folder into the archive folder (in `/openspec/changes/archive/*`).
|
||||
|
||||
When every box in `tasks.md` is checked, in your AI chat:
|
||||
|
||||
```text
|
||||
Archive the add-rate-limiting change.
|
||||
```
|
||||
|
||||
Step through what archiving does:
|
||||
|
||||
```file-steps
|
||||
## The finished change
|
||||
> Implementation is done. The delta spec (what this change adds) still sits inside the change folder; specs/ doesn't know about rate limiting yet.
|
||||
openspec/
|
||||
├── specs/ (no rate-limiting spec yet)
|
||||
└── changes/
|
||||
└── add-rate-limiting/
|
||||
├── proposal.md
|
||||
├── tasks.md every box checked
|
||||
└── specs/
|
||||
└── rate-limiting/
|
||||
└── spec.md the delta: ADDED requirements
|
||||
|
||||
## Requirements land in specs/
|
||||
> Each requirement in the delta lands in the main spec: added ones append, modified ones replace their old version. A new capability gets a new spec file.
|
||||
openspec/
|
||||
├── specs/
|
||||
+ │ └── rate-limiting/
|
||||
+ │ └── spec.md gains "Requirement: Rate limiting"
|
||||
└── changes/
|
||||
└── add-rate-limiting/
|
||||
└── specs/
|
||||
└── rate-limiting/
|
||||
└── spec.md the delta, source of the merge
|
||||
|
||||
## The folder moves to archive/
|
||||
> The whole change folder, delta included, moves into the archive under a date prefix. Nothing is deleted.
|
||||
openspec/
|
||||
├── specs/
|
||||
│ └── rate-limiting/
|
||||
│ └── spec.md
|
||||
└── changes/
|
||||
- └── add-rate-limiting/
|
||||
+ └── archive/
|
||||
+ └── 2026-08-08-add-rate-limiting/
|
||||
+ ├── proposal.md
|
||||
+ ├── tasks.md
|
||||
+ └── specs/rate-limiting/spec.md
|
||||
|
||||
## Specs describe the system as built
|
||||
> changes/ is clear for the next change. specs/ is the source of truth for what the system does; archive/ is the history of how it got there.
|
||||
openspec/
|
||||
├── specs/
|
||||
│ └── rate-limiting/
|
||||
│ └── spec.md the spec as built
|
||||
└── changes/
|
||||
└── archive/
|
||||
└── 2026-08-08-add-rate-limiting/
|
||||
```
|
||||
|
||||
Git is a separate concern. Commit the change folder with the code, and nothing else about your workflow changes.
|
||||
|
||||
## Going further
|
||||
|
||||
- [Delta specs](../reference/schemas/spec-driven/index.md#delta-specs-specmd): how to write the behavior changes in a delta spec.
|
||||
- [Profiles](../customize/profiles.md): optional workflows beyond the core set (verify before archive, incremental planning).
|
||||
|
||||
## Advanced guides
|
||||
|
||||
<!-- Planned pages, not yet written or in the README page map. Listed here so the quickstart routes to them once they exist. -->
|
||||
|
||||
Not written yet; guides we plan to add:
|
||||
|
||||
- **Prototype first**: spike the code before any spec, then backfill the proposal from what the prototype taught you.
|
||||
- **Building iteratively**: a sequence of small changes instead of one big proposal.
|
||||
- **Revising an implemented change**: the plan needs to move again after apply, but the change hasn't merged or archived yet.
|
||||
@@ -1,137 +0,0 @@
|
||||
# Set up your project
|
||||
|
||||
> Add OpenSpec to a project: run init, see what it wrote, and adjust it.
|
||||
|
||||
## Pick where OpenSpec lives
|
||||
|
||||
- **In your repo (the default)**: specs and changes sit next to the code they describe and are versioned with it. The rest of this page follows this path.
|
||||
- **In a store**: a separate planning repo shared by the repos that use it, for multi-repo setups or keeping planning out of the repo entirely. [Stores (beta)](../multi-repo/stores.md) covers when that's worth it and how to set one up.
|
||||
|
||||
## Initialize your project
|
||||
|
||||
With the CLI installed ([Installation](installation.md)), run init at the root of your project. In your terminal:
|
||||
|
||||
```bash
|
||||
cd <your-project>
|
||||
openspec init
|
||||
```
|
||||
|
||||
Init asks which AI tools you use, writes the workflow files for the ones you pick, and reports what you got:
|
||||
|
||||
```
|
||||
OpenSpec Setup Complete
|
||||
|
||||
Created: Claude Code
|
||||
6 skills and 6 commands in .claude/
|
||||
Config: openspec/config.yaml (schema: spec-driven)
|
||||
```
|
||||
|
||||
Restart your IDE for the new commands to take effect.
|
||||
|
||||
Re-running init is safe:
|
||||
|
||||
- Tools you already set up print `Refreshed` instead of `Created`.
|
||||
- Running init again with a new tool selected adds that tool.
|
||||
- The `--tools` flag skips the picker ([CLI reference](../reference/cli.md)).
|
||||
|
||||
## What init installs
|
||||
|
||||
Running init creates two things in your project:
|
||||
|
||||
- An `openspec/` folder at the repo root
|
||||
- Workflow files (skills and commands) added to your AI tool's folder (`.agents/`, `.claude/`, etc.)
|
||||
|
||||
Commit all of it like the rest of your source. Init changes nothing else in your repo (if it finds leftovers from an older OpenSpec version, it asks before cleaning them up).
|
||||
|
||||
### The `openspec/` folder
|
||||
|
||||
Every OpenSpec artifact lives here, at the root of your project. Here's what that looks like:
|
||||
|
||||
```
|
||||
openspec/
|
||||
├── config.yaml project settings and context for the AI
|
||||
├── specs/ your specs (empty for now)
|
||||
└── changes/ in-motion changes (empty for now)
|
||||
└── archive/ completed changes move here
|
||||
```
|
||||
|
||||
[Project config](../customize/project-config.md) covers `config.yaml`.
|
||||
|
||||
### The workflow files (skills and commands)
|
||||
|
||||
These are the OpenSpec workflows, the actions you'll use as you work. Here they are as installed skills, in the shared `.agents/` folder most tools use:
|
||||
|
||||
```
|
||||
.agents/skills/
|
||||
├── openspec-explore/ think through an idea first
|
||||
├── openspec-propose/ propose a change
|
||||
├── openspec-apply-change/ implement a change's tasks
|
||||
├── openspec-update-change/ revise a change's plan
|
||||
├── openspec-sync-specs/ sync a change's spec updates into specs/
|
||||
├── openspec-archive-change/ move a finished change to the archive
|
||||
├── openspec-verify-change/ check the implementation matches the plan (not included by default)
|
||||
└── openspec-bulk-archive-change/ archive several changes at once (not included by default)
|
||||
```
|
||||
|
||||
This is the default set plus two optional workflows. [Profiles](../customize/profiles.md) lists all twelve.
|
||||
|
||||
By default each workflow installs in two forms:
|
||||
|
||||
- **Skill** (`openspec-apply-change`): instructions your agent picks up on its own when you ask for the work.
|
||||
- **Command** (`/opsx:apply` in Claude Code): a typed entry point for the same workflow, under a shorter name.
|
||||
|
||||
The two are functionally identical. A workflow's skill and its command carry the same instructions.
|
||||
|
||||
Why two: commands came first, and every tool spells them its own way. Skills are the newer standard shared across tools, but not every tool can invoke a skill directly, so commands stay as those tools' entry point.
|
||||
|
||||
Some tools install in skill form only. Where the tool runs skills directly, init skips commands and says so (`Commands skipped for: codex (uses skills)`).
|
||||
|
||||
We prefer skills and expect to retire commands eventually.
|
||||
|
||||
#### Change what gets installed
|
||||
|
||||
The interactive picker changes the delivery form and the workflow set ([Profiles](../customize/profiles.md)). In your terminal:
|
||||
|
||||
```bash
|
||||
openspec config profile
|
||||
```
|
||||
|
||||
Here's switching to skills only:
|
||||
|
||||
```
|
||||
Current profile settings
|
||||
Delivery: both
|
||||
|
||||
? What do you want to configure? Delivery only
|
||||
? Delivery mode (how workflows are installed): Skills only
|
||||
|
||||
Config changes:
|
||||
delivery: both -> skills
|
||||
? Apply changes to this project now? (Y/n) y
|
||||
```
|
||||
|
||||
Answering yes applies it to the current project on the spot. Other projects pick it up on their next `openspec update`. The setting is global, per machine.
|
||||
|
||||
#### Claude Code doesn't show the workflows
|
||||
|
||||
Claude Code loads OpenSpec workflows from one or both of these project paths, based on your delivery setting:
|
||||
|
||||
- **Skills**: `.claude/skills/openspec-*/SKILL.md`
|
||||
- **Commands**: `.claude/commands/opsx/<id>.md`
|
||||
|
||||
If the files are missing, refresh the project. In your terminal:
|
||||
|
||||
```bash
|
||||
openspec update
|
||||
```
|
||||
|
||||
If the command files exist but `/opsx:` shows no OpenSpec commands, update Claude Code and restart it. If commands still don't load, enable skills too. In your terminal:
|
||||
|
||||
```bash
|
||||
openspec config set delivery both
|
||||
openspec update
|
||||
```
|
||||
|
||||
Restart Claude Code, then run `/openspec-propose` in its chat. If only some workflows are missing, [change your profile](../customize/profiles.md#expanding-the-set-optional-workflows).
|
||||
|
||||
Setup is done. The [Quickstart](quickstart.md) takes your first change from here.
|
||||
-115
@@ -1,115 +0,0 @@
|
||||
# OpenSpec Documentation
|
||||
|
||||
Welcome. This is the home for everything OpenSpec.
|
||||
|
||||
OpenSpec helps you and your AI coding assistant **agree on what to build before any code is written.** You describe the change, the AI drafts a short spec and a task list, you both look at the same plan, and then the work happens. No more discovering halfway through that the AI built the wrong thing.
|
||||
|
||||
If you read nothing else, read these two pages:
|
||||
|
||||
1. [Getting Started](getting-started.md): install, initialize, and ship your first change.
|
||||
2. [How Commands Work](how-commands-work.md): where you actually type `/opsx:propose` (hint: in your AI chat, not the terminal). This trips up almost everyone once.
|
||||
|
||||
That second one matters more than it looks. OpenSpec has two halves: a command line tool you run in your terminal, and slash commands you give to your AI assistant. Knowing which is which saves you the most common moment of confusion.
|
||||
|
||||
> **The best habit to build first: when you're not sure what to build, start with `/opsx:explore`.** It's a no-stakes thinking partner that reads your code, weighs options, and sharpens a fuzzy idea into a concrete plan before any code gets written. The [Explore First](explore.md) guide makes the case.
|
||||
|
||||
## Pick your path
|
||||
|
||||
**I'm brand new.** Start with [Getting Started](getting-started.md), then skim the [Core Concepts at a Glance](overview.md). When something feels mysterious, the [FAQ](faq.md) and [Glossary](glossary.md) are nearby.
|
||||
|
||||
**I have a problem but not a plan.** This is the common case, and it has a dedicated answer: [Explore First](explore.md). Use `/opsx:explore` to think it through with the AI before committing to anything.
|
||||
|
||||
**I have a big existing codebase.** You don't document all of it. [Using OpenSpec in an Existing Project](existing-projects.md) shows how to start on real, brownfield code without boiling the ocean.
|
||||
|
||||
**I just want to get it working.** [Install](installation.md), run `openspec init`, then read [How Commands Work](how-commands-work.md) so your first slash command lands in the right place. Or hand the setup to your assistant with the [AI-assisted install prompt](installation.md#install-with-your-ai-assistant).
|
||||
|
||||
**I learn by example.** The [Examples & Recipes](examples.md) page walks through real changes start to finish: a small feature, a bug fix, a refactor, an exploration.
|
||||
|
||||
**The AI just drafted a plan — now what?** Read it. [Reviewing a Change](reviewing-changes.md) shows the two-minute pass that catches a wrong turn while it's still cheap, and [Writing Good Specs](writing-specs.md) covers what a plan worth approving is made of.
|
||||
|
||||
**I work on a team.** [OpenSpec on a Team](team-workflow.md) shows how a change maps onto a branch and a pull request, and how teammates review a plan before the code.
|
||||
|
||||
**I'm coming from the old workflow.** The [Migration Guide](migration-guide.md) explains what changed and why, and promises your existing work is safe.
|
||||
|
||||
**I want to bend it to my team's process.** [Customization](customization.md) covers project config, custom schemas, and shared context.
|
||||
|
||||
**Something's broken.** [Troubleshooting](troubleshooting.md) collects the failures people actually hit, with fixes.
|
||||
|
||||
## The whole map
|
||||
|
||||
### Start here
|
||||
|
||||
| Doc | What it gives you |
|
||||
|-----|-------------------|
|
||||
| [Getting Started](getting-started.md) | Install, initialize, and run your first change end to end |
|
||||
| [Explore First](explore.md) | Use `/opsx:explore` to think through an idea before you commit |
|
||||
| [How Commands Work](how-commands-work.md) | Where slash commands run, what "interactive mode" means, terminal vs chat |
|
||||
| [Core Concepts at a Glance](overview.md) | The whole mental model on one page: specs, changes, deltas, archive |
|
||||
| [Installation](installation.md) | npm, pnpm, yarn, bun, Nix, a prompt that hands setup to your AI assistant, and how to verify it worked |
|
||||
|
||||
### Use it day to day
|
||||
|
||||
| Doc | What it gives you |
|
||||
|-----|-------------------|
|
||||
| [Workflows](workflows.md) | Common patterns and when to reach for each command |
|
||||
| [Examples & Recipes](examples.md) | Full walkthroughs of real changes, copy-pasteable |
|
||||
| [Writing Good Specs](writing-specs.md) | What a strong requirement and scenario look like, and how to right-size a change |
|
||||
| [Reviewing a Change](reviewing-changes.md) | The two-minute pass on a drafted plan before any code is written |
|
||||
| [OpenSpec on a Team](team-workflow.md) | How changes fit branches, pull requests, and review |
|
||||
| [Using OpenSpec in an Existing Project](existing-projects.md) | Adopting OpenSpec on a large brownfield codebase |
|
||||
| [Editing & Iterating on a Change](editing-changes.md) | Update artifacts, go back, reconcile manual edits |
|
||||
| [Commands](commands.md) | Reference for every `/opsx:*` slash command |
|
||||
| [CLI](cli.md) | Reference for every `openspec` terminal command |
|
||||
|
||||
### Understand it deeply
|
||||
|
||||
| Doc | What it gives you |
|
||||
|-----|-------------------|
|
||||
| [Concepts](concepts.md) | The long-form explanation of specs, changes, artifacts, schemas, and archive |
|
||||
| [OPSX Workflow](opsx.md) | Why the workflow is fluid instead of phase-locked, plus an architecture deep dive |
|
||||
| [Glossary](glossary.md) | Every term defined in one place |
|
||||
|
||||
### Make it yours
|
||||
|
||||
| Doc | What it gives you |
|
||||
|-----|-------------------|
|
||||
| [Customization](customization.md) | Project config, custom schemas, shared context |
|
||||
| [Multi-Language](multi-language.md) | Generate artifacts in languages other than English |
|
||||
| [Supported Tools](supported-tools.md) | The 30+ AI tools OpenSpec integrates with, and where files land |
|
||||
| [Community Showcase](community.md) | Projects and resources built with and for OpenSpec |
|
||||
|
||||
### When you need help
|
||||
|
||||
| Doc | What it gives you |
|
||||
|-----|-------------------|
|
||||
| [FAQ](faq.md) | Quick answers to the questions people ask most |
|
||||
| [Troubleshooting](troubleshooting.md) | Concrete fixes for concrete failures |
|
||||
| [Migration Guide](migration-guide.md) | Moving from the legacy workflow to OPSX |
|
||||
|
||||
### Coordinate across repos (beta)
|
||||
|
||||
| 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 |
|
||||
| [Agent Contract](agent-contract.md) | The machine-readable CLI surfaces agents drive |
|
||||
|
||||
## The thirty-second version
|
||||
|
||||
```text
|
||||
1. Install npm install -g @fission-ai/openspec@latest
|
||||
2. Initialize cd your-project && openspec init
|
||||
3. Explore (in your AI chat) /opsx:explore ← optional, but a great habit
|
||||
4. Propose (in your AI chat) /opsx:propose add-dark-mode
|
||||
5. Build (in your AI chat) /opsx:apply
|
||||
6. Archive (in your AI chat) /opsx:archive
|
||||
```
|
||||
|
||||
Steps 1 and 2 happen in your terminal. The rest happen in your AI assistant's chat. That split is the one thing worth memorizing, and [How Commands Work](how-commands-work.md) explains exactly why. Step 3 is optional, but starting with `/opsx:explore` when you're unsure is the habit most worth forming.
|
||||
|
||||
## Where else to get help
|
||||
|
||||
- **Discord:** [discord.gg/YctCnvvshC](https://discord.gg/YctCnvvshC) for questions, ideas, and help.
|
||||
- **GitHub Issues:** [github.com/Fission-AI/OpenSpec/issues](https://github.com/Fission-AI/OpenSpec/issues) for bugs and feature requests.
|
||||
- **`openspec feedback "your message"`** sends feedback straight from your terminal (it opens a GitHub issue).
|
||||
|
||||
Found something in these docs that's wrong, stale, or confusing? That's a bug. Open an issue or a PR. Documentation improvements are some of the most valuable contributions you can make.
|
||||
@@ -1,146 +0,0 @@
|
||||
# OpenSpec Agent Contract
|
||||
|
||||
Machine-readable surfaces of the `openspec` CLI, verified against `src/` (capstone audit, 2026-06-11). Every shape below is documented from the emitting code.
|
||||
|
||||
## 1. General conventions
|
||||
|
||||
- **One JSON document per invocation.** In `--json` mode, stdout carries exactly one JSON document (2-space pretty-printed). Human prose, spinners, and the store banner go to stderr.
|
||||
- **Store banner.** In human mode, a store-selected root prints `Using OpenSpec root: <id> (<path>)` to stderr. Never printed in JSON mode.
|
||||
- **Key casing is surface-dependent** (see Known inconsistencies): store/doctor/context payloads use `snake_case`; workflow payloads (`status`, `instructions`, `new change`, `validate`, `list`) use `camelCase`, except the embedded `root` object, which always uses `store_id`.
|
||||
- **Optional keys are omitted, not null**, in most payloads (e.g. `root.store_id`, `member.path`). Exceptions that use explicit `null` are called out per shape (store doctor `git.*`, failure payloads).
|
||||
|
||||
## 2. The diagnostic envelope
|
||||
|
||||
One envelope shape is shared by every machine-readable diagnostic (`StoreDiagnostic`):
|
||||
|
||||
```json
|
||||
{
|
||||
"severity": "error" | "warning" | "info",
|
||||
"code": "snake_case_string",
|
||||
"message": "human sentence",
|
||||
"target": "dotted.surface (optional)",
|
||||
"fix": "one actionable sentence/command (optional)"
|
||||
}
|
||||
```
|
||||
|
||||
Diagnostics appear in two positions: **status arrays** (`status: StoreDiagnostic[]` at top level or per entry) for health findings, and **thrown errors** converted to a single-element `status` array on command failure.
|
||||
|
||||
## 3. Root selection and `RootOutput`
|
||||
|
||||
All root-resolving commands (`list`, `show`, `validate`, `status`, `instructions`, `instructions apply`, `instructions archive`, `new change`, `archive`, `doctor`, `context`, `schemas`) resolve one OpenSpec root with one precedence:
|
||||
|
||||
1. `--store <id>` → the registered store's root (`source: "store"`).
|
||||
2. Otherwise, nearest ancestor with `openspec/`: planning shape → `source: "nearest"` (a `store:` pointer is ignored with a stderr warning); config-only dir with a valid `store:` pointer → that store, `source: "declared"`.
|
||||
3. No nearest root + global `defaultStore` set (`openspec config set defaultStore <id>`) → that store, `source: "global_default"`; a stale id fails with the underlying store error and a `fix` naming `openspec config unset defaultStore`.
|
||||
4. No nearest root, no default + registered stores exist → error `no_root_with_registered_stores`.
|
||||
5. No root, no default, no stores: commands may treat the cwd as `source: "implicit"`; `doctor`, `context`, `list`, and bulk `validate` instead fail with `no_openspec_root`. `list` preserves the implicit fallback for legacy projects with `openspec/project.md`.
|
||||
|
||||
Successful JSON payloads normally embed the root; successful `schemas --json`
|
||||
deliberately remains the compatibility bare array documented in §4.13:
|
||||
|
||||
```json
|
||||
"root": { "path": "/abs/path", "source": "store" | "declared" | "global_default" | "nearest" | "implicit", "store_id": "id (only when store-selected)" }
|
||||
```
|
||||
|
||||
**Root-failure contract**: in JSON mode a resolution failure prints `{ ...commandNullShape, "status": [diagnostic] }` on stdout and exits 1.
|
||||
|
||||
## 4. Command JSON shapes
|
||||
|
||||
### 4.1 `list --json`
|
||||
`{ "changes": [ { "name", "completedTasks", "totalTasks", "lastModified", "status": "no-tasks"|"complete"|"in-progress", "nested"?: ["<area>/<name>", ...] } ], "warnings"?: [ { "code", "name", "nested", "message" } ], "root": RootOutput }` — note the per-change `status` is a string enum here. `--specs`: `{ "specs": [ { "id", "requirementCount" } ], "root" }`.
|
||||
|
||||
`warnings` (omitted when empty) reports directories under `changes/` that are not changes. Today the only code is `nested_change_directory`: a namespace folder wrapping change directories, which OpenSpec cannot address because a change is always a directory directly under `changes/`. The same entry carries `nested` on the listed change, whose `status` is then meaningless. Do not treat such an entry as a change; report the message and leave the directories alone.
|
||||
|
||||
### 4.2 `show <item> --json`
|
||||
Change: `{ "id", "title", "deltaCount", "deltas": [...], "root" }`. Spec: `{ "id", "title", "overview", "requirementCount", "requirements": [...], "metadata": { "version", "format", "sourcePath"? }, "root" }`.
|
||||
|
||||
### 4.3 `validate --json`
|
||||
`{ "items": [ { "id", "type": "change"|"spec", "valid", "issues": [ { "level", "path", "message", "line"?, "column"? } ], "durationMs" } ], "summary": { "totals": {items,passed,failed}, "byType": {...} }, "version": "1.0", "root" }`. Exit 1 when any item fails.
|
||||
|
||||
### 4.4 `status --json`
|
||||
`{ "changeName", "schemaName", "planningHome"?: { "kind", "root", "changesDir", "defaultSchema" }, "changeRoot", "artifactPaths": { "<id>": {outputPath, resolvedOutputPath, existingOutputPaths} }, "nextSteps": ["..."], "actionContext": { "mode": "repo-local", "sourceOfTruth": "repo", "planningArtifacts", "linkedContext", "allowedEditRoots", "requiresAffectedAreaSelection", "constraints" }, "isPlanningComplete", "isComplete", "applyRequires", "artifacts": [ {id, outputPath, status: "done"|"skipped"|"ready"|"blocked", requires, missingDeps?} ], "root" }`. `isPlanningComplete` means every non-skipped planning artifact exists; skipped artifacts count as satisfied without being created. It does not mean implementation tasks are complete. `isComplete` is retained as a compatibility alias with the same value. Each artifact's `requires` is its direct dependency ids (present for every status, so the transitive required set is computable even when the artifact is `done`); `missingDeps` appears only when `blocked`. The `artifacts` array is in dependency order, with the schema's `artifacts:` declaration order breaking ties between artifacts that become ready at the same time (never alphabetical), so the first `ready` entry is the artifact to write next; `missingDeps` uses that same order. `"skipped"` marks an artifact whose `generates` path is under `specs/` in a change whose `.openspec.yaml` declares `skip_specs: true`; it satisfies dependencies but must not be created. No active changes: `{ "changes": [], "message", "root" }`, exit 0.
|
||||
|
||||
`--all` (batch, mutually exclusive with `--change` — combining them is an error with the `{ "changes": [], "root": null, "status": [d] }` null-shape): `{ "changes": [ <per-change status object, no per-change root>, ... ], "root" }`, sorted by change name. A change that fails to load contributes `{ "changeName", "status": [d] }` in place; the sweep continues, preserves the complete envelope, and exits 1 in both text and JSON modes. An invalid `--schema` fails the whole invocation with the null-shape, even when no changes exist.
|
||||
|
||||
### 4.5 `instructions <artifact> --json`
|
||||
`{ "changeName", "artifactId", "schemaName", "changeDir", "planningHome"?, "outputPath", "resolvedOutputPath", "existingOutputPaths", "description", "instruction"?, "context"?, "rules"?, "references"?: ReferenceIndexEntry[], "skipped"?, "warning"?, "template", "dependencies": [{id,done,path,description,skipped?}], "unlocks", "root" }`. `unlocks` lists the artifacts this one makes ready, in the schema's declaration order (the same order `status` recommends them). `"skipped": true` (with `"warning"`) appears when the change declares `skip_specs: true` and this artifact is skipped — do not create its files. A dependency entry with `skipped: true` is satisfied without files — do not try to read its paths.
|
||||
|
||||
`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`).
|
||||
|
||||
### 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"?, "missingPrerequisites"?, "warnings"?, "instruction", "references"?, "context"?, "operationGuidance"?, "root" }`. `missingArtifacts` is what apply blocks on (the schema's `apply.requires`); `missingPrerequisites` is everything still to build before apply can run, in build order - the transitive closure of those requires, so it can be the longer list. `warnings` lists non-blocking problems with the change itself - today, a change that is ready to implement with no delta specs and no `skip_specs: true`, the state `openspec validate` rejects. Both optional root fields (`context`, `operationGuidance`) are read from the selected root on every invocation. `context` is a required prompt-level input whose relevant project facts, conventions, and constraints must be applied; `operationGuidance` is advisory input whose entries are followed only when applicable and compatible with the built-in workflow. Both remain separate from state, tasks, progress, context files, and the built-in instruction.
|
||||
|
||||
### 4.7 `instructions archive --json`
|
||||
`{ "changeName", "context"?, "operationGuidance"?, "root" }`. Requires a valid `--change` in the resolved repo/store root and uses the same required-context/advisory-guidance semantics as apply. This is a read-only runtime-input surface: it does not return the static archive workflow, inspect or merge delta specs, write main specs, or move the change.
|
||||
|
||||
### 4.8 `new change <name> --json`
|
||||
Success: `{ "change": { "id", "path", "metadataPath", "schema" }, "root" }`. Failure: `{ "change": null, "status": [d] }`, exit 1.
|
||||
|
||||
### 4.9 `archive <name> --json`
|
||||
Success: `{ "archive": { "change", "archivedAs": "YYYY-MM-DD-name", "path", "specsUpdated", "totals"?, "warnings"? }, "root" }`. Failure: `{ "archive": null, "root"?, "status": [d] }`, exit 1. `specsUpdated` is true only when at least one spec file was written or retired (a capability whose last requirement the change removed has its spec deleted, which requires `retire_capabilities: true` in the change's `.openspec.yaml`; every retirement is named in `warnings`, with a pasteable Git recovery command only when the spec lived in the caller's checkout); an already-synced change archives with all-zero totals and the skips listed in `warnings`. JSON mode is strictly non-interactive: every prompt point becomes an `archive_*` code.
|
||||
|
||||
### 4.10 `doctor --json`
|
||||
`{ "root": { "path", "source", "store_id"?, "healthy", "status": [] }, "store": { "id", "metadata": {present,valid,remote?}, "origin_url"?, "drift"?: {ahead,behind}, "status": [] } | null, "references": [...], "status": [] }`. `drift` (present only for a git-backed store checkout that has an upstream tracking ref) is ahead/behind counts against the last-fetched upstream, not the live remote. Health findings of any severity exit 0. Failure payload: `{ "root": null, "store": null, "references": [], "status": [d] }`, exit 1.
|
||||
|
||||
### 4.11 `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.
|
||||
|
||||
### 4.12 `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.13 `schemas --json` / `templates --json`
|
||||
`schemas`: success remains a bare array `[ {name, description, artifacts, source} ]`; it resolves the canonical root-selection precedence and accepts `--store <id>`. Root-selection failure: `{ "schemas": [], "root": null, "status": [d] }`, exit 1. `templates`: keyed object `{ "<artifactId>": {path, source} }`, still cwd-based with no root/status keys.
|
||||
|
||||
## 5. Exit-code contract
|
||||
|
||||
| Situation | Exit | Stdout |
|
||||
|---|---|---|
|
||||
| Success, incl. health findings (doctor/context/store doctor) | 0 | the payload |
|
||||
| Command failure in `--json` mode | 1 | one JSON document with `status: [d]` and the command's null-shape |
|
||||
| `validate` with failing items | 1 | full report |
|
||||
| Prompt cancellation (`store` group, human mode) | 130 | stderr only |
|
||||
|
||||
## 6. Diagnostic code catalog
|
||||
|
||||
### Resolution
|
||||
`no_openspec_root`, `no_root_with_registered_stores`, `no_registered_stores`, `unknown_store`, `store_identity_mismatch`, `unhealthy_store_root`, `store_path_not_supported`, `invalid_store_pointer`, `initiative_option_removed`, `areas_option_removed`; pass-through: `invalid_store_id`, `invalid_store_registry`, `invalid_store_metadata`.
|
||||
|
||||
### OpenSpec-root health (error, no fix)
|
||||
`openspec_store_root_missing`, `openspec_store_root_not_directory`, `openspec_root_missing`, `openspec_root_not_directory`, `openspec_config_missing`, `openspec_config_not_file`, `openspec_specs_not_directory`, `openspec_changes_not_directory`, `openspec_archive_not_directory`. During the stores beta, `openspec/specs/`, `openspec/changes/`, and `openspec/changes/archive/` may be absent in a healthy root; they are only health errors when present but not directories.
|
||||
|
||||
### Store registry/identity/state
|
||||
`invalid_store_id`, `invalid_store_registry`, `invalid_store_metadata`, `store_registry_busy`, `store_not_found`, `no_store_registry`, `store_registry_changed`, `store_metadata_missing`, `store_metadata_id_mismatch`, `store_metadata_invalid`, `store_id_conflict`, `store_path_conflict`, `store_already_registered` (info).
|
||||
|
||||
### Store setup/register/remove
|
||||
`store_setup_id_required`, `store_setup_path_required`, `store_setup_path_not_directory`, `store_setup_inside_git_repo`, `store_setup_non_empty_directory`, `store_setup_cancelled`, `store_path_required`, `store_path_missing`, `store_path_not_directory`, `store_root_pointer_declared`, `store_register_root_unhealthy`, `store_register_identity_confirmation_required`, `store_register_cancelled`, `store_remote_empty`, `store_remote_requires_hand_edit`, `store_remove_confirmation_required`, `store_remove_cancelled`, `store_remove_path_not_directory`, `store_remove_metadata_missing`, `store_remove_contains_registered_store`, `store_root_missing` (warning in remove, error in doctor), `store_root_not_directory`.
|
||||
|
||||
### Store git
|
||||
`store_git_init_failed`, `store_git_identity_missing`, `store_git_commit_failed`, `store_git_no_commits` (warning), `store_clone_fragile_directories` (warning), `store_remote_divergence` (info, doctor), `store_checkout_drift` (info, doctor).
|
||||
|
||||
### References (warning)
|
||||
`reference_invalid_id`, `reference_registry_unreadable`, `reference_unresolved`, `reference_root_unhealthy`, `reference_index_truncated`.
|
||||
|
||||
### Relationships (warning; doctor; context keeps only the registry one)
|
||||
`relationship_registry_unreadable`, `root_pointer_ignored`, `root_pointer_invalid`, `pointer_declarations_inert`.
|
||||
|
||||
### Archive (JSON mode)
|
||||
`archive_change_name_required`, `archive_change_not_found`, `archive_change_symlink`, `archive_validation_failed`, `archive_confirmation_required`, `archive_tasks_incomplete`, `archive_spec_update_failed`, `archive_spec_validation_failed`, `archive_target_exists`, `archive_error`.
|
||||
|
||||
### Context writes
|
||||
`context_file_exists`, `context_output_dir_missing`.
|
||||
|
||||
### Fallbacks
|
||||
`doctor_failed`, `context_failed`, `store_error`, `change_error`, `archive_error`.
|
||||
|
||||
## Known inconsistencies
|
||||
|
||||
Recorded by the capstone audit; published-key renames are product decisions deferred past this release:
|
||||
|
||||
1. ~~In `--json` mode, several failure paths printed stderr only with no JSON document.~~ Fixed in the capstone gauntlet round: `show`/`validate` unknown and ambiguous items emit `{status:[{code: unknown_item | ambiguous_item, ...}]}`; thrown errors in `status`/`instructions`/`list`/`show`/`validate` route through the JSON-aware failure helper (the command's null-shape + `status`); `store <unknown subcommand> --json` emits `{status:[{code: unknown_store_subcommand}]}`; `list` carries its `{changes|specs: [], root: null}` null-shape on resolution failures.
|
||||
2. `store_root_missing` is emitted with two severities (warning in remove, error in store doctor) — context-dependent, documented above.
|
||||
3. snake_case (store family) vs camelCase (workflow family) key casing; `root.store_id` is snake_case everywhere.
|
||||
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. `templates` ignores root selection (cwd-based, no `--store`).
|
||||
8. Deprecated noun forms (`change`/`spec` subcommands) emit unenveloped payloads without `root`/`status`.
|
||||
-1342
File diff suppressed because it is too large
Load Diff
@@ -1,779 +0,0 @@
|
||||
# Commands
|
||||
|
||||
This is the reference for OpenSpec's slash commands. These commands are invoked in your AI coding assistant's chat interface (e.g., Claude Code, Cursor, Devin Desktop).
|
||||
|
||||
For workflow patterns and when to use each command, see [Workflows](workflows.md). For CLI commands, see [CLI](cli.md).
|
||||
|
||||
These pages use `/opsx:<command>` as the canonical name. Some tools spell it
|
||||
differently — Cursor and GitHub Copilot register `/opsx-propose`, Codex uses
|
||||
`$openspec-propose` — so check [How To Invoke](supported-tools.md#how-to-invoke)
|
||||
for your tool. The files OpenSpec generates already use the right form.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Default Quick Path (`core` profile)
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `/opsx:propose` | Create a change and generate planning artifacts in one step |
|
||||
| `/opsx:explore` | Think through ideas before committing to a change |
|
||||
| `/opsx:apply` | Implement tasks from the change |
|
||||
| `/opsx:update` | Revise a change's planning artifacts and keep them coherent |
|
||||
| `/opsx:sync` | Merge delta specs into main specs |
|
||||
| `/opsx:archive` | Archive a completed change |
|
||||
|
||||
### Expanded Workflow Commands (custom workflow selection)
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `/opsx:new` | Start a new change scaffold |
|
||||
| `/opsx:continue` | Create the next artifact based on dependencies |
|
||||
| `/opsx:ff` | Fast-forward: create all planning artifacts at once |
|
||||
| `/opsx:verify` | Validate implementation matches artifacts |
|
||||
| `/opsx:bulk-archive` | Archive multiple changes at once |
|
||||
| `/opsx:onboard` | Guided tutorial through the complete workflow |
|
||||
|
||||
The default global profile is `core`. To enable expanded workflow commands, run `openspec config profile`, select workflows, then run `openspec update` in your project.
|
||||
|
||||
---
|
||||
|
||||
## Command Reference
|
||||
|
||||
### `/opsx:propose`
|
||||
|
||||
Create a new change and generate planning artifacts in one step. This is the default start command in the `core` profile.
|
||||
|
||||
**Syntax:**
|
||||
```text
|
||||
/opsx:propose [change-name-or-description]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
| Argument | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `change-name-or-description` | No | Kebab-case name or plain-language change description |
|
||||
|
||||
**What it does:**
|
||||
- Creates `openspec/changes/<change-name>/`
|
||||
- Generates artifacts needed before implementation (for `spec-driven`: proposal, specs, design, tasks)
|
||||
- Stops when the change is ready for `/opsx:apply`
|
||||
|
||||
**Example:**
|
||||
```text
|
||||
You: /opsx:propose add-dark-mode
|
||||
|
||||
AI: Created openspec/changes/add-dark-mode/
|
||||
✓ proposal.md
|
||||
✓ specs/ui/spec.md
|
||||
✓ design.md
|
||||
✓ tasks.md
|
||||
Ready for implementation. Run /opsx:apply.
|
||||
```
|
||||
|
||||
**Tips:**
|
||||
- Use this for the fastest end-to-end path
|
||||
- If you want step-by-step artifact control, enable expanded workflows and use `/opsx:new` + `/opsx:continue`
|
||||
|
||||
---
|
||||
|
||||
### `/opsx:explore`
|
||||
|
||||
> **Start here when you're unsure.** Explore is a no-stakes thinking partner: it reads your codebase, compares options, and sharpens a fuzzy idea into a concrete plan before any code gets written. It ships in the default profile. For the full case and more examples, see the [Explore First](explore.md) guide.
|
||||
|
||||
Think through ideas, investigate problems, and clarify requirements before committing to a change.
|
||||
|
||||
**Syntax:**
|
||||
```
|
||||
/opsx:explore [topic]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
| Argument | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `topic` | No | What you want to explore or investigate |
|
||||
|
||||
**What it does:**
|
||||
- Opens an exploratory conversation with no structure required
|
||||
- Investigates the codebase to answer questions
|
||||
- Compares options and approaches
|
||||
- Creates visual diagrams to clarify thinking
|
||||
- Captures the exploration when you ask, or when you say yes to its offer: scaffolds a change with `openspec new change` and writes the planning artifacts you name, or updates an existing change's artifacts
|
||||
- Can transition to `/opsx:propose` (default) or `/opsx:new` (expanded workflow) when insights crystallize
|
||||
|
||||
**Example:**
|
||||
```text
|
||||
You: /opsx:explore
|
||||
|
||||
AI: What would you like to explore?
|
||||
|
||||
You: How should we handle authentication for the mobile app?
|
||||
|
||||
AI: Let me investigate your current auth setup...
|
||||
[Analyzes codebase]
|
||||
|
||||
I see you're using session-based auth for the web app.
|
||||
For mobile, we have three main options:
|
||||
|
||||
1. JWT tokens (stateless, works offline)
|
||||
2. OAuth2 (if you need third-party login)
|
||||
3. Extend current sessions (simpler, but requires connectivity)
|
||||
|
||||
Your API already has CORS configured. Which direction interests you?
|
||||
|
||||
You: Let's go with JWT.
|
||||
|
||||
AI: That's a decision worth keeping. Want me to start a change called
|
||||
add-jwt-auth? Just the change folder, nothing else yet.
|
||||
|
||||
You: Yes.
|
||||
|
||||
AI: Started openspec/changes/add-jwt-auth/. Say the word and I'll
|
||||
write the proposal, specs, and tasks from what we just worked out.
|
||||
```
|
||||
|
||||
**Tips:**
|
||||
- Use when requirements are unclear or you need to investigate
|
||||
- It never writes code, and writes nothing else unless you ask, or say yes when it offers
|
||||
- Good for comparing multiple approaches before deciding
|
||||
- Can read files and search the codebase
|
||||
|
||||
---
|
||||
|
||||
### `/opsx:new`
|
||||
|
||||
Start a new change scaffold. Creates the change folder and waits for you to generate artifacts with `/opsx:continue` or `/opsx:ff`.
|
||||
|
||||
This command is part of the expanded workflow set (not included in the default `core` profile).
|
||||
|
||||
**Syntax:**
|
||||
```
|
||||
/opsx:new [change-name] [--schema <schema-name>]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
| Argument | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `change-name` | No | Name for the change folder (prompted if not provided) |
|
||||
| `--schema` | No | Workflow schema to use (default: from config or `spec-driven`) |
|
||||
|
||||
**What it does:**
|
||||
- Creates `openspec/changes/<change-name>/` directory
|
||||
- Creates `.openspec.yaml` metadata file in the change folder
|
||||
- Shows the first artifact template ready for creation
|
||||
- Prompts for change name and schema if not provided
|
||||
|
||||
**What it creates:**
|
||||
```
|
||||
openspec/changes/<change-name>/
|
||||
└── .openspec.yaml # Change metadata (schema, created date)
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```
|
||||
You: /opsx:new add-dark-mode
|
||||
|
||||
AI: Created openspec/changes/add-dark-mode/
|
||||
Schema: spec-driven
|
||||
|
||||
Ready to create: proposal
|
||||
Use /opsx:continue to create it, or /opsx:ff to create all artifacts.
|
||||
```
|
||||
|
||||
**Tips:**
|
||||
- Use descriptive names: `add-feature`, `fix-bug`, `refactor-module`
|
||||
- Avoid generic names like `update`, `changes`, `wip`
|
||||
- Schema can also be set in project config (`openspec/config.yaml`)
|
||||
|
||||
---
|
||||
|
||||
### `/opsx:continue`
|
||||
|
||||
Create the next artifact in the dependency chain. Creates one artifact at a time for incremental progress.
|
||||
|
||||
**Syntax:**
|
||||
```
|
||||
/opsx:continue [change-name]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
| Argument | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `change-name` | No | Which change to continue (inferred from context if not provided) |
|
||||
|
||||
**What it does:**
|
||||
- Queries the artifact dependency graph
|
||||
- Shows which artifacts are ready vs blocked
|
||||
- Creates the first ready artifact
|
||||
- Reads dependency files for context
|
||||
- Shows what becomes available after creation
|
||||
|
||||
**Example:**
|
||||
```
|
||||
You: /opsx:continue
|
||||
|
||||
AI: Change: add-dark-mode
|
||||
|
||||
Artifact status:
|
||||
✓ proposal (done)
|
||||
◆ specs (ready)
|
||||
◆ design (ready)
|
||||
○ tasks (blocked - needs: specs, design)
|
||||
|
||||
Creating specs...
|
||||
|
||||
[Reads proposal.md, creates specs based on requirements]
|
||||
|
||||
✓ Created openspec/changes/add-dark-mode/specs/ui/spec.md
|
||||
|
||||
Now available: design
|
||||
Run /opsx:continue to create the next artifact.
|
||||
```
|
||||
|
||||
**Tips:**
|
||||
- Use when you want to review each artifact before proceeding
|
||||
- Good for complex changes where you want control
|
||||
- Multiple artifacts may become ready simultaneously
|
||||
- You can edit created artifacts before continuing
|
||||
|
||||
---
|
||||
|
||||
### `/opsx:ff`
|
||||
|
||||
Fast-forward through artifact creation. Creates all planning artifacts at once.
|
||||
|
||||
**Syntax:**
|
||||
```
|
||||
/opsx:ff [change-name]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
| Argument | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `change-name` | No | Which change to fast-forward (inferred from context if not provided) |
|
||||
|
||||
**What it does:**
|
||||
- Creates all artifacts in dependency order
|
||||
- Tracks progress via todo list
|
||||
- Stops when all `apply-required` artifacts are complete
|
||||
- Reads each dependency before creating the next artifact
|
||||
|
||||
**Example:**
|
||||
```
|
||||
You: /opsx:ff add-dark-mode
|
||||
|
||||
AI: Fast-forwarding add-dark-mode...
|
||||
|
||||
✓ Creating proposal.md
|
||||
✓ Creating specs/ui/spec.md
|
||||
✓ Creating design.md
|
||||
✓ Creating tasks.md
|
||||
|
||||
All planning artifacts complete!
|
||||
Ready for implementation. Run /opsx:apply to begin.
|
||||
```
|
||||
|
||||
**Tips:**
|
||||
- Use when you have a clear picture of what you're building
|
||||
- Faster than `/opsx:continue` for straightforward changes
|
||||
- You can still edit artifacts afterward
|
||||
- Good for small to medium features
|
||||
|
||||
---
|
||||
|
||||
### `/opsx:apply`
|
||||
|
||||
Implement tasks from the change. Works through the task list, writing code and checking off items.
|
||||
|
||||
**Syntax:**
|
||||
```
|
||||
/opsx:apply [change-name]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
| Argument | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `change-name` | No | Which change to implement (inferred from context if not provided) |
|
||||
|
||||
**What it does:**
|
||||
- Reads `tasks.md` and identifies incomplete tasks
|
||||
- Works through tasks one by one
|
||||
- Writes code, creates files, runs tests as needed
|
||||
- Marks tasks complete with checkboxes `[x]`
|
||||
|
||||
**Example:**
|
||||
```
|
||||
You: /opsx:apply
|
||||
|
||||
AI: Implementing add-dark-mode...
|
||||
|
||||
Reading tasks.md:
|
||||
- [ ] 1.1 Create ThemeContext
|
||||
- [ ] 1.2 Add CSS custom properties
|
||||
- [ ] 1.3 Implement localStorage persistence
|
||||
|
||||
Working on 1.1: Create ThemeContext...
|
||||
[Creates src/context/ThemeContext.tsx]
|
||||
|
||||
✓ 1.1 Complete
|
||||
|
||||
Working on 1.2: Add CSS custom properties...
|
||||
[Updates src/styles/globals.css]
|
||||
|
||||
✓ 1.2 Complete
|
||||
...
|
||||
```
|
||||
|
||||
**Tips:**
|
||||
- Can resume where you left off if interrupted
|
||||
- Use for parallel changes by specifying the change name
|
||||
- Completion state is tracked in `tasks.md` checkboxes
|
||||
|
||||
---
|
||||
|
||||
### `/opsx:update`
|
||||
|
||||
Revise a change's existing planning artifacts and keep them coherent with one another. Planning artifacts only - it never edits code.
|
||||
|
||||
**Syntax:**
|
||||
|
||||
```text
|
||||
/opsx:update [change-name]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
|
||||
| Argument | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `change-name` | No | Which change to update (inferred from context if not provided) |
|
||||
|
||||
**What it does:**
|
||||
|
||||
- Reads the change's artifacts via `openspec status --change <name> --json`
|
||||
- Applies your requested revision, or reviews the artifacts for contradictions if you didn't name one
|
||||
- Reconciles the other existing artifacts in any direction (a design edit may ripple back to the proposal)
|
||||
- Confirms every edit with you before writing, one artifact at a time
|
||||
- Ends by recommending the next step: `/opsx:continue` (unstarted artifacts), `/opsx:apply` (carry a revised plan into code), or `/opsx:archive` (all done)
|
||||
|
||||
**Missing files:**
|
||||
|
||||
- For a glob artifact such as `specs/**/*.md` with at least one existing file, update can propose a missing companion file. It uses the schema's instructions and asks you to confirm the concrete path before creating it.
|
||||
- Artifacts with no files yet remain with `/opsx:continue`. Intentionally skipped artifacts stay untouched.
|
||||
- New files must stay inside the change directory. If a file appears at the confirmed path before creation, update stops instead of overwriting it.
|
||||
|
||||
**Example:**
|
||||
|
||||
```text
|
||||
You: /opsx:update add-dark-mode - we're storing the theme in a cookie now, not localStorage
|
||||
|
||||
AI: Reading add-dark-mode artifacts...
|
||||
|
||||
The design references localStorage in two places; tasks 1.3 covers
|
||||
localStorage persistence; the proposal doesn't mention storage.
|
||||
|
||||
Proposed revisions:
|
||||
1. design.md - swap localStorage decision for cookie storage
|
||||
2. tasks.md - reword task 1.3 to cookie persistence
|
||||
|
||||
Apply revision 1? (design.md)
|
||||
```
|
||||
|
||||
**Tips:**
|
||||
|
||||
- It won't start an artifact with no existing files. Enable `/opsx:continue` for that, or use `openspec status` and `openspec instructions` if that optional workflow isn't installed.
|
||||
- If the change was already implemented, follow up with `/opsx:apply` so the code matches the revised plan
|
||||
- If your revision changes the *intent* of the change, start fresh with a new change instead (see [When to Update vs. Start Fresh](opsx.md#when-to-update-vs-start-fresh))
|
||||
|
||||
---
|
||||
|
||||
### `/opsx:verify`
|
||||
|
||||
Validate that implementation matches your change artifacts. Checks completeness, correctness, and coherence.
|
||||
|
||||
**Syntax:**
|
||||
```
|
||||
/opsx:verify [change-name]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
| Argument | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `change-name` | No | Which change to verify (inferred from context if not provided) |
|
||||
|
||||
**What it does:**
|
||||
- Checks three dimensions of implementation quality
|
||||
- Searches codebase for implementation evidence
|
||||
- Reports issues categorized as CRITICAL, WARNING, or SUGGESTION
|
||||
- Does not block archive, but surfaces issues
|
||||
|
||||
**Verification dimensions:**
|
||||
|
||||
| Dimension | What it validates |
|
||||
|-----------|-------------------|
|
||||
| **Completeness** | All tasks done, all requirements implemented, scenarios covered |
|
||||
| **Correctness** | Implementation matches spec intent, edge cases handled |
|
||||
| **Coherence** | Design decisions reflected in code, patterns consistent |
|
||||
|
||||
**Example:**
|
||||
```
|
||||
You: /opsx:verify
|
||||
|
||||
AI: Verifying add-dark-mode...
|
||||
|
||||
COMPLETENESS
|
||||
✓ All 8 tasks in tasks.md are checked
|
||||
✓ All requirements in specs have corresponding code
|
||||
⚠ Scenario "System preference detection" has no test coverage
|
||||
|
||||
CORRECTNESS
|
||||
✓ Implementation matches spec intent
|
||||
✓ Edge cases from scenarios are handled
|
||||
✓ Error states match spec definitions
|
||||
|
||||
COHERENCE
|
||||
✓ Design decisions reflected in code structure
|
||||
✓ Naming conventions consistent with design.md
|
||||
⚠ Design mentions "CSS variables" but implementation uses Tailwind classes
|
||||
|
||||
SUMMARY
|
||||
─────────────────────────────
|
||||
Critical issues: 0
|
||||
Warnings: 2
|
||||
Ready to archive: Yes (with warnings)
|
||||
|
||||
Recommendations:
|
||||
1. Add test for system preference detection
|
||||
2. Update design.md to reflect Tailwind usage, or refactor to use CSS variables
|
||||
```
|
||||
|
||||
**Tips:**
|
||||
- Run before archiving to catch mismatches early
|
||||
- Warnings don't block archive but indicate potential issues
|
||||
- Good for reviewing AI's work before committing
|
||||
- Can reveal drift between artifacts and implementation
|
||||
|
||||
---
|
||||
|
||||
### `/opsx:sync`
|
||||
|
||||
**Optional command.** Merge delta specs from a change into main specs. Archive will prompt to sync if needed, so you typically don't need to run this manually.
|
||||
|
||||
**Syntax:**
|
||||
```
|
||||
/opsx:sync [change-name]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
| Argument | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `change-name` | No | Which change to sync (inferred from context if not provided) |
|
||||
|
||||
**What it does:**
|
||||
- Reads delta specs from change folder
|
||||
- Parses ADDED/MODIFIED/REMOVED/RENAMED sections
|
||||
- Merges changes into main `openspec/specs/` directory
|
||||
- Preserves existing content not mentioned in delta
|
||||
- Does not archive the change (remains active)
|
||||
|
||||
**Example:**
|
||||
```text
|
||||
You: /opsx:sync
|
||||
|
||||
AI: Syncing add-dark-mode delta specs...
|
||||
|
||||
Reading: openspec/changes/add-dark-mode/specs/ui/spec.md
|
||||
Target: openspec/specs/ui/spec.md
|
||||
|
||||
Changes to apply:
|
||||
✓ ADDED: Theme Selection requirement (2 scenarios)
|
||||
✓ ADDED: Accessibility requirement (1 scenario)
|
||||
|
||||
Merging...
|
||||
✓ openspec/specs/ui/spec.md updated
|
||||
|
||||
Change remains active. Run /opsx:archive when ready to complete.
|
||||
```
|
||||
|
||||
**When to use manually:**
|
||||
|
||||
| Scenario | Use sync? |
|
||||
|----------|-----------|
|
||||
| Long-running change, want specs in main before archiving | Yes |
|
||||
| Multiple parallel changes need the updated base specs | Yes |
|
||||
| Want to preview/review the merge separately | Yes |
|
||||
| Quick change, going straight to archive | No (archive handles it) |
|
||||
|
||||
**Tips:**
|
||||
- Sync is intelligent, not copy-paste
|
||||
- Can add scenarios to existing requirements without duplicating
|
||||
- Change stays active after sync (not archived)
|
||||
- Most users will never need to call this directly—archive prompts if needed
|
||||
|
||||
---
|
||||
|
||||
### `/opsx:archive`
|
||||
|
||||
Archive a completed change. Finalizes the change and moves it to the archive folder.
|
||||
|
||||
**Syntax:**
|
||||
```
|
||||
/opsx:archive [change-name]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
| Argument | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `change-name` | No | Which change to archive (inferred from context if not provided) |
|
||||
|
||||
**What it does:**
|
||||
- Checks artifact completion status
|
||||
- Checks task completion (warns if incomplete)
|
||||
- Offers to sync delta specs if not already synced
|
||||
- Moves change folder to `openspec/changes/archive/YYYY-MM-DD-<name>/`
|
||||
- Preserves all artifacts for audit trail
|
||||
|
||||
**Example:**
|
||||
```text
|
||||
You: /opsx:archive
|
||||
|
||||
AI: Archiving add-dark-mode...
|
||||
|
||||
Artifact status:
|
||||
✓ proposal.md exists
|
||||
✓ specs/ exists
|
||||
✓ design.md exists
|
||||
✓ tasks.md exists (8/8 tasks complete)
|
||||
|
||||
Delta specs: Not yet synced
|
||||
→ Sync now? (recommended)
|
||||
|
||||
You: Yes
|
||||
|
||||
AI: ✓ Synced specs to openspec/specs/ui/spec.md
|
||||
✓ Moved to openspec/changes/archive/2025-01-24-add-dark-mode/
|
||||
|
||||
Change archived successfully.
|
||||
```
|
||||
|
||||
**Tips:**
|
||||
- Archive won't block on incomplete tasks, but will warn
|
||||
- Delta specs can be synced during archive or beforehand
|
||||
- Archived changes are preserved for history
|
||||
- Use `/opsx:verify` first to catch issues
|
||||
|
||||
---
|
||||
|
||||
### `/opsx:bulk-archive`
|
||||
|
||||
Archive multiple completed changes at once. Handles spec conflicts between changes.
|
||||
|
||||
**Syntax:**
|
||||
```
|
||||
/opsx:bulk-archive [change-names...]
|
||||
```
|
||||
|
||||
**Arguments:**
|
||||
| Argument | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `change-names` | No | Specific changes to archive (prompts to select if not provided) |
|
||||
|
||||
**What it does:**
|
||||
- Lists all completed changes
|
||||
- Validates each change before archiving
|
||||
- Detects spec conflicts across changes
|
||||
- Resolves conflicts by checking what's actually implemented
|
||||
- Archives in chronological order
|
||||
|
||||
**Example:**
|
||||
```
|
||||
You: /opsx:bulk-archive
|
||||
|
||||
AI: Found 3 completed changes:
|
||||
- add-dark-mode (8/8 tasks complete)
|
||||
- fix-login-bug (3/3 tasks complete)
|
||||
- update-footer (2/2 tasks complete)
|
||||
|
||||
Checking for spec conflicts...
|
||||
⚠ add-dark-mode and update-footer both touch specs/ui/
|
||||
|
||||
Inspecting codebase to resolve...
|
||||
Both changes are implemented. Will merge in chronological order:
|
||||
1. add-dark-mode (created Jan 20)
|
||||
2. update-footer (created Jan 22)
|
||||
|
||||
Archive all 3 changes?
|
||||
|
||||
You: Yes
|
||||
|
||||
AI: ✓ Archived add-dark-mode
|
||||
✓ Archived fix-login-bug
|
||||
✓ Archived update-footer
|
||||
Specs merged: add-dark-mode → update-footer
|
||||
```
|
||||
|
||||
**Tips:**
|
||||
- Good for parallel work streams
|
||||
- Conflict resolution is agentic (checks codebase)
|
||||
- Changes are archived in order of creation
|
||||
- Prompts before overwriting spec content
|
||||
|
||||
---
|
||||
|
||||
### `/opsx:onboard`
|
||||
|
||||
Guided onboarding through the complete OpenSpec workflow. An interactive tutorial using your actual codebase.
|
||||
|
||||
**Syntax:**
|
||||
```
|
||||
/opsx:onboard
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- Walks through a complete workflow cycle with narration
|
||||
- Scans your codebase for real improvement opportunities
|
||||
- Creates an actual change with real artifacts
|
||||
- Implements actual work (small, safe changes)
|
||||
- Archives the completed change
|
||||
- Explains each step as it happens
|
||||
|
||||
**Phases:**
|
||||
1. Welcome and codebase analysis
|
||||
2. Finding an improvement opportunity
|
||||
3. Creating a change (`/opsx:new`)
|
||||
4. Writing the proposal
|
||||
5. Creating specs
|
||||
6. Writing the design
|
||||
7. Creating tasks
|
||||
8. Implementing tasks (`/opsx:apply`)
|
||||
9. Verifying implementation
|
||||
10. Archiving the change
|
||||
11. Summary and next steps
|
||||
|
||||
**Example:**
|
||||
```
|
||||
You: /opsx:onboard
|
||||
|
||||
AI: Welcome to OpenSpec!
|
||||
|
||||
I'll walk you through the complete workflow using your actual codebase.
|
||||
We'll find something small to improve, create a proper change for it,
|
||||
implement it, and archive it.
|
||||
|
||||
Let me scan your codebase for opportunities...
|
||||
|
||||
[Analyzes codebase]
|
||||
|
||||
I found a few things we could work on:
|
||||
1. Add input validation to the contact form
|
||||
2. Improve error messages in the auth flow
|
||||
3. Add loading states to async buttons
|
||||
|
||||
Which interests you? (or suggest something else)
|
||||
```
|
||||
|
||||
**Tips:**
|
||||
- Best for new users learning the workflow
|
||||
- Uses real code, not toy examples
|
||||
- Creates a real change you can keep or discard
|
||||
- Takes 15-30 minutes to complete
|
||||
|
||||
---
|
||||
|
||||
## Command Syntax by AI Tool
|
||||
|
||||
Different AI tools use slightly different command syntax. Use the format that matches your tool:
|
||||
|
||||
| Your tool's command file | Syntax example | Example tools |
|
||||
|--------------------------|----------------|---------------|
|
||||
| `.../commands/opsx/<id>.*` | `/opsx:propose`, `/opsx:apply` | Claude Code, Gemini CLI, Crush |
|
||||
| `.../opsx-<id>.*` | `/opsx-propose`, `/opsx-apply` | Cursor, Devin Desktop, Copilot (IDE), Trae, Oh My Pi |
|
||||
| none — skills only | `/openspec-propose`, `/openspec-apply-change` | CodeArts, ForgeCode, Hermes, MiniMax Code, Mistral Vibe, Zed Agent, shared `.agents` |
|
||||
| none — Kimi Code | `/skill:openspec-propose` | Kimi Code |
|
||||
| none — Codex CLI | `$openspec-propose` | Codex |
|
||||
|
||||
> **Devin Desktop vs Devin Local:** the `.devin/workflows/opsx-*.md` files give
|
||||
> Devin Desktop `/opsx-propose`. Devin Local has no workflows — use the skills
|
||||
> OpenSpec writes to `.devin/skills/`, e.g. `/openspec-propose`, which work on
|
||||
> both agents.
|
||||
|
||||
The intent is the same across tools, but how commands are surfaced can differ by integration. [How To Invoke](supported-tools.md#how-to-invoke) lists every supported tool; this table shows only examples of each shape.
|
||||
|
||||
> **Note:** GitHub Copilot commands (`.github/prompts/*.prompt.md`) are only available in IDE extensions (VS Code, JetBrains, Visual Studio). GitHub Copilot CLI does not currently support custom prompt files — see [Supported Tools](supported-tools.md) for details and workarounds.
|
||||
|
||||
---
|
||||
|
||||
## Legacy Commands
|
||||
|
||||
These commands use the older "all-at-once" workflow. They still work but OPSX commands are recommended.
|
||||
|
||||
| Command | What it does |
|
||||
|---------|--------------|
|
||||
| `/openspec:proposal` | Create all artifacts at once (proposal, specs, design, tasks) |
|
||||
| `/openspec:apply` | Implement the change |
|
||||
| `/openspec:archive` | Archive the change |
|
||||
|
||||
**When to use legacy commands:**
|
||||
- Existing projects using the old workflow
|
||||
- Simple changes where you don't need incremental artifact creation
|
||||
- Preference for the all-or-nothing approach
|
||||
|
||||
**Migrating to OPSX:**
|
||||
Legacy changes can be continued with OPSX commands. The artifact structure is compatible.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Change not found"
|
||||
|
||||
The command couldn't identify which change to work on.
|
||||
|
||||
**Solutions:**
|
||||
- Specify the change name explicitly: `/opsx:apply add-dark-mode`
|
||||
- Check that the change folder exists: `openspec list`
|
||||
- Verify you're in the right project directory
|
||||
|
||||
### "No artifacts ready"
|
||||
|
||||
All artifacts are either complete or blocked by missing dependencies.
|
||||
|
||||
**Solutions:**
|
||||
- Run `openspec status --change <name>` to see what's blocking
|
||||
- Check if required artifacts exist
|
||||
- Create missing dependency artifacts first
|
||||
|
||||
### "Schema not found"
|
||||
|
||||
The specified schema doesn't exist.
|
||||
|
||||
**Solutions:**
|
||||
- List available schemas: `openspec schemas`
|
||||
- Check spelling of schema name
|
||||
- Create the schema if it's custom: `openspec schema init <name>`
|
||||
|
||||
### Commands not recognized
|
||||
|
||||
The AI tool doesn't recognize OpenSpec commands.
|
||||
|
||||
**Solutions:**
|
||||
- Ensure OpenSpec is initialized: `openspec init`
|
||||
- Regenerate skills: `openspec update`
|
||||
- Check that `.claude/skills/` directory exists (for Claude Code)
|
||||
- Restart your AI tool to pick up new skills
|
||||
|
||||
### Artifacts not generating properly
|
||||
|
||||
The AI creates incomplete or incorrect artifacts.
|
||||
|
||||
**Solutions:**
|
||||
- Add project context in `openspec/config.yaml`
|
||||
- Add per-artifact rules for specific guidance
|
||||
- Provide more detail in your change description
|
||||
- Use `/opsx:continue` instead of `/opsx:ff` for more control
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Workflows](workflows.md) - Common patterns and when to use each command
|
||||
- [CLI](cli.md) - Terminal commands for management and validation
|
||||
- [Customization](customization.md) - Create custom schemas and workflows
|
||||
@@ -1,20 +0,0 @@
|
||||
# Community Showcase
|
||||
|
||||
A community-owned awesome list of projects and resources built with and for OpenSpec. Tools, integrations, workflows, and learning resources are welcome. Community members grow and maintain this showcase through pull requests.
|
||||
|
||||
Listed projects are maintained independently. Inclusion does not imply official support or endorsement by OpenSpec. See each project's documentation and issue tracker for setup and support.
|
||||
|
||||
## Projects and resources
|
||||
|
||||
- **[OpenSpec Workbench](https://github.com/VeryComplexAndLongName/OpenSpec-UI)**: Running and supervising agents on OpenSpec changes.
|
||||
- **[openspec-guard](https://github.com/guillaume-flambard/spec-guard)**: CLI and GitHub Action that reports which OpenSpec scenarios are covered by a Vitest or Jest test, without running the tests.
|
||||
|
||||
## Add your project
|
||||
|
||||
Open a pull request adding one line to this file with your project's name, a direct link, and a short description of how it relates to OpenSpec.
|
||||
|
||||
- Keep entries focused on something built with OpenSpec or supporting its use, rather than general product advertising.
|
||||
- Describe what people can use. Avoid promotional claims, referral links, and tracking links.
|
||||
- Disclose paid features or required accounts in the entry, if any.
|
||||
|
||||
Corrections and updates to existing entries are welcome too.
|
||||
@@ -1,631 +0,0 @@
|
||||
# Concepts
|
||||
|
||||
This guide explains the core ideas behind OpenSpec and how they fit together. For practical usage, see [Getting Started](getting-started.md) and [Workflows](workflows.md).
|
||||
|
||||
## Philosophy
|
||||
|
||||
OpenSpec is built around four principles:
|
||||
|
||||
```
|
||||
fluid not rigid — no phase gates, work on what makes sense
|
||||
iterative not waterfall — learn as you build, refine as you go
|
||||
easy not complex — lightweight setup, minimal ceremony
|
||||
brownfield-first — works with existing codebases, not just greenfield
|
||||
```
|
||||
|
||||
### Why These Principles Matter
|
||||
|
||||
**Fluid not rigid.** Traditional spec systems lock you into phases: first you plan, then you implement, then you're done. OpenSpec is more flexible — you can create artifacts in any order that makes sense for your work.
|
||||
|
||||
**Iterative not waterfall.** Requirements change. Understanding deepens. What seemed like a good approach at the start might not hold up after you see the codebase. OpenSpec embraces this reality.
|
||||
|
||||
**Easy not complex.** Some spec frameworks require extensive setup, rigid formats, or heavyweight processes. OpenSpec stays out of your way. Initialize in seconds, start working immediately, customize only if you need to.
|
||||
|
||||
**Brownfield-first.** Most software work isn't building from scratch — it's modifying existing systems. OpenSpec's delta-based approach makes it easy to specify changes to existing behavior, not just describe new systems.
|
||||
|
||||
## The Big Picture
|
||||
|
||||
OpenSpec organizes your work into two main areas:
|
||||
|
||||
```
|
||||
┌────────────────────────────────────────────────────────────────────┐
|
||||
│ openspec/ │
|
||||
│ │
|
||||
│ ┌─────────────────────┐ ┌───────────────────────────────┐ │
|
||||
│ │ specs/ │ │ changes/ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ Source of truth │◄─────│ Proposed modifications │ │
|
||||
│ │ How your system │ merge│ Each change = one folder │ │
|
||||
│ │ currently works │ │ Contains artifacts + deltas │ │
|
||||
│ │ │ │ │ │
|
||||
│ └─────────────────────┘ └───────────────────────────────┘ │
|
||||
│ │
|
||||
└────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Specs** are the source of truth — they describe how your system currently behaves.
|
||||
|
||||
**Changes** are proposed modifications — they live in separate folders until you're ready to merge them.
|
||||
|
||||
This separation is key. You can work on multiple changes in parallel without conflicts. You can review a change before it affects the main specs. And when you archive a change, its deltas merge cleanly into the source of truth.
|
||||
|
||||
## Specs
|
||||
|
||||
Specs describe your system's behavior using structured requirements and scenarios.
|
||||
|
||||
### Structure
|
||||
|
||||
```
|
||||
openspec/specs/
|
||||
├── auth/
|
||||
│ └── spec.md # Authentication behavior
|
||||
├── payments/
|
||||
│ └── spec.md # Payment processing
|
||||
├── notifications/
|
||||
│ └── spec.md # Notification system
|
||||
└── ui/
|
||||
└── spec.md # UI behavior and themes
|
||||
```
|
||||
|
||||
Organize specs by domain — logical groupings that make sense for your system. Common patterns:
|
||||
|
||||
- **By feature area**: `auth/`, `payments/`, `search/`
|
||||
- **By component**: `api/`, `frontend/`, `workers/`
|
||||
- **By bounded context**: `ordering/`, `fulfillment/`, `inventory/`
|
||||
|
||||
### Spec Format
|
||||
|
||||
A spec contains requirements, and each requirement has scenarios:
|
||||
|
||||
```markdown
|
||||
# Auth Specification
|
||||
|
||||
## Purpose
|
||||
Authentication and session management for the application.
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: User Authentication
|
||||
The system SHALL issue a JWT token upon successful login.
|
||||
|
||||
#### Scenario: Valid credentials
|
||||
- GIVEN a user with valid credentials
|
||||
- WHEN the user submits login form
|
||||
- THEN a JWT token is returned
|
||||
- AND the user is redirected to dashboard
|
||||
|
||||
#### Scenario: Invalid credentials
|
||||
- GIVEN invalid credentials
|
||||
- WHEN the user submits login form
|
||||
- THEN an error message is displayed
|
||||
- AND no token is issued
|
||||
|
||||
### Requirement: Session Expiration
|
||||
The system MUST expire sessions after 30 minutes of inactivity.
|
||||
|
||||
#### Scenario: Idle timeout
|
||||
- GIVEN an authenticated session
|
||||
- WHEN 30 minutes pass without activity
|
||||
- THEN the session is invalidated
|
||||
- AND the user must re-authenticate
|
||||
```
|
||||
|
||||
**Key elements:**
|
||||
|
||||
| Element | Purpose |
|
||||
|---------|---------|
|
||||
| `## Purpose` | High-level description of this spec's domain |
|
||||
| `### Requirement:` | A specific behavior the system must have |
|
||||
| `#### Scenario:` | A concrete example of the requirement in action |
|
||||
| SHALL/MUST/SHOULD | RFC 2119 keywords indicating requirement strength |
|
||||
|
||||
### Why Structure Specs This Way
|
||||
|
||||
**Requirements are the "what"** — they state what the system should do without specifying implementation.
|
||||
|
||||
**Scenarios are the "when"** — they provide concrete examples that can be verified. Good scenarios:
|
||||
- Are testable (you could write an automated test for them)
|
||||
- Cover both happy path and edge cases
|
||||
- Use Given/When/Then or similar structured format
|
||||
|
||||
**RFC 2119 keywords** (SHALL, MUST, SHOULD, MAY) communicate intent:
|
||||
- **MUST/SHALL** — absolute requirement
|
||||
- **SHOULD** — recommended, but exceptions exist
|
||||
- **MAY** — optional
|
||||
|
||||
### What a Spec Is (and Is Not)
|
||||
|
||||
A spec is a **behavior contract**, not an implementation plan.
|
||||
|
||||
Good spec content:
|
||||
- Observable behavior users or downstream systems rely on
|
||||
- Inputs, outputs, and error conditions
|
||||
- External constraints (security, privacy, reliability, compatibility)
|
||||
- Scenarios that can be tested or explicitly validated
|
||||
|
||||
Avoid in specs:
|
||||
- Internal class/function names
|
||||
- Library or framework choices
|
||||
- Step-by-step implementation details
|
||||
- Detailed execution plans (those belong in `design.md` or `tasks.md`)
|
||||
|
||||
Quick test:
|
||||
- If implementation can change without changing externally visible behavior, it likely does not belong in the spec.
|
||||
|
||||
### Keep It Lightweight: Progressive Rigor
|
||||
|
||||
OpenSpec aims to avoid bureaucracy. Use the lightest level that still makes the change verifiable.
|
||||
|
||||
**Lite spec (default):**
|
||||
- Short behavior-first requirements
|
||||
- Clear scope and non-goals
|
||||
- A few concrete acceptance checks
|
||||
|
||||
**Full spec (for higher risk):**
|
||||
- Cross-team or cross-repo changes
|
||||
- API/contract changes, migrations, security/privacy concerns
|
||||
- Changes where ambiguity is likely to cause expensive rework
|
||||
|
||||
Most changes should stay in Lite mode.
|
||||
|
||||
### Human + Agent Collaboration
|
||||
|
||||
In many teams, humans explore and agents draft artifacts. The intended loop is:
|
||||
|
||||
1. Human provides intent, context, and constraints.
|
||||
2. Agent converts this into behavior-first requirements and scenarios.
|
||||
3. Agent keeps implementation detail in `design.md` and `tasks.md`, not `spec.md`.
|
||||
4. Validation confirms structure and clarity before implementation.
|
||||
|
||||
This keeps specs readable for humans and consistent for agents.
|
||||
|
||||
## Changes
|
||||
|
||||
A change is a proposed modification to your system, packaged as a folder with everything needed to understand and implement it.
|
||||
|
||||
### Change Structure
|
||||
|
||||
```
|
||||
openspec/changes/add-dark-mode/
|
||||
├── proposal.md # Why and what
|
||||
├── design.md # How (technical approach)
|
||||
├── tasks.md # Implementation checklist
|
||||
├── .openspec.yaml # Change metadata (optional): schema, created, skip_specs, retire_capabilities
|
||||
└── specs/ # Delta specs
|
||||
└── ui/
|
||||
└── spec.md # What's changing in ui/spec.md
|
||||
```
|
||||
|
||||
Each change is self-contained. It has:
|
||||
- **Artifacts** — documents that capture intent, design, and tasks
|
||||
- **Delta specs** — specifications for what's being added, modified, or removed
|
||||
- **Metadata** — optional configuration for this specific change
|
||||
|
||||
### Why Changes Are Folders
|
||||
|
||||
Packaging a change as a folder has several benefits:
|
||||
|
||||
1. **Everything together.** Proposal, design, tasks, and specs live in one place. No hunting through different locations.
|
||||
|
||||
2. **Parallel work.** Multiple changes can exist simultaneously without conflicting. Work on `add-dark-mode` while `fix-auth-bug` is also in progress.
|
||||
|
||||
3. **Clean history.** When archived, changes move to `changes/archive/` with their full context preserved. You can look back and understand not just what changed, but why.
|
||||
|
||||
4. **Review-friendly.** A change folder is easy to review — open it, read the proposal, check the design, see the spec deltas.
|
||||
|
||||
## Artifacts
|
||||
|
||||
Artifacts are the documents within a change that guide the work.
|
||||
|
||||
### The Artifact Flow
|
||||
|
||||
```
|
||||
proposal ──────► specs ──────► design ──────► tasks ──────► implement
|
||||
│ │ │ │
|
||||
why what how steps
|
||||
+ scope changes approach to take
|
||||
```
|
||||
|
||||
Artifacts build on each other. Each artifact provides context for the next.
|
||||
|
||||
### Artifact Types
|
||||
|
||||
#### Proposal (`proposal.md`)
|
||||
|
||||
The proposal captures **intent**, **scope**, and **approach** at a high level.
|
||||
|
||||
```markdown
|
||||
# Proposal: Add Dark Mode
|
||||
|
||||
## Intent
|
||||
Users have requested a dark mode option to reduce eye strain
|
||||
during nighttime usage and match system preferences.
|
||||
|
||||
## Scope
|
||||
In scope:
|
||||
- Theme toggle in settings
|
||||
- System preference detection
|
||||
- Persist preference in localStorage
|
||||
|
||||
Out of scope:
|
||||
- Custom color themes (future work)
|
||||
- Per-page theme overrides
|
||||
|
||||
## Approach
|
||||
Use CSS custom properties for theming with a React context
|
||||
for state management. Detect system preference on first load,
|
||||
allow manual override.
|
||||
```
|
||||
|
||||
**When to update the proposal:**
|
||||
- Scope changes (narrowing or expanding)
|
||||
- Intent clarifies (better understanding of the problem)
|
||||
- Approach fundamentally shifts
|
||||
|
||||
#### Specs (delta specs in `specs/`)
|
||||
|
||||
Delta specs describe **what's changing** relative to the current specs. See [Delta Specs](#delta-specs) below.
|
||||
|
||||
#### Design (`design.md`)
|
||||
|
||||
The design captures **technical approach** and **architecture decisions**.
|
||||
|
||||
````markdown
|
||||
# Design: Add Dark Mode
|
||||
|
||||
## Technical Approach
|
||||
Theme state managed via React Context to avoid prop drilling.
|
||||
CSS custom properties enable runtime switching without class toggling.
|
||||
|
||||
## Architecture Decisions
|
||||
|
||||
### Decision: Context over Redux
|
||||
Using React Context for theme state because:
|
||||
- Simple binary state (light/dark)
|
||||
- No complex state transitions
|
||||
- Avoids adding Redux dependency
|
||||
|
||||
### Decision: CSS Custom Properties
|
||||
Using CSS variables instead of CSS-in-JS because:
|
||||
- Works with existing stylesheet
|
||||
- No runtime overhead
|
||||
- Browser-native solution
|
||||
|
||||
## Data Flow
|
||||
```
|
||||
ThemeProvider (context)
|
||||
│
|
||||
▼
|
||||
ThemeToggle ◄──► localStorage
|
||||
│
|
||||
▼
|
||||
CSS Variables (applied to :root)
|
||||
```
|
||||
|
||||
## File Changes
|
||||
- `src/contexts/ThemeContext.tsx` (new)
|
||||
- `src/components/ThemeToggle.tsx` (new)
|
||||
- `src/styles/globals.css` (modified)
|
||||
````
|
||||
|
||||
**When to update the design:**
|
||||
- Implementation reveals the approach won't work
|
||||
- Better solution discovered
|
||||
- Dependencies or constraints change
|
||||
|
||||
#### Tasks (`tasks.md`)
|
||||
|
||||
Tasks are the **implementation checklist** — concrete steps with checkboxes.
|
||||
|
||||
```markdown
|
||||
# Tasks
|
||||
|
||||
## 1. Theme Infrastructure
|
||||
- [ ] 1.1 Create ThemeContext with light/dark state
|
||||
- [ ] 1.2 Add CSS custom properties for colors
|
||||
- [ ] 1.3 Implement localStorage persistence
|
||||
- [ ] 1.4 Add system preference detection
|
||||
|
||||
## 2. UI Components
|
||||
- [ ] 2.1 Create ThemeToggle component
|
||||
- [ ] 2.2 Add toggle to settings page
|
||||
- [ ] 2.3 Update Header to include quick toggle
|
||||
|
||||
## 3. Styling
|
||||
- [ ] 3.1 Define dark theme color palette
|
||||
- [ ] 3.2 Update components to use CSS variables
|
||||
- [ ] 3.3 Test contrast ratios for accessibility
|
||||
```
|
||||
|
||||
**Task best practices:**
|
||||
- Group related tasks under headings
|
||||
- Use hierarchical numbering (1.1, 1.2, etc.)
|
||||
- Keep tasks small enough to complete in one session
|
||||
- State how each task is verified (a test, command, or observable result)
|
||||
- Land the tests and documentation each group's work calls for inside that group, not in a final catch-up group
|
||||
- Check tasks off as you complete them
|
||||
|
||||
## Delta Specs
|
||||
|
||||
Delta specs are the key concept that makes OpenSpec work for brownfield development. They describe **what's changing** rather than restating the entire spec.
|
||||
|
||||
### The Format
|
||||
|
||||
```markdown
|
||||
# Delta for Auth
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Two-Factor Authentication
|
||||
The system MUST support TOTP-based two-factor authentication.
|
||||
|
||||
#### Scenario: 2FA enrollment
|
||||
- GIVEN a user without 2FA enabled
|
||||
- WHEN the user enables 2FA in settings
|
||||
- THEN a QR code is displayed for authenticator app setup
|
||||
- AND the user must verify with a code before activation
|
||||
|
||||
#### Scenario: 2FA login
|
||||
- GIVEN a user with 2FA enabled
|
||||
- WHEN the user submits valid credentials
|
||||
- THEN an OTP challenge is presented
|
||||
- AND login completes only after valid OTP
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Session Expiration
|
||||
The system MUST expire sessions after 15 minutes of inactivity.
|
||||
(Previously: 30 minutes)
|
||||
|
||||
#### Scenario: Idle timeout
|
||||
- GIVEN an authenticated session
|
||||
- WHEN 15 minutes pass without activity
|
||||
- THEN the session is invalidated
|
||||
|
||||
## REMOVED Requirements
|
||||
|
||||
### Requirement: Remember Me
|
||||
(Deprecated in favor of 2FA. Users should re-authenticate each session.)
|
||||
```
|
||||
|
||||
### Delta Sections
|
||||
|
||||
| Section | Meaning | What Happens on Archive |
|
||||
|---------|---------|------------------------|
|
||||
| `## ADDED Requirements` | New behavior | Appended to main spec |
|
||||
| `## MODIFIED Requirements` | Changed behavior | Replaces existing requirement |
|
||||
| `## REMOVED Requirements` | Deprecated behavior | Deleted from main spec; removing the last requirement retires the capability and deletes its spec file, when the change declares `retire_capabilities: true` |
|
||||
| `## Purpose` | What a brand-new capability is for | Seeds the Purpose of the main spec being created; ignored when the spec already exists |
|
||||
|
||||
### Why Deltas Instead of Full Specs
|
||||
|
||||
**Clarity.** A delta shows exactly what's changing. Reading a full spec, you'd have to diff it mentally against the current version.
|
||||
|
||||
**Conflict avoidance.** Two changes can touch the same spec file without conflicting, as long as they modify different requirements.
|
||||
|
||||
**Review efficiency.** Reviewers see the change, not the unchanged context. Focus on what matters.
|
||||
|
||||
**Brownfield fit.** Most work modifies existing behavior. Deltas make modifications first-class, not an afterthought.
|
||||
|
||||
## Schemas
|
||||
|
||||
Schemas define the artifact types and their dependencies for a workflow.
|
||||
|
||||
### How Schemas Work
|
||||
|
||||
```yaml
|
||||
# openspec/schemas/spec-driven/schema.yaml
|
||||
name: spec-driven
|
||||
artifacts:
|
||||
- id: proposal
|
||||
generates: proposal.md
|
||||
requires: [] # No dependencies, can create first
|
||||
|
||||
- id: specs
|
||||
generates: specs/**/*.md
|
||||
requires: [proposal] # Needs proposal before creating
|
||||
|
||||
- id: design
|
||||
generates: design.md
|
||||
requires: [proposal] # Can create in parallel with specs
|
||||
|
||||
- id: tasks
|
||||
generates: tasks.md
|
||||
requires: [specs, design] # Needs both specs and design first
|
||||
```
|
||||
|
||||
**Artifacts form a dependency graph:**
|
||||
|
||||
```
|
||||
proposal
|
||||
(root node)
|
||||
│
|
||||
┌─────────────┴─────────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
specs design
|
||||
(requires: (requires:
|
||||
proposal) proposal)
|
||||
│ │
|
||||
└─────────────┬─────────────┘
|
||||
│
|
||||
▼
|
||||
tasks
|
||||
(requires:
|
||||
specs, design)
|
||||
```
|
||||
|
||||
**Dependencies are enablers, not gates.** They show what's possible to create, not what you must create next. You can skip design if you don't need it. You can create specs before or after design — both depend only on proposal.
|
||||
|
||||
### Built-in Schemas
|
||||
|
||||
**spec-driven** (default)
|
||||
|
||||
The standard workflow for spec-driven development:
|
||||
|
||||
```
|
||||
proposal → specs → design → tasks → implement
|
||||
```
|
||||
|
||||
Best for: Most feature work where you want to agree on specs before implementation.
|
||||
|
||||
### Custom Schemas
|
||||
|
||||
Create custom schemas for your team's workflow:
|
||||
|
||||
```bash
|
||||
# Create from scratch
|
||||
openspec schema init research-first
|
||||
|
||||
# Or fork an existing one
|
||||
openspec schema fork spec-driven research-first
|
||||
```
|
||||
|
||||
**Example custom schema:**
|
||||
|
||||
```yaml
|
||||
# openspec/schemas/research-first/schema.yaml
|
||||
name: research-first
|
||||
artifacts:
|
||||
- id: research
|
||||
generates: research.md
|
||||
requires: [] # Do research first
|
||||
|
||||
- id: proposal
|
||||
generates: proposal.md
|
||||
requires: [research] # Proposal informed by research
|
||||
|
||||
- id: tasks
|
||||
generates: tasks.md
|
||||
requires: [proposal] # Skip specs/design, go straight to tasks
|
||||
```
|
||||
|
||||
See [Customization](customization.md) for full details on creating and using custom schemas.
|
||||
|
||||
## Archive
|
||||
|
||||
Archiving completes a change by merging its delta specs into the main specs and preserving the change for history.
|
||||
|
||||
### What Happens When You Archive
|
||||
|
||||
```
|
||||
Before archive:
|
||||
|
||||
openspec/
|
||||
├── specs/
|
||||
│ └── auth/
|
||||
│ └── spec.md ◄────────────────┐
|
||||
└── changes/ │
|
||||
└── add-2fa/ │
|
||||
├── proposal.md │
|
||||
├── design.md │ merge
|
||||
├── tasks.md │
|
||||
└── specs/ │
|
||||
└── auth/ │
|
||||
└── spec.md ─────────┘
|
||||
|
||||
|
||||
After archive:
|
||||
|
||||
openspec/
|
||||
├── specs/
|
||||
│ └── auth/
|
||||
│ └── spec.md # Now includes 2FA requirements
|
||||
└── changes/
|
||||
└── archive/
|
||||
└── 2025-01-24-add-2fa/ # Preserved for history
|
||||
├── proposal.md
|
||||
├── design.md
|
||||
├── tasks.md
|
||||
└── specs/
|
||||
└── auth/
|
||||
└── spec.md
|
||||
```
|
||||
|
||||
### The Archive Process
|
||||
|
||||
1. **Merge deltas.** Each delta spec section (ADDED/MODIFIED/REMOVED) is applied to the corresponding main spec.
|
||||
|
||||
2. **Move to archive.** The change folder moves to `changes/archive/` with a date prefix for chronological ordering.
|
||||
|
||||
3. **Preserve context.** All artifacts remain intact in the archive. You can always look back to understand why a change was made.
|
||||
|
||||
### Why Archive Matters
|
||||
|
||||
**Clean state.** Active changes (`changes/`) shows only work in progress. Completed work moves out of the way.
|
||||
|
||||
**Audit trail.** The archive preserves the full context of every change — not just what changed, but the proposal explaining why, the design explaining how, and the tasks showing the work done.
|
||||
|
||||
**Spec evolution.** Specs grow organically as changes are archived. Each archive merges its deltas, building up a comprehensive specification over time.
|
||||
|
||||
## How It All Fits Together
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────────────────┐
|
||||
│ OPENSPEC FLOW │
|
||||
│ │
|
||||
│ ┌────────────────┐ │
|
||||
│ │ 1. START │ /opsx:propose (core) or /opsx:new (expanded) │
|
||||
│ │ CHANGE │ │
|
||||
│ └───────┬────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌────────────────┐ │
|
||||
│ │ 2. CREATE │ /opsx:ff or /opsx:continue (expanded workflow) │
|
||||
│ │ ARTIFACTS │ Creates proposal → specs → design → tasks │
|
||||
│ │ │ (based on schema dependencies) │
|
||||
│ └───────┬────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌────────────────┐ │
|
||||
│ │ 3. IMPLEMENT │ /opsx:apply │
|
||||
│ │ TASKS │ Work through tasks, checking them off │
|
||||
│ │ │◄──── Update artifacts as you learn │
|
||||
│ └───────┬────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌────────────────┐ │
|
||||
│ │ 4. VERIFY │ /opsx:verify (optional) │
|
||||
│ │ WORK │ Check implementation matches specs │
|
||||
│ └───────┬────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌────────────────┐ ┌──────────────────────────────────────────────┐ │
|
||||
│ │ 5. ARCHIVE │────►│ Delta specs merge into main specs │ │
|
||||
│ │ CHANGE │ │ Change folder moves to archive/ │ │
|
||||
│ └────────────────┘ │ Specs are now the updated source of truth │ │
|
||||
│ └──────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**The virtuous cycle:**
|
||||
|
||||
1. Specs describe current behavior
|
||||
2. Changes propose modifications (as deltas)
|
||||
3. Implementation makes the changes real
|
||||
4. Archive merges deltas into specs
|
||||
5. Specs now describe the new behavior
|
||||
6. Next change builds on updated specs
|
||||
|
||||
## Glossary
|
||||
|
||||
| Term | Definition |
|
||||
|------|------------|
|
||||
| **Artifact** | A document within a change (proposal, design, tasks, or delta specs) |
|
||||
| **Archive** | The process of completing a change and merging its deltas into main specs |
|
||||
| **Change** | A proposed modification to the system, packaged as a folder with artifacts |
|
||||
| **Delta spec** | A spec that describes changes (ADDED/MODIFIED/REMOVED) relative to current specs |
|
||||
| **Domain** | A logical grouping for specs (e.g., `auth/`, `payments/`) |
|
||||
| **Requirement** | A specific behavior the system must have |
|
||||
| **Scenario** | A concrete example of a requirement, typically in Given/When/Then format |
|
||||
| **Schema** | A definition of artifact types and their dependencies |
|
||||
| **Spec** | A specification describing system behavior, containing requirements and scenarios |
|
||||
| **Source of truth** | The `openspec/specs/` directory, containing the current agreed-upon behavior |
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Getting Started](getting-started.md) - Practical first steps
|
||||
- [Workflows](workflows.md) - Common patterns and when to use each
|
||||
- [Commands](commands.md) - Full command reference
|
||||
- [Customization](customization.md) - Create custom schemas and configure your project
|
||||
@@ -1,433 +0,0 @@
|
||||
# Customization
|
||||
|
||||
OpenSpec provides three levels of customization:
|
||||
|
||||
| Level | What it does | Best for |
|
||||
|-------|--------------|----------|
|
||||
| **Project Config** | Set defaults, inject context/rules | Most teams |
|
||||
| **Custom Schemas** | Define your own workflow artifacts | Teams with unique processes |
|
||||
| **Global Overrides** | Share schemas across all projects | Power users |
|
||||
|
||||
---
|
||||
|
||||
## Project Configuration
|
||||
|
||||
The `openspec/config.yaml` file is the easiest way to customize OpenSpec for your team. It lets you:
|
||||
|
||||
- **Set a default schema** - Skip `--schema` on every command
|
||||
- **Inject project context** - AI sees your tech stack, conventions, etc.
|
||||
- **Add per-artifact rules** - Custom rules for specific artifacts
|
||||
- **Add per-operation guidance** - Advisory preferences for apply and archive work
|
||||
- **Remember integration choices** - e.g. the [GitHub Copilot cloud coding agent](supported-tools.md#github-copilot-cloud-coding-agent) opt-in
|
||||
|
||||
### Quick Setup
|
||||
|
||||
```bash
|
||||
openspec init
|
||||
```
|
||||
|
||||
This walks you through creating a config interactively. Or create one manually:
|
||||
|
||||
```yaml
|
||||
# openspec/config.yaml
|
||||
schema: spec-driven
|
||||
|
||||
context: |
|
||||
Tech stack: TypeScript, React, Node.js, PostgreSQL
|
||||
API style: RESTful, documented in docs/api.md
|
||||
Testing: Jest + React Testing Library
|
||||
We value backwards compatibility for all public APIs
|
||||
|
||||
rules:
|
||||
proposal:
|
||||
- Include rollback plan
|
||||
- Identify affected teams
|
||||
specs:
|
||||
- Use Given/When/Then format
|
||||
- Reference existing patterns before inventing new ones
|
||||
|
||||
operations:
|
||||
apply:
|
||||
guidance:
|
||||
- Run focused tests before the full suite
|
||||
archive:
|
||||
guidance:
|
||||
- Keep the completion summary concise
|
||||
|
||||
# Set by `openspec init` when you choose (or decline) the GitHub Copilot
|
||||
# cloud coding agent; controls whether `init`/`update` generate its files.
|
||||
githubCopilot:
|
||||
cloudAgent: false
|
||||
```
|
||||
|
||||
### How It Works
|
||||
|
||||
**Default schema:**
|
||||
|
||||
```bash
|
||||
# Without config
|
||||
openspec new change my-feature --schema spec-driven
|
||||
|
||||
# With config - schema is automatic
|
||||
openspec new change my-feature
|
||||
```
|
||||
|
||||
**Context and rules injection:**
|
||||
|
||||
When generating any artifact, your context and rules are injected into the AI prompt:
|
||||
|
||||
```xml
|
||||
<context>
|
||||
Tech stack: TypeScript, React, Node.js, PostgreSQL
|
||||
...
|
||||
</context>
|
||||
|
||||
<rules>
|
||||
- Include rollback plan
|
||||
- Identify affected teams
|
||||
</rules>
|
||||
|
||||
<template>
|
||||
[Schema's built-in template]
|
||||
</template>
|
||||
```
|
||||
|
||||
- **Context** appears in ALL artifacts
|
||||
- **Rules** ONLY appear for the matching artifact
|
||||
|
||||
**Operation guidance:**
|
||||
|
||||
`operations.apply.guidance` and `operations.archive.guidance` are optional arrays
|
||||
of advisory instructions for how an agent should conduct those operations. They
|
||||
are separate from `rules`: operation guidance does not constrain artifact content,
|
||||
and artifact rules are never relabeled as operation guidance.
|
||||
|
||||
Apply and archive fetch these inputs at execution time:
|
||||
|
||||
```bash
|
||||
openspec instructions apply --change my-feature --json
|
||||
openspec instructions archive --change my-feature --json
|
||||
```
|
||||
|
||||
Both surfaces return current project `context` and matching
|
||||
`operationGuidance` as separate optional fields. Each invocation reads a fresh
|
||||
snapshot from the resolved root. When `--store <id>` is selected, the change,
|
||||
context, and guidance all come from that store rather than the current repository.
|
||||
The archive instruction command is read-only: it does not inspect or merge delta
|
||||
specs, write main specs, move the change, or run the static archive workflow.
|
||||
|
||||
Project context is a required prompt-level input. Generated workflows read it and
|
||||
apply relevant project facts, conventions, and constraints. Operation guidance is
|
||||
optional additive advice: workflows consider every entry and follow entries that
|
||||
are applicable and compatible with the built-in workflow.
|
||||
|
||||
Both fields remain separate from CLI-controlled state, resolved paths, built-in
|
||||
steps, explicit user choices, and artifact rules. A workflow reports context
|
||||
conflicts while preserving the controlling value. It does not follow inapplicable
|
||||
or conflicting guidance and explains why. Neither field is an enforceable check,
|
||||
and workflows do not copy their text into implementation files, specs, change
|
||||
artifacts, or summaries unless the user separately requests that content.
|
||||
|
||||
**Archive and spec-sync input safety:**
|
||||
|
||||
Archive, bulk archive, and standalone sync use
|
||||
`artifactPaths.specs.existingOutputPaths` from `openspec status --json` as the
|
||||
only delta-spec source. A schema without a `specs` artifact, or a change whose
|
||||
concrete output list is empty, has nothing to sync; other artifacts are not used
|
||||
to infer delta specs.
|
||||
|
||||
Before a semantic merge writes a main spec, the workflow consumes current
|
||||
`openspec instructions specs --change <name> --json` output. The returned
|
||||
`specs` rules constrain only the main specs produced by that merge. Single archive
|
||||
passes that snapshot into inline sync, standalone sync fetches it directly, and
|
||||
bulk archive obtains every required snapshot before its first spec write. A
|
||||
non-zero or invalid JSON archive/specs instruction response is a lookup failure,
|
||||
not an empty input: the workflow stops before the affected spec write or change
|
||||
move (for bulk archive, before any batch write or move).
|
||||
|
||||
This configuration does not change archive execution phases, user prompts,
|
||||
filesystem operations, semantic merge ownership, the direct `openspec archive`
|
||||
command, or the structure and output of artifact `rules`.
|
||||
|
||||
### Schema Resolution Order
|
||||
|
||||
When OpenSpec needs a schema, it checks in this order:
|
||||
|
||||
1. CLI flag: `--schema <name>`
|
||||
2. Change metadata (`.openspec.yaml` in the change folder)
|
||||
3. Project config (`openspec/config.yaml`)
|
||||
4. Default (`spec-driven`)
|
||||
|
||||
---
|
||||
|
||||
## Custom Schemas
|
||||
|
||||
When project config isn't enough, create your own schema with a completely custom workflow. Custom schemas live in your project's `openspec/schemas/` directory and are version-controlled with your code.
|
||||
|
||||
```text
|
||||
your-project/
|
||||
├── openspec/
|
||||
│ ├── config.yaml # Project config
|
||||
│ ├── schemas/ # Custom schemas live here
|
||||
│ │ └── my-workflow/
|
||||
│ │ ├── schema.yaml
|
||||
│ │ └── templates/
|
||||
│ └── changes/ # Your changes
|
||||
└── src/
|
||||
```
|
||||
|
||||
### Fork an Existing Schema
|
||||
|
||||
The fastest way to customize is to fork a built-in schema:
|
||||
|
||||
```bash
|
||||
openspec schema fork spec-driven my-workflow
|
||||
```
|
||||
|
||||
This copies the entire `spec-driven` schema to `openspec/schemas/my-workflow/` where you can edit it freely.
|
||||
|
||||
**What you get:**
|
||||
|
||||
```text
|
||||
openspec/schemas/my-workflow/
|
||||
├── schema.yaml # Workflow definition
|
||||
└── templates/
|
||||
├── proposal.md # Template for proposal artifact
|
||||
├── spec.md # Template for specs
|
||||
├── design.md # Template for design
|
||||
└── tasks.md # Template for tasks
|
||||
```
|
||||
|
||||
Now edit `schema.yaml` to change the workflow, or edit templates to change what AI generates.
|
||||
|
||||
### Create a Schema from Scratch
|
||||
|
||||
For a completely fresh workflow:
|
||||
|
||||
```bash
|
||||
# Interactive
|
||||
openspec schema init research-first
|
||||
|
||||
# Non-interactive
|
||||
openspec schema init rapid \
|
||||
--description "Rapid iteration workflow" \
|
||||
--artifacts "proposal,tasks" \
|
||||
--default
|
||||
```
|
||||
|
||||
### Schema Structure
|
||||
|
||||
A schema defines the artifacts in your workflow and how they depend on each other:
|
||||
|
||||
```yaml
|
||||
# openspec/schemas/my-workflow/schema.yaml
|
||||
name: my-workflow
|
||||
version: 1
|
||||
description: My team's custom workflow
|
||||
|
||||
artifacts:
|
||||
- id: proposal
|
||||
generates: proposal.md
|
||||
description: Initial proposal document
|
||||
template: proposal.md
|
||||
instruction: |
|
||||
Create a proposal that explains WHY this change is needed.
|
||||
Focus on the problem, not the solution.
|
||||
requires: []
|
||||
|
||||
- id: design
|
||||
generates: design.md
|
||||
description: Technical design
|
||||
template: design.md
|
||||
instruction: |
|
||||
Create a design document explaining HOW to implement.
|
||||
requires:
|
||||
- proposal # Can't create design until proposal exists
|
||||
|
||||
- id: tasks
|
||||
generates: tasks.md
|
||||
description: Implementation checklist
|
||||
template: tasks.md
|
||||
requires:
|
||||
- design
|
||||
|
||||
apply:
|
||||
requires: [tasks]
|
||||
tracks: tasks.md
|
||||
```
|
||||
|
||||
**Key fields:**
|
||||
|
||||
| Field | Purpose |
|
||||
|-------|---------|
|
||||
| `id` | Unique identifier, used in commands and rules |
|
||||
| `generates` | Output filename (supports globs like `specs/**/*.md`) |
|
||||
| `template` | Template file in `templates/` directory |
|
||||
| `instruction` | AI instructions for creating this artifact |
|
||||
| `requires` | Dependencies - which artifacts must exist first |
|
||||
|
||||
List artifacts in the order you want them written. `requires` decides what is
|
||||
possible; the order of the `artifacts:` list decides what comes first when
|
||||
several artifacts are ready at once.
|
||||
|
||||
### Templates
|
||||
|
||||
Templates are markdown files that guide the AI. They're injected into the prompt when creating that artifact.
|
||||
|
||||
```markdown
|
||||
<!-- templates/proposal.md -->
|
||||
## Why
|
||||
|
||||
<!-- Explain the motivation for this change. What problem does this solve? -->
|
||||
|
||||
## What Changes
|
||||
|
||||
<!-- Describe what will change. Be specific about new capabilities or modifications. -->
|
||||
|
||||
## Impact
|
||||
|
||||
<!-- Affected code, APIs, dependencies, systems -->
|
||||
```
|
||||
|
||||
Templates can include:
|
||||
- Section headers the AI should fill in
|
||||
- HTML comments with guidance for the AI
|
||||
- Example formats showing expected structure
|
||||
|
||||
### Validate Your Schema
|
||||
|
||||
Before using a custom schema, validate it:
|
||||
|
||||
```bash
|
||||
openspec schema validate my-workflow
|
||||
```
|
||||
|
||||
This checks:
|
||||
- `schema.yaml` syntax is correct
|
||||
- All referenced templates exist
|
||||
- No circular dependencies
|
||||
- Artifact IDs are valid
|
||||
|
||||
### Use Your Custom Schema
|
||||
|
||||
Once created, use your schema with:
|
||||
|
||||
```bash
|
||||
# Specify on command
|
||||
openspec new change feature --schema my-workflow
|
||||
|
||||
# Or set as default in config.yaml
|
||||
schema: my-workflow
|
||||
```
|
||||
|
||||
### Debug Schema Resolution
|
||||
|
||||
Not sure which schema is being used? Check with:
|
||||
|
||||
```bash
|
||||
# See where a specific schema resolves from
|
||||
openspec schema which my-workflow
|
||||
|
||||
# List all available schemas
|
||||
openspec schema which --all
|
||||
```
|
||||
|
||||
Output shows whether it's from your project, user directory, or the package:
|
||||
|
||||
```text
|
||||
Schema: my-workflow
|
||||
Source: project
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
## Examples
|
||||
|
||||
### Rapid Iteration Workflow
|
||||
|
||||
A minimal workflow for quick iterations:
|
||||
|
||||
```yaml
|
||||
# openspec/schemas/rapid/schema.yaml
|
||||
name: rapid
|
||||
version: 1
|
||||
description: Fast iteration with minimal overhead
|
||||
|
||||
artifacts:
|
||||
- id: proposal
|
||||
generates: proposal.md
|
||||
description: Quick proposal
|
||||
template: proposal.md
|
||||
instruction: |
|
||||
Create a brief proposal for this change.
|
||||
Focus on what and why, skip detailed specs.
|
||||
requires: []
|
||||
|
||||
- id: tasks
|
||||
generates: tasks.md
|
||||
description: Implementation checklist
|
||||
template: tasks.md
|
||||
requires: [proposal]
|
||||
|
||||
apply:
|
||||
requires: [tasks]
|
||||
tracks: tasks.md
|
||||
```
|
||||
|
||||
### Adding a Review Artifact
|
||||
|
||||
Fork the default and add a review step:
|
||||
|
||||
```bash
|
||||
openspec schema fork spec-driven with-review
|
||||
```
|
||||
|
||||
Then edit `schema.yaml` to add:
|
||||
|
||||
```yaml
|
||||
- id: review
|
||||
generates: review.md
|
||||
description: Pre-implementation review checklist
|
||||
template: review.md
|
||||
instruction: |
|
||||
Create a review checklist based on the design.
|
||||
Include security, performance, and testing considerations.
|
||||
requires:
|
||||
- design
|
||||
|
||||
- id: tasks
|
||||
# ... existing tasks config ...
|
||||
requires:
|
||||
- specs
|
||||
- design
|
||||
- review # Now tasks require review too
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Community Schemas
|
||||
|
||||
OpenSpec also supports community-maintained schemas distributed via standalone repositories. These provide opinionated workflows that integrate OpenSpec with other tools or systems, similar to how [github/spec-kit's community extension catalog](https://github.com/github/spec-kit/tree/main/extensions) works for spec-kit.
|
||||
|
||||
Community schemas are not vendored into OpenSpec core — they live in their own repositories with their own release cadence. To use one, copy the schema bundle into your project's `openspec/schemas/<schema-name>/` directory (each repo's README has install instructions).
|
||||
|
||||
| Schema | Maintainer | Repository | Description |
|
||||
|--------|-----------|-----------|-------------|
|
||||
| `intent-driven` | @harikrishnan83 | [intent-driven-dev/openspec-schemas](https://github.com/intent-driven-dev/openspec-schemas/tree/main/openspec/schemas/intent-driven) | Captures change intent, observable behaviour, technical design, and durable architectural decisions before implementation. Adds a change-local ADR review manifest and writes qualifying long-lived decisions as immutable, supersedable ADRs. |
|
||||
| `superpowers-bridge` | @JiangWay | [JiangWay/openspec-schemas](https://github.com/JiangWay/openspec-schemas/tree/main/superpowers-bridge) | Integrates OpenSpec's artifact governance with [obra/superpowers](https://github.com/obra/superpowers) execution skills (brainstorming, writing-plans, TDD via subagents, code review, finishing). Adds an evidence-first `retrospective` artifact filling a gap Superpowers does not natively cover. |
|
||||
| `nanopm` | @nmrtn | [nmrtn/nanopm](https://github.com/nmrtn/nanopm/tree/main/openspec-schema) | PM-first workflow. Runs [nanopm](https://github.com/nmrtn/nanopm)'s planning pipeline (audit → strategy → roadmap → PRD) upstream of implementation. Bridges product planning to OpenSpec's spec-driven engineering workflow. Artifacts read from `.nanopm/` if present — proposal sources the audit, design sources the strategy, and tasks source the PRD breakdown. |
|
||||
| `e2e-runbooks` | @Lukk17 | [Lukk17/openspec-schemas](https://github.com/Lukk17/openspec-schemas/tree/master/openspec/schemas/e2e-runbooks) | Capability-level end-to-end test runbooks. Each capability gets an immutable spec, an immutable tasks-template, and one timestamped run record per execution. Assertions are observable behaviour only (HTTP status, response body, persisted state — never log substrings); each run records start/end UTC, duration, and best-estimate LLM token consumption. |
|
||||
| `anvil` | @jikkujoyce | [jikkujoyce/openspec-schemas](https://github.com/jikkujoyce/openspec-schemas/tree/main/schemas/anvil) | Spec-driven workflow with TDD discipline and an adversarial review step. Flow: `proposal` → `specs` → `design` → `review` → `test-plan` → `tasks` → `apply` → `verify`. `review` is written by a fresh-context, read-only reviewer (a second model when one is available) and emits a `VERDICT:` line telling the agent to gate `test-plan`, `tasks`, and `apply`; OpenSpec only checks that artifacts exist, so enforce the gate with your own CI or hook. `test-plan` maps every spec scenario to a named test and doubles as a red/green ledger that `verify` audits. |
|
||||
|
||||
> Want to contribute a community schema? Open an issue with a link to your repository, or submit a PR adding a row to this table.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [CLI Reference: Schema Commands](cli.md#schema-commands) - Full command documentation
|
||||
@@ -1,91 +0,0 @@
|
||||
# Editing & Iterating on a Change
|
||||
|
||||
**Every artifact in a change is just a Markdown file you can edit at any time.** There is no locked "planning phase," no approval gate, no special edit mode to enter. Want to change the proposal after you've started building? Open `proposal.md` and change it. Realized the design is wrong mid-implementation? Fix `design.md` and keep going. That's the whole answer, and it's by design.
|
||||
|
||||
This page is for the moment you think "wait, can I go back and change that?" Yes. Here's how, for each common case.
|
||||
|
||||
## Two ways to edit anything
|
||||
|
||||
You always have both:
|
||||
|
||||
1. **Edit the file directly.** Artifacts are plain Markdown in `openspec/changes/<name>/`. Open `proposal.md`, `design.md`, `tasks.md`, or a delta spec under `specs/` in your editor and change it. Nothing else is required.
|
||||
|
||||
2. **Ask your AI to revise it.** In chat, just say what you want: "Update the proposal to drop the caching idea and add a rate-limit section," or "the design should use a queue, not polling." The AI edits the artifact for you, using the rest of the change as context.
|
||||
|
||||
Use whichever fits the moment. Small wording tweak? Edit the file. Substantive rethink? Let the AI revise with full context.
|
||||
|
||||
## "How do I update the proposal (or specs) after I've started?"
|
||||
|
||||
Just update it. Same change, refined.
|
||||
|
||||
If you're using the expanded commands, the natural flow is: edit the artifact, then run `/opsx:continue` to pick up from the new state, or `/opsx:apply` to keep implementing against the updated plan. If you're on the default `core` commands, edit the artifact and run `/opsx:apply`; it reads the current files, so it builds against whatever the artifacts now say.
|
||||
|
||||
The mental model: artifacts are the live plan, not a signed contract. The AI always works from their current contents, so editing them steers the work.
|
||||
|
||||
```text
|
||||
You: I want to change the approach in this change.
|
||||
|
||||
You: [edit design.md, or tell the AI:]
|
||||
Update design.md to use a background job instead of a synchronous call.
|
||||
|
||||
AI: Updated design.md. The task list still fits; want me to continue applying?
|
||||
|
||||
You: /opsx:apply
|
||||
```
|
||||
|
||||
This answers a very common question: there's no separate "update proposal" command because you don't need one. The file is the source of truth, and editing it (by hand or via the AI) is the update.
|
||||
|
||||
## "How do I go back to review after implementing?"
|
||||
|
||||
You don't have to "go back," because you never left. The workflow is fluid: review, edit, and implementation aren't sequential phases you're trapped in.
|
||||
|
||||
Concretely, after some `/opsx:apply` work:
|
||||
|
||||
- Want to re-examine the plan? Open the artifacts and read them, or run `openspec show <change>` in your terminal for a consolidated view.
|
||||
- Found something to change? Edit the artifact (or ask the AI to), then continue.
|
||||
- Want a structured check that the code matches the plan? Run `/opsx:verify` (expanded command). It reports completeness, correctness, and coherence without blocking anything. See [Workflows: Verify](workflows.md#verify-check-your-work).
|
||||
|
||||
There's no "review phase" to return to, because review is something you can do at any point, including after implementation.
|
||||
|
||||
## "I edited the code by hand. How do I reconcile that with OpenSpec?"
|
||||
|
||||
This happens constantly and it's fine. You tweaked something in your editor, and now the code and the artifacts disagree. Bring them back in sync in whichever direction is true:
|
||||
|
||||
- **The code is now correct, the spec is stale.** Update the delta spec (and tasks, if relevant) to describe the behavior you actually shipped. The spec should match reality before you archive, because archiving merges the spec into your source of truth.
|
||||
- **The spec is correct, the code drifted.** Keep building or fixing until the code matches the spec.
|
||||
|
||||
A fast way to surface mismatches is `/opsx:verify`: it reads your artifacts and your code and tells you where they diverge. Treat its output as a to-do list for reconciliation, then archive once they agree.
|
||||
|
||||
The principle: at archive time, your specs become the truth of record. So before you archive, make the specs honest about what the code does. Manual edits are welcome; just don't let them quietly desync the spec.
|
||||
|
||||
## Refining a proposal you're not happy with
|
||||
|
||||
If a generated proposal misses the mark, you have three good moves:
|
||||
|
||||
- **Iterate in place.** Tell the AI what's off ("the scope is too broad, drop the admin features") and let it revise. Cheapest and usually right.
|
||||
- **Explore first, then re-propose.** If the problem is that the idea itself is unclear, step back to `/opsx:explore`, think it through, and let a sharper proposal come out of that. See [Explore First](explore.md).
|
||||
- **Start fresh.** If the intent has fundamentally changed, a new change can be clearer than patching the old one.
|
||||
|
||||
That last move has its own decision guide, next.
|
||||
|
||||
## When to update vs. start a new change
|
||||
|
||||
Short version: **update when it's the same work refined; start new when the intent fundamentally changed or the scope exploded into different work.**
|
||||
|
||||
- Same goal, better approach? Update.
|
||||
- Scope narrowing (ship the MVP now, more later)? Update, then archive, then a new change for phase two.
|
||||
- The problem itself changed ("add dark mode" became "build a full theming system")? New change.
|
||||
|
||||
There's a full flowchart and worked examples in [Workflows: When to Update vs Start Fresh](workflows.md#when-to-update-vs-start-fresh) and a deeper treatment in [OPSX: When to Update vs. Start Fresh](opsx.md#when-to-update-vs-start-fresh).
|
||||
|
||||
## A note on tasks
|
||||
|
||||
`tasks.md` is a living checklist, not a frozen plan. As you implement, you can add tasks you discover, remove ones that turned out unnecessary, or reorder them. The AI checks items off as it completes them during `/opsx:apply`, and it resumes from the first unchecked task if you come back later. Editing the list mid-flight is expected.
|
||||
|
||||
## Where to go next
|
||||
|
||||
- [Workflows](workflows.md) - patterns, plus the update-vs-new decision guide
|
||||
- [Reviewing a Change](reviewing-changes.md) - the two-minute pass on a plan before you build it
|
||||
- [Explore First](explore.md) - the place to step back to when an idea needs rethinking
|
||||
- [Commands](commands.md) - `/opsx:continue`, `/opsx:apply`, and `/opsx:verify` in detail
|
||||
- [Concepts: Artifacts](concepts.md#artifacts) - what each artifact is for
|
||||
@@ -1,224 +0,0 @@
|
||||
# Examples & Recipes
|
||||
|
||||
Real changes, start to finish. Each recipe shows the commands you'd type and what you'd see back, so you can match your situation to a pattern and copy it. These use the default **core** commands (`propose`, `explore`, `apply`, `update`, `sync`, `archive`); where the expanded set helps, it's noted.
|
||||
|
||||
A reminder before you start: slash commands like `/opsx:propose` go in your **AI assistant's chat**, and `openspec` commands go in your **terminal**. If that's new, read [How Commands Work](how-commands-work.md) first. In the transcripts below, `You:` and `AI:` are the chat, and lines starting with `$` are the terminal.
|
||||
|
||||
> **Not sure what you're building yet?** Most of these recipes are sharper if you start with `/opsx:explore` to think it through first. [Recipe 3](#recipe-3-exploring-before-you-commit) shows it in action, and the [Explore First](explore.md) guide makes the full case.
|
||||
|
||||
## Recipe 1: A small feature, the fast path
|
||||
|
||||
**When to use it:** you know what you want, and it's a contained piece of work. This is the most common recipe.
|
||||
|
||||
The whole thing is three commands. Propose, build, archive.
|
||||
|
||||
```text
|
||||
You: /opsx:propose add-logout-button
|
||||
|
||||
AI: Created openspec/changes/add-logout-button/
|
||||
✓ proposal.md — why and what
|
||||
✓ specs/ — the new requirement and its scenarios
|
||||
✓ design.md — technical approach
|
||||
✓ tasks.md — implementation checklist
|
||||
Ready for implementation. Run /opsx:apply.
|
||||
```
|
||||
|
||||
Now read the plan. Open the proposal and the delta spec. This is the moment OpenSpec is built for: catching a wrong assumption while it's still one paragraph, not 400 lines of code. Edit any artifact directly if something's off, then continue.
|
||||
|
||||
```text
|
||||
You: /opsx:apply
|
||||
|
||||
AI: Working through tasks...
|
||||
✓ 1.1 Add logout button to header
|
||||
✓ 1.2 Clear session on click
|
||||
✓ 1.3 Add confirmation dialog
|
||||
All tasks complete!
|
||||
|
||||
You: /opsx:archive
|
||||
|
||||
AI: Archiving add-logout-button...
|
||||
✓ Merged specs into openspec/specs/auth/spec.md
|
||||
✓ Moved to openspec/changes/archive/2026-06-22-add-logout-button/
|
||||
Done. Ready for the next change.
|
||||
```
|
||||
|
||||
That's it. The logout behavior is now part of your specs, and the change is filed away with its full context.
|
||||
|
||||
## Recipe 2: A bug fix
|
||||
|
||||
**When to use it:** something is broken and you want the fix recorded as a deliberate change to behavior, not a mystery commit.
|
||||
|
||||
Bug fixes work exactly like features. The difference is in how you frame the proposal: describe the *correct* behavior, not just "fix the bug."
|
||||
|
||||
```text
|
||||
You: /opsx:propose fix-login-redirect-loop
|
||||
|
||||
AI: Created openspec/changes/fix-login-redirect-loop/
|
||||
The proposal captures the current broken behavior and the
|
||||
intended behavior. The delta spec MODIFIES the redirect
|
||||
requirement so it's now precise and testable.
|
||||
Ready for implementation.
|
||||
```
|
||||
|
||||
Because the fix lands as a `MODIFIED` requirement with a fresh scenario, the next person (or the next AI session) sees not just that you fixed it, but what "correct" means. Then `/opsx:apply` and `/opsx:archive` as usual.
|
||||
|
||||
Tip: for a fix, a good scenario is the regression test in prose. "GIVEN a logged-out user, WHEN they submit valid credentials, THEN they land on the dashboard and are not redirected again." Write that, and the implementation has a clear target.
|
||||
|
||||
## Recipe 3: Exploring before you commit
|
||||
|
||||
**When to use it:** you have a problem but not yet a plan. You're not sure what to build, or which approach is right.
|
||||
|
||||
Start with `/opsx:explore`. It's a thinking partner with no structure. It never writes code, and writes nothing else unless you ask it to capture what you decided, or say yes when it offers. It reads your codebase and helps you decide.
|
||||
|
||||
```text
|
||||
You: /opsx:explore
|
||||
|
||||
AI: What would you like to explore?
|
||||
|
||||
You: Page loads feel slow but I don't know where the time goes.
|
||||
|
||||
AI: Let me look... I found three likely culprits:
|
||||
1. Large unoptimized images on the product list
|
||||
2. Synchronous data fetching that blocks render
|
||||
3. Re-renders triggered by context changes
|
||||
Which should we tackle first?
|
||||
|
||||
You: The data fetching one.
|
||||
|
||||
You: /opsx:propose optimize-product-list-fetching
|
||||
|
||||
AI: Created the change, with a proposal informed by what we just
|
||||
found. Ready for implementation.
|
||||
```
|
||||
|
||||
Exploration clarifies your thinking *before* you spend a change on it. When the insight crystallizes, propose, and the AI carries the context forward.
|
||||
|
||||
## Recipe 4: Juggling two changes at once
|
||||
|
||||
**When to use it:** you're mid-feature and an urgent fix jumps the queue.
|
||||
|
||||
Changes are independent folders, so parallel work doesn't conflict. Start the fix, ship it, then return to the feature right where you left off.
|
||||
|
||||
```text
|
||||
You: I'm partway through add-dark-mode, but I need to fix a login bug now.
|
||||
|
||||
You: /opsx:propose fix-login-redirect
|
||||
|
||||
AI: Created openspec/changes/fix-login-redirect/. Ready for implementation.
|
||||
|
||||
You: /opsx:apply
|
||||
|
||||
AI: Implemented the fix. All tasks complete.
|
||||
|
||||
You: /opsx:archive
|
||||
|
||||
AI: ✓ Archived fix-login-redirect.
|
||||
|
||||
You: Back to dark mode.
|
||||
|
||||
You: /opsx:apply add-dark-mode
|
||||
|
||||
AI: Resuming add-dark-mode. Picking up at task 2.3: Update Header...
|
||||
```
|
||||
|
||||
Naming the change in `/opsx:apply add-dark-mode` is how you point the AI at a specific change when more than one is active. Because tasks track completion in `tasks.md`, the AI knows exactly where you stopped.
|
||||
|
||||
When several changes are done at once, the expanded `/opsx:bulk-archive` files them together and resolves spec conflicts by checking what's actually implemented. See [Workflows](workflows.md#parallel-changes).
|
||||
|
||||
## Recipe 5: A refactor with no behavior change
|
||||
|
||||
**When to use it:** you're restructuring code, and externally visible behavior should stay identical.
|
||||
|
||||
This is the interesting case, because a pure refactor has *nothing to add to your specs*. The behavior contract doesn't change; only the implementation does. So the work lives in the design and tasks, and the spec delta is empty or absent.
|
||||
|
||||
```text
|
||||
You: /opsx:propose refactor-payment-module
|
||||
|
||||
AI: Created the change. The proposal states the goal (split the
|
||||
payment module, no behavior change) and the design captures
|
||||
the new structure. No spec changes, since behavior is identical.
|
||||
Ready for implementation.
|
||||
```
|
||||
|
||||
Declare the empty delta explicitly by setting `skip_specs: true` in the change's `.openspec.yaml`:
|
||||
|
||||
```yaml
|
||||
schema: spec-driven
|
||||
skip_specs: true
|
||||
```
|
||||
|
||||
Without the marker, `openspec validate` rejects a change with zero deltas (so a forgotten specs phase still gets caught); with it, validation passes and `openspec status` shows the specs stage as explicitly skipped rather than pending. If the refactor turns out to change behavior after all, remove `skip_specs` from `.openspec.yaml` and write the delta specs — validate treats the marker plus spec files as a conflict, so the stale marker can't linger silently.
|
||||
|
||||
Archiving a marked change needs no extra flags (there are no deltas to merge). Independently, the `--skip-specs` flag tells the terminal command to skip the spec step explicitly:
|
||||
|
||||
```bash
|
||||
$ openspec archive refactor-payment-module --skip-specs
|
||||
```
|
||||
|
||||
The same flag is handy for tooling, CI, and docs-only changes. The principle: specs describe behavior, so if behavior didn't change, the spec shouldn't either. See [Concepts](concepts.md#what-a-spec-is-and-is-not).
|
||||
|
||||
## Recipe 6: Step-by-step control (expanded commands)
|
||||
|
||||
**When to use it:** a complex or risky change where you want to review each artifact before moving on.
|
||||
|
||||
The core `/opsx:propose` drafts everything at once. When you'd rather go one step at a time, turn on the expanded commands:
|
||||
|
||||
```bash
|
||||
$ openspec config profile # select the expanded workflows
|
||||
$ openspec update # apply them to this project
|
||||
```
|
||||
|
||||
Now you can scaffold and build incrementally:
|
||||
|
||||
```text
|
||||
You: /opsx:new add-2fa
|
||||
|
||||
AI: Created openspec/changes/add-2fa/. Ready to create: proposal.
|
||||
|
||||
You: /opsx:continue
|
||||
|
||||
AI: Created proposal.md. Now available: specs, design.
|
||||
|
||||
You: /opsx:continue
|
||||
|
||||
AI: Created specs/auth/spec.md. Now available: design.
|
||||
```
|
||||
|
||||
Review each artifact as it lands, edit freely, and continue when you're happy. When you want the rest drafted in one go, `/opsx:ff` fast-forwards through the remaining planning artifacts. Before archiving, `/opsx:verify` checks that the implementation actually matches the specs. See [Workflows](workflows.md#opsxff-vs-opsxcontinue).
|
||||
|
||||
## Recipe 7: Learning the whole loop hands-on
|
||||
|
||||
**When to use it:** you've installed OpenSpec and want to *feel* the workflow on your own code, not a toy example.
|
||||
|
||||
Turn on the expanded commands (see Recipe 6), then:
|
||||
|
||||
```text
|
||||
You: /opsx:onboard
|
||||
|
||||
AI: Welcome to OpenSpec! I'll walk you through a complete change
|
||||
using your actual codebase. Let me scan for a small, safe
|
||||
improvement we can make together...
|
||||
```
|
||||
|
||||
`/opsx:onboard` finds a real (small) improvement, creates a change for it, implements it, and archives it, narrating every step. It takes 15 to 30 minutes and leaves you with a real change you can keep or discard. It's the gentlest way to learn. See [Commands](commands.md#opsxonboard).
|
||||
|
||||
## Checking your work from the terminal
|
||||
|
||||
Any time, from your terminal, you can inspect the state of things:
|
||||
|
||||
```bash
|
||||
$ openspec list # active changes
|
||||
$ openspec show add-dark-mode # one change in detail
|
||||
$ openspec validate add-dark-mode # check structure
|
||||
$ openspec view # interactive dashboard
|
||||
```
|
||||
|
||||
These are read-and-inspect tools. The proposing and building still happen through slash commands in chat. Full details in the [CLI reference](cli.md).
|
||||
|
||||
## Where to go next
|
||||
|
||||
- [Explore First](explore.md): the recommended way to start when you're unsure
|
||||
- [Workflows](workflows.md): the patterns above, with decision guidance on when to use each
|
||||
- [Commands](commands.md): every slash command in detail
|
||||
- [Getting Started](getting-started.md): the canonical first-change walkthrough
|
||||
- [Concepts](concepts.md): why the pieces fit together the way they do
|
||||
@@ -1,134 +0,0 @@
|
||||
# Using OpenSpec in an Existing Project
|
||||
|
||||
**You do not document your whole codebase to start. You write specs only for what you're about to change.** That's the single most important thing to know about adopting OpenSpec on an existing project, and it's why OpenSpec is built brownfield-first.
|
||||
|
||||
A common worry sounds like this: "My app is 80,000 lines old. Do I have to write specs for all of it before OpenSpec is useful?" No. You'd hate that, and so would we. OpenSpec grows your specs one change at a time. Your first change documents the slice it touches, the next change documents its slice, and over months your specs fill in naturally around the work you actually do.
|
||||
|
||||
This guide shows how to start on day one without boiling the ocean.
|
||||
|
||||
## The thirty-second version
|
||||
|
||||
```bash
|
||||
$ cd your-existing-project
|
||||
$ openspec init # adds openspec/ and your AI tool's commands
|
||||
```
|
||||
|
||||
Then, in your AI chat:
|
||||
|
||||
```text
|
||||
/opsx:explore # optional: have the AI read the area you'll touch
|
||||
/opsx:propose <a real, small change you actually need>
|
||||
/opsx:apply
|
||||
/opsx:archive
|
||||
```
|
||||
|
||||
Your specs now describe exactly the part of the system that change touched, and nothing more. That's correct. You're done worrying about the other 80,000 lines.
|
||||
|
||||
## Why delta-first is the whole trick
|
||||
|
||||
OpenSpec changes are written as **deltas**: `ADDED`, `MODIFIED`, `REMOVED`. A delta describes what's changing relative to current behavior, not the entire system.
|
||||
|
||||
This is exactly what brownfield work needs. You're rarely building from nothing. You're adding a field, fixing a redirect, tightening a timeout. A delta lets you specify that one change precisely without first writing a 40-page spec of everything around it.
|
||||
|
||||
So your `openspec/specs/` directory doesn't start full and complete. It starts nearly empty and accumulates. Each archived change merges its delta in. The spec for `auth/` becomes thorough only after you've made several auth changes, which is exactly when you want it thorough.
|
||||
|
||||
If you want the deeper mechanics, see [Concepts: Delta Specs](concepts.md#delta-specs).
|
||||
|
||||
## Your first change on a real codebase
|
||||
|
||||
Pick something small and real. Not a toy, not a rewrite. A change you were going to make this week anyway. Small first changes teach you the workflow with low stakes.
|
||||
|
||||
**Step 1: Let the AI read the relevant area.** This is where `/opsx:explore` earns its keep on an unfamiliar or large codebase. Point it at the part you're about to touch and let it map how things work before proposing anything.
|
||||
|
||||
```text
|
||||
You: /opsx:explore
|
||||
|
||||
AI: What would you like to explore?
|
||||
|
||||
You: I need to add rate limiting to our public API, but I'm not sure
|
||||
how requests currently flow through the middleware.
|
||||
|
||||
AI: Let me trace it... [reads the router, middleware stack, and config]
|
||||
Requests hit Express, pass through auth middleware, then your
|
||||
controllers. There's no rate-limiting layer today. The cleanest
|
||||
insertion point is a middleware right after auth. Want me to scope it?
|
||||
```
|
||||
|
||||
Notice the AI now understands your actual structure, so the proposal it writes will fit your code, not a generic template. On a big codebase, this single habit saves the most pain. See [Explore First](explore.md).
|
||||
|
||||
**Step 2: Propose the change.** The proposal and its delta spec capture just this change.
|
||||
|
||||
```text
|
||||
You: /opsx:propose add-api-rate-limiting
|
||||
```
|
||||
|
||||
**Step 3: Build and archive** with `/opsx:apply` and `/opsx:archive`, same as any change. After archiving, you have a real spec for your rate-limiting behavior, born from a change you needed anyway.
|
||||
|
||||
## Prefer a guided tour? Use onboard
|
||||
|
||||
If you'd rather watch the whole loop happen on your own code with narration, the expanded command `/opsx:onboard` does exactly that: it scans your codebase for a small, safe improvement, then walks you through proposing, building, and archiving it, explaining each step.
|
||||
|
||||
Turn on the expanded commands first:
|
||||
|
||||
```bash
|
||||
$ openspec config profile # select the expanded workflows
|
||||
$ openspec update # apply them to this project
|
||||
```
|
||||
|
||||
Then in chat:
|
||||
|
||||
```text
|
||||
/opsx:onboard
|
||||
```
|
||||
|
||||
It's the gentlest possible introduction on a real project, and it leaves you with a genuine (small) change you can keep or discard. See [Commands: `/opsx:onboard`](commands.md#opsxonboard).
|
||||
|
||||
## "But I already have requirements docs"
|
||||
|
||||
Maybe you have a PRD, an SRS, a formal spec, even TLA+ models. Good. You don't import them wholesale, and you don't throw them away either.
|
||||
|
||||
Treat existing docs as **source material for exploration**, not as specs to convert. When you start a change, paste or point the AI at the relevant section, and let it shape a focused OpenSpec delta from it. The delta captures the behavior you're changing now, in OpenSpec's testable requirement-and-scenario form. Your original documents stay where they are as background.
|
||||
|
||||
The honest reason: OpenSpec specs are deliberately behavior-first and scoped to changes. A 40-page PRD is a different artifact with a different job. Forcing a one-time bulk conversion tends to produce a large, stale spec nobody trusts. Letting specs grow from real changes keeps them accurate.
|
||||
|
||||
```text
|
||||
You: /opsx:explore
|
||||
You: Here's the section of our PRD about checkout. I'm implementing the
|
||||
"guest checkout" requirement next.
|
||||
[paste the relevant requirement]
|
||||
AI: [reads it, asks clarifying questions, then helps scope a change]
|
||||
You: /opsx:propose add-guest-checkout
|
||||
```
|
||||
|
||||
## Organizing specs in a big codebase
|
||||
|
||||
Specs live under `openspec/specs/`, grouped by **domain**: a logical area that matches how your team thinks about the system. You don't have to design the whole taxonomy up front. Create a domain folder when your first change in that area needs one.
|
||||
|
||||
Common ways to slice domains:
|
||||
|
||||
- **By feature area:** `auth/`, `payments/`, `search/`
|
||||
- **By component:** `api/`, `frontend/`, `workers/`
|
||||
- **By bounded context:** `ordering/`, `fulfillment/`, `inventory/`
|
||||
|
||||
Pick whatever makes a newcomer nod. You can refine later. See [Concepts: Specs](concepts.md#specs).
|
||||
|
||||
## Monorepos and work that spans repos
|
||||
|
||||
For a monorepo, the simplest model is one `openspec/` directory at the repo root, with domains that map to your packages or services. That covers most teams.
|
||||
|
||||
If your work genuinely spans **multiple repositories** (or several packages you treat as separate), OpenSpec has a beta **stores** feature: planning lives in its own standalone repo that any of your code repos can reference, so the plan does not have to live inside one repo's `openspec/` folder. It's beta, so treat its commands and state as evolving. Start with the [Stores User Guide](stores-beta/user-guide.md) for the mental model and the smallest useful path.
|
||||
|
||||
## A few honest cautions
|
||||
|
||||
- **Resist the urge to back-fill everything.** Writing specs for code you aren't changing feels productive and usually isn't. Those specs go stale, because nothing forces them to track reality. Let real changes drive your specs.
|
||||
- **Keep early changes small.** Your first few changes are as much about learning the rhythm as shipping. A tight scope makes the loop fast and the lessons cheap.
|
||||
- **Commit `openspec/` to git.** Your specs and archive belong in version control alongside the code they describe.
|
||||
- **Give the AI context.** On a large codebase with strong conventions, fill in `openspec/config.yaml`'s `context:` so every proposal respects your stack and patterns. See [Customization](customization.md#project-configuration).
|
||||
|
||||
## Where to go next
|
||||
|
||||
- [Explore First](explore.md) - the key habit for understanding code before you change it
|
||||
- [Getting Started](getting-started.md) - the full first-change walkthrough
|
||||
- [Editing & Iterating on a Change](editing-changes.md) - adjusting a change as you learn
|
||||
- [Concepts: Delta Specs](concepts.md#delta-specs) - why deltas make brownfield work clean
|
||||
- [Customization](customization.md) - teach OpenSpec your project's conventions
|
||||
-127
@@ -1,127 +0,0 @@
|
||||
# Explore First
|
||||
|
||||
**`/opsx:explore` is your thinking partner. Reach for it whenever you have a problem but not yet a plan.** It investigates your codebase, weighs options with you, and clarifies what you actually want, all before a line of code is written. When the picture is clear, it hands off to `/opsx:propose`.
|
||||
|
||||
If you take one habit from these docs, take this one: **when you're not sure, explore before you propose.**
|
||||
|
||||
Here's why that matters. AI coding assistants are eager. Ask vaguely and they'll confidently build *something*, just maybe not the thing you needed. Explore is the cure. It's a no-stakes conversation where you and the AI figure out the right move together, so that by the time you propose, you're proposing the right thing.
|
||||
|
||||
## When to explore
|
||||
|
||||
Explore is the right first step more often than people expect. Use it when any of these is true:
|
||||
|
||||
- You know the *problem* but not the *solution*. ("Pages feel slow." "Auth is a mess." "We keep getting duplicate orders.")
|
||||
- You're choosing between approaches and want the tradeoffs laid out against your actual code.
|
||||
- You're new to a codebase and need to understand how something works before you change it.
|
||||
- The requirements are fuzzy and you want to sharpen them before committing.
|
||||
- You suspect the work is bigger or smaller than it looks and want to scope it honestly.
|
||||
|
||||
Skip explore only when you already know exactly what you want and how. In that case go straight to [`/opsx:propose`](commands.md#opsxpropose).
|
||||
|
||||
## What it does (and doesn't)
|
||||
|
||||
Explore is a **conversation**, not a generator.
|
||||
|
||||
**It does:**
|
||||
- Read and search your codebase to answer real questions.
|
||||
- Compare options and name the tradeoffs of each.
|
||||
- Draw diagrams to make a design legible.
|
||||
- Help you narrow a vague idea into a concrete, buildable scope.
|
||||
- Capture the exploration when you ask, or when you accept its offer: it scaffolds the change with `openspec new change` and writes the planning artifacts you named, or updates an existing change's artifacts.
|
||||
- Transition to `/opsx:propose` when you're ready.
|
||||
|
||||
**It does not:**
|
||||
- Write or modify code. Explore never writes code, on any path, capture included.
|
||||
- Design or edit your schemas or templates. Shaping those is a change, not thinking.
|
||||
- Start a change or write an artifact on its own. It writes nothing unless you ask, or say yes when it offers, and then only what you agreed to, plus the setup files starting a change needs (see below).
|
||||
- Push you toward capturing. It offers when the thinking crystallizes; you decide.
|
||||
|
||||
That's the point. Exploring costs you nothing and commits you to nothing until you say so. You can explore three dead ends, learn something from each, and only then propose the path that survived.
|
||||
|
||||
## It's already installed
|
||||
|
||||
Good news: `/opsx:explore` ships in the default **core** profile, right alongside `propose`, `apply`, `update`, `sync`, and `archive`. You don't need to enable anything. If OpenSpec is set up in your project, explore is ready in your AI chat. (As with all `/opsx:*` commands, you type it in your assistant's chat, not the terminal. See [How Commands Work](how-commands-work.md).)
|
||||
|
||||
## A full example
|
||||
|
||||
Watch how a vague worry becomes a sharp, buildable change.
|
||||
|
||||
```text
|
||||
You: /opsx:explore
|
||||
|
||||
AI: What would you like to explore?
|
||||
|
||||
You: Our checkout sometimes creates duplicate orders. I don't know why
|
||||
and I don't know how to fix it safely.
|
||||
|
||||
AI: Let me dig into the checkout path...
|
||||
[reads the order service, the payment webhook handler, and the
|
||||
client submit logic]
|
||||
|
||||
Here's what I found. There are two ways a duplicate can happen:
|
||||
|
||||
1. The client can submit twice (double-click, retry on slow network).
|
||||
Nothing debounces it.
|
||||
2. The payment webhook can fire more than once, and the handler
|
||||
creates an order each time. There's no idempotency key.
|
||||
|
||||
Cause #2 is the dangerous one: it can charge and fulfill twice.
|
||||
|
||||
Three ways to fix it, roughly in order of robustness:
|
||||
- Idempotency key on the order-creation endpoint (handles both causes)
|
||||
- Dedup on the webhook by payment-intent id (handles #2 only)
|
||||
- Client-side debounce (handles #1 only, papers over the real bug)
|
||||
|
||||
Given your code already stores the payment-intent id, the
|
||||
idempotency-key approach is a small change with the biggest payoff.
|
||||
Want me to scope that?
|
||||
|
||||
You: Yes, let's do the idempotency key.
|
||||
|
||||
You: /opsx:propose add-order-idempotency-key
|
||||
|
||||
AI: Created openspec/changes/add-order-idempotency-key/, with a proposal
|
||||
and delta spec grounded in what we just found. Ready for implementation.
|
||||
```
|
||||
|
||||
Notice what happened. The starting point was "something is wrong and I'm scared to touch it." Twenty seconds of exploration turned that into a named root cause, three ranked options, a recommendation tied to the existing code, and a precise change. The proposal that follows is sharp because the thinking happened first.
|
||||
|
||||
## Handing off to propose
|
||||
|
||||
Explore doesn't archive into anything. When you're ready, you simply start a change, and the AI carries the context from your conversation into the artifacts.
|
||||
|
||||
```text
|
||||
explore ──► propose ──► apply ──► archive
|
||||
(think) (agree) (build) (record)
|
||||
```
|
||||
|
||||
You can say it in plain language ("let's turn this into a change") or run `/opsx:propose <name>` directly. Either way, the exploration you just did becomes the foundation of the proposal, not throwaway chat.
|
||||
|
||||
You can also ask explore to capture the change itself, without leaving the conversation: "start a change for this" scaffolds the folder, and "write the proposal too" writes exactly the artifacts you named. Scaffolding also lays down the change's own metadata, and fills in anything your project is missing at the top level (`openspec/specs/`, `openspec/changes/archive/`, a `config.yaml`).
|
||||
|
||||
That's the same destination as handing off, with one difference: propose writes the whole set your schema requires to reach implementation, while capture writes only the artifacts you named.
|
||||
|
||||
If you use the expanded command set, explore can hand off to `/opsx:new` instead, for step-by-step artifact creation. See [Workflows](workflows.md).
|
||||
|
||||
## Tips for a good exploration
|
||||
|
||||
- **Bring the problem, not the solution.** "Logins feel slow" gives the AI room to investigate. "Add a Redis cache" pre-commits you to an answer you haven't tested yet.
|
||||
- **Ask for the tradeoffs out loud.** "What are the downsides of each option?" gets you a more honest comparison.
|
||||
- **Let it read first.** The best explorations start with the AI actually looking at your code, not guessing. Point it at the relevant area if it helps.
|
||||
- **It's okay to bail.** If exploration reveals the idea isn't worth it, that's a win. You learned it cheaply.
|
||||
- **Explore again mid-change.** Stuck during `/opsx:apply`? You can step back and explore a sub-problem, then return.
|
||||
|
||||
## The honest tradeoffs
|
||||
|
||||
**What you gain:** explore catches wrong turns at the cheapest possible moment, before you've committed to anything. It's especially powerful in unfamiliar code, where the AI's ability to read and summarize the system saves you an afternoon of spelunking.
|
||||
|
||||
**What it costs:** a little patience. Explore is a conversation, so it's slower than firing off `/opsx:propose` and hoping. For work you genuinely understand already, that extra step is pure overhead, and you should skip it.
|
||||
|
||||
The rule of thumb: the fuzzier the task, the more explore pays off. The clearer the task, the more you can skip straight to proposing.
|
||||
|
||||
## Where to go next
|
||||
|
||||
- [Commands: `/opsx:explore`](commands.md#opsxexplore): the precise reference
|
||||
- [Workflows](workflows.md): explore as part of the everyday loop
|
||||
- [Examples & Recipes](examples.md#recipe-3-exploring-before-you-commit): explore in a full walkthrough
|
||||
- [Getting Started](getting-started.md): the first-change guide, exploration included
|
||||
-155
@@ -1,155 +0,0 @@
|
||||
# FAQ
|
||||
|
||||
Quick answers to the questions people ask most. If your question is really a "something is broken" question, [Troubleshooting](troubleshooting.md) is the better page. If you want a term defined, see the [Glossary](glossary.md).
|
||||
|
||||
## The basics
|
||||
|
||||
### What is OpenSpec, in one sentence?
|
||||
|
||||
A lightweight layer that gets you and your AI coding assistant to agree on what to build, in writing, before any code is written.
|
||||
|
||||
### Why would I want that?
|
||||
|
||||
Because AI assistants are confident even when they're wrong. When the requirements live only in a chat thread, the AI fills gaps with guesses, and you find out after the code exists. OpenSpec moves the agreement earlier, where mistakes are cheap to fix. See [Core Concepts at a Glance](overview.md) for the full case.
|
||||
|
||||
### Do I have to use it for everything?
|
||||
|
||||
No. Use it where agreement matters, which is most non-trivial work. For a one-character typo fix, the ceremony probably isn't worth it, and that's fine.
|
||||
|
||||
### Can I use it on a big existing codebase, or only new projects?
|
||||
|
||||
Existing codebases are the main event. OpenSpec is brownfield-first: you do not document your whole app up front. You write specs only for what each change touches, and your specs fill in over time around the work you actually do. There's a dedicated guide: [Using OpenSpec in an Existing Project](existing-projects.md).
|
||||
|
||||
### Is it tied to one AI tool?
|
||||
|
||||
No. OpenSpec works with 30+ assistants, including Claude Code, Cursor, Devin Desktop, GitHub Copilot, Gemini CLI, Codex, and more. The full list and per-tool details are in [Supported Tools](supported-tools.md).
|
||||
|
||||
## Running commands
|
||||
|
||||
### Where do I type `/opsx:propose`?
|
||||
|
||||
In your AI assistant's chat, not your terminal. This is the single most common point of confusion, so it has its own page: [How Commands Work](how-commands-work.md). Short version: `openspec ...` runs in the terminal, `/opsx:...` runs in chat.
|
||||
|
||||
### How do I "start interactive mode"?
|
||||
|
||||
There isn't a separate mode to start. You open your AI assistant like normal and type a slash command into its chat. The slash command is how you "enter" OpenSpec. (The one genuinely interactive terminal feature is `openspec view`, a dashboard for browsing specs and changes.) Full explanation in [How Commands Work](how-commands-work.md).
|
||||
|
||||
### I typed a slash command and nothing happened. Why?
|
||||
|
||||
Most likely you typed it in the terminal instead of your AI chat, you used a spelling your tool doesn't register, or the commands aren't installed yet. If the files are missing — or you never set the tool up — run `openspec init`; `openspec update` only refreshes files that already exist. Then restart your assistant and use the form printed under "Getting started" — see [How To Invoke](supported-tools.md#how-to-invoke). [Troubleshooting](troubleshooting.md#commands-dont-show-up) has the full checklist.
|
||||
|
||||
### Why is the syntax `/opsx:propose` in one tool and `/opsx-propose` in another?
|
||||
|
||||
Each AI tool surfaces custom commands a little differently, and OpenSpec spells them the way your tool loads the file it wrote. A command file named `opsx-propose.md` is typed `/opsx-propose`; one filed under `commands/opsx/` is typed `/opsx:propose`. Tools that take skills instead of commands use the skill name — Codex needs `$openspec-propose`, Kimi Code `/skill:openspec-propose`. The `openspec init` "Getting started" line already prints the right form for the tools you picked; the full table is in [How To Invoke](supported-tools.md#how-to-invoke).
|
||||
|
||||
### What's the difference between a skill and a command?
|
||||
|
||||
Both are files OpenSpec writes so your assistant can run the workflow. Skills (`.../skills/openspec-*/SKILL.md`) are the newer cross-tool standard; commands (`.../commands/opsx-*`) are the older per-tool slash files. You don't need to pick. You just type the slash command, and OpenSpec installs whichever your tool uses.
|
||||
|
||||
## The workflow
|
||||
|
||||
### Where should I start if I'm not sure what to build?
|
||||
|
||||
With `/opsx:explore`. It's a no-stakes thinking partner that reads your codebase, lays out options, and turns a fuzzy problem into a concrete plan, all before any code gets written. It's in the default profile, so it's always available. When the plan is clear, it hands off to `/opsx:propose`. This is the single best habit to form, because it stops an eager AI from confidently building the wrong thing. See [Explore First](explore.md).
|
||||
|
||||
### What's the simplest possible flow?
|
||||
|
||||
```text
|
||||
/opsx:explore (optional) then /opsx:propose <what you want> then /opsx:apply then /opsx:archive
|
||||
```
|
||||
|
||||
Explore to think it through, propose to draft the plan, apply to build it, archive to file it away. Skip explore when you already know exactly what you want.
|
||||
|
||||
### What's the difference between `/opsx:propose` and `/opsx:new`?
|
||||
|
||||
`/opsx:propose` is the default one-step command: it creates the change and drafts all the planning artifacts at once. `/opsx:new` is part of the expanded command set and only scaffolds an empty change, leaving you to create artifacts one at a time with `/opsx:continue` (or all at once with `/opsx:ff`). Use propose unless you want step-by-step control. See [Commands](commands.md).
|
||||
|
||||
### What are `core` and expanded profiles?
|
||||
|
||||
A profile decides which slash commands get installed. **Core** (the default) gives you `propose`, `explore`, `apply`, `update`, `sync`, `archive`. The **expanded** set adds `new`, `continue`, `ff`, `verify`, `bulk-archive`, and `onboard` for finer control. Switch with `openspec config profile`, then apply with `openspec update`.
|
||||
|
||||
### Do I need to run `/opsx:sync`?
|
||||
|
||||
Usually not. Sync merges a change's delta specs into your main specs, and `/opsx:archive` will offer to do it for you. Run sync manually only when you want the specs merged before archiving, for example on a long-running change. See [Commands](commands.md#opsxsync).
|
||||
|
||||
### How do I edit a proposal, spec, or task after I've started?
|
||||
|
||||
Just edit the file. Every artifact is plain Markdown in `openspec/changes/<name>/`, and there's no locked phase or special edit mode. Change it by hand, or ask your AI to revise it ("update the design to use a queue"), then keep going. The AI always works from the current file contents. Full guide: [Editing & Iterating on a Change](editing-changes.md).
|
||||
|
||||
### Can I go back and change the plan after implementing some of it?
|
||||
|
||||
Yes, at any time. The workflow is fluid, so review and editing aren't phases you get locked out of. Edit the artifact, then continue. If you want a structured check that the code still matches the plan, run `/opsx:verify`. See [Editing & Iterating on a Change](editing-changes.md#how-do-i-go-back-to-review-after-implementing).
|
||||
|
||||
### I edited the code by hand. How do I reconcile it with the spec?
|
||||
|
||||
Bring them back in sync before you archive, since archiving makes your specs the record of truth. If the code is now correct, update the delta spec to match what you shipped; if the spec is correct, keep building until the code agrees. `/opsx:verify` surfaces the mismatches. See [Editing & Iterating on a Change](editing-changes.md#i-edited-the-code-by-hand-how-do-i-reconcile-that-with-openspec).
|
||||
|
||||
### When should I update an existing change versus start a new one?
|
||||
|
||||
Update when it's the same work, refined. Start fresh when the intent fundamentally changed or the scope exploded into different work. There's a decision flowchart and examples in [Workflows](workflows.md#when-to-update-vs-start-fresh).
|
||||
|
||||
### What if my session runs out of context, or requirements change mid-implementation?
|
||||
|
||||
This is where specs earn their keep. Because the plan lives in files (not only in chat history), you can clear your context, start a fresh AI session, and pick up with `/opsx:apply`; it reads the artifacts and resumes from the first unchecked task. If requirements change, edit the artifacts to match the new reality and continue. Keeping a clean context window also produces better results; clear it before implementation.
|
||||
|
||||
### Should I commit the `openspec/` folder to git?
|
||||
|
||||
Yes. Your specs, active changes, and archive are part of your project's history. Commit them like any other source. The archive in particular becomes a durable record of why your system works the way it does.
|
||||
|
||||
## Specs and changes
|
||||
|
||||
### What goes in a spec versus a design?
|
||||
|
||||
A spec describes observable behavior: what the system does, its inputs, outputs, and error conditions. A design describes how you'll build it: the technical approach, architecture decisions, file changes. If implementation could change without changing externally visible behavior, it belongs in the design, not the spec. [Concepts](concepts.md#what-a-spec-is-and-is-not) goes deeper.
|
||||
|
||||
### What's a delta spec?
|
||||
|
||||
A spec that describes only what's changing, using `ADDED`, `MODIFIED`, and `REMOVED` sections, rather than restating the whole spec. It's how OpenSpec handles edits to existing systems cleanly. See [Concepts](concepts.md#delta-specs).
|
||||
|
||||
### Where do archived changes go?
|
||||
|
||||
To `openspec/changes/archive/YYYY-MM-DD-<name>/`, with all change artifacts preserved. The change moves out of your active list. A change that explicitly declares `retire_capabilities: true` can also delete a main capability spec when it removes that capability's final requirement.
|
||||
|
||||
## Configuration and customization
|
||||
|
||||
### How do I tell the AI about my tech stack?
|
||||
|
||||
Put it in `openspec/config.yaml` under `context:`. That text is injected into every planning request, so the AI always knows your stack and conventions. See [Customization](customization.md#project-configuration).
|
||||
|
||||
### Can I generate specs in a language other than English?
|
||||
|
||||
Yes. Add a language instruction to your config's `context:`. [Multi-Language](multi-language.md) has copy-paste snippets for several languages.
|
||||
|
||||
### Can I change the workflow itself?
|
||||
|
||||
Yes, with custom schemas. A schema defines which artifacts exist and how they depend on each other. Fork the default with `openspec schema fork spec-driven my-workflow`, then edit it. See [Customization](customization.md#custom-schemas).
|
||||
|
||||
## Models, privacy, and upgrades
|
||||
|
||||
### Which AI model should I use?
|
||||
|
||||
OpenSpec works best with high-reasoning models. The README recommends models like Codex 5.5 and Opus 4.7 for both planning and implementation. Also keep your context window clean: clear it before implementation for best results.
|
||||
|
||||
### Does OpenSpec collect data?
|
||||
|
||||
It collects anonymous usage stats: command names and version only. No arguments, paths, content, or personal data, and it's off automatically in CI. Opt out with `export OPENSPEC_TELEMETRY=0` or `export DO_NOT_TRACK=1`.
|
||||
|
||||
### How do I upgrade?
|
||||
|
||||
Two steps. Upgrade the package (`npm install -g @fission-ai/openspec@latest`), then run `openspec update` inside each project to refresh the generated skills and commands.
|
||||
|
||||
### How do I uninstall OpenSpec?
|
||||
|
||||
There's no uninstall command, because it's just a global package plus files in your project. Remove the package (`npm uninstall -g @fission-ai/openspec`), and optionally delete the `openspec/` directory and the generated tool files. Step-by-step, including what's safe to keep, is in [Installation: Uninstalling](installation.md#uninstalling).
|
||||
|
||||
## Getting help
|
||||
|
||||
### Where do I ask questions or report bugs?
|
||||
|
||||
- **Discord:** [discord.gg/YctCnvvshC](https://discord.gg/YctCnvvshC)
|
||||
- **GitHub Issues:** [github.com/Fission-AI/OpenSpec/issues](https://github.com/Fission-AI/OpenSpec/issues)
|
||||
- **From your terminal:** `openspec feedback "your message"` opens a GitHub issue for you.
|
||||
|
||||
### These docs are wrong or confusing. What do I do?
|
||||
|
||||
Tell us, or fix it. Documentation PRs are welcome and valued. Open an issue or send a pull request.
|
||||
@@ -1,291 +0,0 @@
|
||||
# Getting Started
|
||||
|
||||
This guide explains how OpenSpec works after you've installed and initialized it. For installation instructions, see the [main README](../README.md#quick-start) or the [Installation guide](installation.md). New to the whole docs set? The [documentation home](README.md) maps everything.
|
||||
|
||||
> **Where do I type these commands?** Two places, and mixing them up is the most common early stumble.
|
||||
>
|
||||
> - `openspec ...` commands (like `openspec init`) run in your **terminal**.
|
||||
> - `/opsx:...` commands (like `/opsx:propose`) run in your **AI assistant's chat**, the same box where you'd ask it to write code.
|
||||
>
|
||||
> There's no separate "interactive mode" to start. You just type the slash command in chat and your assistant takes it from there. Full explanation: [How Commands Work](how-commands-work.md).
|
||||
|
||||
## Your First Five Minutes
|
||||
|
||||
The whole loop, with each step labeled by where it happens:
|
||||
|
||||
```text
|
||||
TERMINAL $ npm install -g @fission-ai/openspec@latest
|
||||
TERMINAL $ cd your-project && openspec init
|
||||
AI CHAT /opsx:explore (optional: think it through first)
|
||||
AI CHAT /opsx:propose add-dark-mode (AI drafts the plan; you review it)
|
||||
AI CHAT /opsx:apply (AI builds it)
|
||||
AI CHAT /opsx:archive (specs updated, change filed away)
|
||||
```
|
||||
|
||||
Two terminal steps to set up, then you live in chat. The rest of this guide unpacks what each step does and what you'll see.
|
||||
|
||||
**Don't want to do the terminal part yourself?** Paste the [setup prompt](installation.md#install-with-your-ai-assistant) into your assistant and it handles both lines, then reports what it created.
|
||||
|
||||
> **Not sure what to build yet? Start with `/opsx:explore`.** It's a no-stakes thinking partner that reads your codebase, weighs options, and sharpens a fuzzy idea into a concrete plan, all before any code gets written. When the picture is clear, it hands off to `/opsx:propose`. This is the single best habit for working with an AI that will otherwise confidently build the wrong thing. See the [Explore guide](explore.md).
|
||||
|
||||
## How It Works
|
||||
|
||||
OpenSpec helps you and your AI coding assistant agree on what to build before any code is written.
|
||||
|
||||
**Default quick path (core profile):**
|
||||
|
||||
```text
|
||||
/opsx:explore ──► /opsx:propose ──► /opsx:apply ──► /opsx:sync ──► /opsx:archive
|
||||
(optional)
|
||||
```
|
||||
|
||||
Start with `/opsx:explore` when you're figuring out what to do, or jump straight to `/opsx:propose` when you already know. Explore is in the default profile, so it's always there when you want it.
|
||||
|
||||
**Expanded path (custom workflow selection):**
|
||||
|
||||
```text
|
||||
/opsx:new ──► /opsx:ff or /opsx:continue ──► /opsx:apply ──► /opsx:verify ──► /opsx:archive
|
||||
```
|
||||
|
||||
The default global profile is `core`, which includes `propose`, `explore`, `apply`, `update`, `sync`, and `archive`. You can enable the expanded workflow commands with `openspec config profile` and then `openspec update`.
|
||||
|
||||
## What OpenSpec Creates
|
||||
|
||||
After running `openspec init`, your project has this structure:
|
||||
|
||||
```
|
||||
openspec/
|
||||
├── specs/ # Source of truth (your system's behavior)
|
||||
│ └── <domain>/
|
||||
│ └── spec.md
|
||||
├── changes/ # Proposed updates (one folder per change)
|
||||
│ └── <change-name>/
|
||||
│ ├── proposal.md
|
||||
│ ├── design.md
|
||||
│ ├── tasks.md
|
||||
│ └── specs/ # Delta specs (what's changing)
|
||||
│ └── <domain>/
|
||||
│ └── spec.md
|
||||
└── config.yaml # Project configuration (optional)
|
||||
```
|
||||
|
||||
**Two key directories:**
|
||||
|
||||
- **`specs/`** - The source of truth. These specs describe how your system currently behaves. Organized by domain (e.g., `specs/auth/`, `specs/payments/`).
|
||||
|
||||
- **`changes/`** - Proposed modifications. Each change gets its own folder with all related artifacts. When a change is complete, its specs merge into the main `specs/` directory.
|
||||
|
||||
## Understanding Artifacts
|
||||
|
||||
Each change folder contains artifacts that guide the work:
|
||||
|
||||
| Artifact | Purpose |
|
||||
|----------|---------|
|
||||
| `proposal.md` | The "why" and "what" - captures intent, scope, and approach |
|
||||
| `specs/` | Delta specs showing ADDED/MODIFIED/REMOVED requirements |
|
||||
| `design.md` | The "how" - technical approach and architecture decisions |
|
||||
| `tasks.md` | Implementation checklist with checkboxes |
|
||||
|
||||
**Artifacts build on each other:**
|
||||
|
||||
```
|
||||
proposal ──► specs ──► design ──► tasks ──► implement
|
||||
▲ ▲ ▲ │
|
||||
└───────────┴──────────┴────────────────────┘
|
||||
update as you learn
|
||||
```
|
||||
|
||||
You can always go back and refine earlier artifacts as you learn more during implementation.
|
||||
|
||||
## How Delta Specs Work
|
||||
|
||||
Delta specs are the key concept in OpenSpec. They show what's changing relative to your current specs.
|
||||
|
||||
### The Format
|
||||
|
||||
Delta specs use sections to indicate the type of change:
|
||||
|
||||
```markdown
|
||||
# Delta for Auth
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Two-Factor Authentication
|
||||
The system MUST require a second factor during login.
|
||||
|
||||
#### Scenario: OTP required
|
||||
- GIVEN a user with 2FA enabled
|
||||
- WHEN the user submits valid credentials
|
||||
- THEN an OTP challenge is presented
|
||||
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: Session Timeout
|
||||
The system SHALL expire sessions after 30 minutes of inactivity.
|
||||
(Previously: 60 minutes)
|
||||
|
||||
#### Scenario: Idle timeout
|
||||
- GIVEN an authenticated session
|
||||
- WHEN 30 minutes pass without activity
|
||||
- THEN the session is invalidated
|
||||
|
||||
## REMOVED Requirements
|
||||
|
||||
### Requirement: Remember Me
|
||||
(Deprecated in favor of 2FA)
|
||||
```
|
||||
|
||||
### What Happens on Archive
|
||||
|
||||
When you archive a change:
|
||||
|
||||
1. **ADDED** requirements are appended to the main spec
|
||||
2. **MODIFIED** requirements replace the existing version
|
||||
3. **REMOVED** requirements are deleted from the main spec
|
||||
|
||||
The change folder moves to `openspec/changes/archive/` for audit history.
|
||||
|
||||
## Example: Your First Change
|
||||
|
||||
Let's walk through adding dark mode to an application.
|
||||
|
||||
### 1. Start the Change (Default)
|
||||
|
||||
```text
|
||||
You: /opsx:propose add-dark-mode
|
||||
|
||||
AI: Created openspec/changes/add-dark-mode/
|
||||
✓ proposal.md — why we're doing this, what's changing
|
||||
✓ specs/ — requirements and scenarios
|
||||
✓ design.md — technical approach
|
||||
✓ tasks.md — implementation checklist
|
||||
Ready for implementation!
|
||||
```
|
||||
|
||||
If you've enabled the expanded workflow profile, you can also do this as two steps: `/opsx:new` then `/opsx:ff` (or `/opsx:continue` incrementally).
|
||||
|
||||
### 2. What Gets Created
|
||||
|
||||
**proposal.md** - Captures the intent:
|
||||
|
||||
```markdown
|
||||
# Proposal: Add Dark Mode
|
||||
|
||||
## Intent
|
||||
Users have requested a dark mode option to reduce eye strain
|
||||
during nighttime usage.
|
||||
|
||||
## Scope
|
||||
- Add theme toggle in settings
|
||||
- Support system preference detection
|
||||
- Persist preference in localStorage
|
||||
|
||||
## Approach
|
||||
Use CSS custom properties for theming with a React context
|
||||
for state management.
|
||||
```
|
||||
|
||||
**specs/ui/spec.md** - Delta showing new requirements:
|
||||
|
||||
```markdown
|
||||
# Delta for UI
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Theme Selection
|
||||
The system SHALL allow users to choose between light and dark themes.
|
||||
|
||||
#### Scenario: Manual toggle
|
||||
- GIVEN a user on any page
|
||||
- WHEN the user clicks the theme toggle
|
||||
- THEN the theme switches immediately
|
||||
- AND the preference persists across sessions
|
||||
|
||||
#### Scenario: System preference
|
||||
- GIVEN a user with no saved preference
|
||||
- WHEN the application loads
|
||||
- THEN the system's preferred color scheme is used
|
||||
```
|
||||
|
||||
**tasks.md** - Implementation checklist:
|
||||
|
||||
```markdown
|
||||
# Tasks
|
||||
|
||||
## 1. Theme Infrastructure
|
||||
- [ ] 1.1 Create ThemeContext with light/dark state
|
||||
- [ ] 1.2 Add CSS custom properties for colors
|
||||
- [ ] 1.3 Implement localStorage persistence
|
||||
|
||||
## 2. UI Components
|
||||
- [ ] 2.1 Create ThemeToggle component
|
||||
- [ ] 2.2 Add toggle to settings page
|
||||
- [ ] 2.3 Update Header to include quick toggle
|
||||
|
||||
## 3. Styling
|
||||
- [ ] 3.1 Define dark theme color palette
|
||||
- [ ] 3.2 Update components to use CSS variables
|
||||
```
|
||||
|
||||
### 3. Implement
|
||||
|
||||
```
|
||||
You: /opsx:apply
|
||||
|
||||
AI: Working through tasks...
|
||||
✓ 1.1 Created ThemeContext with light/dark state
|
||||
✓ 1.2 Added CSS custom properties to globals.css
|
||||
✓ 1.3 Implemented localStorage persistence
|
||||
✓ 2.1 Created ThemeToggle component
|
||||
...
|
||||
All tasks complete!
|
||||
```
|
||||
|
||||
During implementation, if you discover the design needs adjustment, just update the artifact and continue.
|
||||
|
||||
### 4. Archive
|
||||
|
||||
```
|
||||
You: /opsx:archive
|
||||
|
||||
AI: Archiving add-dark-mode...
|
||||
✓ Merged specs into openspec/specs/ui/spec.md
|
||||
✓ Moved to openspec/changes/archive/2025-01-24-add-dark-mode/
|
||||
Done! Ready for the next feature.
|
||||
```
|
||||
|
||||
Your delta specs are now part of the main specs, documenting how your system works.
|
||||
|
||||
## Verifying and Reviewing
|
||||
|
||||
Use the CLI to check on your changes:
|
||||
|
||||
```bash
|
||||
# List active changes
|
||||
openspec list
|
||||
|
||||
# View change details
|
||||
openspec show add-dark-mode
|
||||
|
||||
# Validate spec formatting
|
||||
openspec validate add-dark-mode
|
||||
|
||||
# Interactive dashboard
|
||||
openspec view
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Explore First](explore.md) - Use `/opsx:explore` to think through an idea before you commit
|
||||
- [Reviewing a Change](reviewing-changes.md) - What to check in the plan the AI drafts, before any code
|
||||
- [Writing Good Specs](writing-specs.md) - What a strong requirement and scenario look like
|
||||
- [Using OpenSpec in an Existing Project](existing-projects.md) - Start on a large brownfield codebase
|
||||
- [Editing & Iterating on a Change](editing-changes.md) - Update artifacts, go back, reconcile manual edits
|
||||
- [Core Concepts at a Glance](overview.md) - The whole mental model on one page
|
||||
- [Examples & Recipes](examples.md) - Real changes, start to finish
|
||||
- [Workflows](workflows.md) - Common patterns and when to use each command
|
||||
- [Commands](commands.md) - Full reference for all slash commands
|
||||
- [Concepts](concepts.md) - Deeper understanding of specs, changes, and schemas
|
||||
- [Customization](customization.md) - Make OpenSpec work your way
|
||||
- [Stores](stores-beta/user-guide.md) - Planning that spans repos or teams? Keep it in its own repo (beta)
|
||||
- [FAQ](faq.md) and [Troubleshooting](troubleshooting.md) - When you get stuck
|
||||
@@ -1,91 +0,0 @@
|
||||
# Glossary
|
||||
|
||||
Every OpenSpec term in one place, defined in plain language. Skim it once and the rest of the docs read faster.
|
||||
|
||||
Terms are grouped by topic, then alphabetized within each group.
|
||||
|
||||
## The core nouns
|
||||
|
||||
**Spec.** A document describing how part of your system behaves. Specs live in `openspec/specs/`, are organized by domain, and are made of requirements and scenarios. The spec is the agreed-upon answer to "what does this software do?" See [Concepts](concepts.md#specs).
|
||||
|
||||
**Source of truth.** The `openspec/specs/` directory as a whole. It holds the current, agreed-upon behavior of your system. Changes propose edits to it; archiving applies them.
|
||||
|
||||
**Change.** One unit of work, packaged as a folder under `openspec/changes/<name>/`. A change holds everything about that work: its proposal, design, tasks, and the spec edits it introduces. One change, one feature or fix.
|
||||
|
||||
**Artifact.** A document inside a change. The standard artifacts are the proposal, the delta specs, the design, and the tasks. They're created in dependency order and feed into each other.
|
||||
|
||||
**Delta spec.** A spec inside a change that describes only what's changing, using `ADDED`, `MODIFIED`, and `REMOVED` sections, rather than restating the entire spec. This is what lets OpenSpec edit existing systems cleanly. See [Concepts](concepts.md#delta-specs).
|
||||
|
||||
**Domain.** A logical grouping for specs, like `auth/`, `payments/`, or `ui/`. You choose domains that match how you think about your system.
|
||||
|
||||
## Inside a spec
|
||||
|
||||
**Requirement.** A single behavior the system must have, usually written with an RFC 2119 keyword: "The system SHALL expire sessions after 30 minutes." Requirements state the *what*, not the *how*.
|
||||
|
||||
**Scenario.** A concrete, testable example of a requirement in action, typically in Given/When/Then form. Scenarios make a requirement verifiable: you could write an automated test from one.
|
||||
|
||||
**RFC 2119 keywords.** The words MUST, SHALL, SHOULD, and MAY, which carry standardized meaning about how strict a requirement is. MUST and SHALL are absolute. SHOULD is recommended with room for exceptions. MAY is optional. The name comes from the internet standards document that defined them.
|
||||
|
||||
## The artifacts
|
||||
|
||||
**Proposal (`proposal.md`).** The *why* and *what* of a change: its intent, scope, and high-level approach. The first artifact you create.
|
||||
|
||||
**Design (`design.md`).** The *how*: technical approach, architecture decisions, and the files you expect to touch. Optional for simple changes.
|
||||
|
||||
**Tasks (`tasks.md`).** The implementation checklist, with checkboxes. The AI works through it during `/opsx:apply` and checks items off as it goes.
|
||||
|
||||
## The lifecycle
|
||||
|
||||
**Archive.** The act of finishing a change. Its delta specs merge into the main specs, and the change folder moves to `openspec/changes/archive/YYYY-MM-DD-<name>/`. After archiving, your specs describe the new reality. See [Concepts](concepts.md#archive).
|
||||
|
||||
**Sync.** Merging a change's delta specs into the main specs *without* archiving the change. Usually automatic (archive offers to do it), but available on its own as `/opsx:sync` for long-running changes. See [Commands](commands.md#opsxsync).
|
||||
|
||||
## Workflow and commands
|
||||
|
||||
**OPSX.** The current standard OpenSpec workflow, built around fluid actions instead of rigid phases. Its slash commands all start with `/opsx:`. See [OPSX Workflow](opsx.md).
|
||||
|
||||
**Slash command.** A command you type into your AI assistant's chat, like `/opsx:propose`. Slash commands drive the workflow. They are not terminal commands. See [How Commands Work](how-commands-work.md).
|
||||
|
||||
**Explore (`/opsx:explore`).** The thinking-partner command. It reads your codebase, compares options, and clarifies a fuzzy idea into a concrete plan. It never writes code, and writes nothing else unless you ask it to capture the exploration as a change, or say yes when it offers. The recommended starting point whenever you have a problem but not yet a plan. See [Explore First](explore.md).
|
||||
|
||||
**CLI.** The `openspec` program you run in your terminal. It sets up projects, lists and validates changes, opens the dashboard, and archives. The terminal half of OpenSpec. See [CLI](cli.md).
|
||||
|
||||
**Skill.** A folder of instructions (`.../skills/openspec-*/SKILL.md`) that your AI assistant auto-detects and follows. Skills are the emerging cross-tool standard for delivering the OpenSpec workflow to your assistant.
|
||||
|
||||
**Command file.** A per-tool slash command file (`.../commands/opsx-*`). The older delivery mechanism, still supported alongside skills. You rarely touch these directly.
|
||||
|
||||
**Profile.** The set of slash commands installed in your project. **Core** (the default) is `propose`, `explore`, `apply`, `update`, `sync`, `archive`. The **expanded** set adds `new`, `continue`, `ff`, `verify`, `bulk-archive`, `onboard`. Change it with `openspec config profile`.
|
||||
|
||||
**Delivery.** Whether OpenSpec installs skills, command files, or both for your tools. Configured globally and applied with `openspec update`.
|
||||
|
||||
## Customization
|
||||
|
||||
**Schema.** The definition of which artifacts a workflow has and how they depend on one another. The built-in default is `spec-driven` (proposal → specs → design → tasks). You can fork it or write your own. See [Customization](customization.md#custom-schemas).
|
||||
|
||||
**Template.** A Markdown file inside a schema that shapes what the AI generates for a given artifact. Editing a template changes the AI's output immediately, with no rebuild.
|
||||
|
||||
**Project config (`openspec/config.yaml`).** Per-project settings: the default schema, the `context:` injected into every planning request, and per-artifact `rules:`. The easiest way to teach OpenSpec about your stack and conventions. See [Customization](customization.md#project-configuration).
|
||||
|
||||
**Context injection.** Putting project background in `config.yaml`'s `context:` field so it's automatically added to every artifact the AI generates. More reliable than hoping the AI reads a separate file.
|
||||
|
||||
**Dependency graph.** The directed graph formed by artifact `requires:` relationships. It's a DAG (directed acyclic graph: arrows only point forward, never in a loop), and OpenSpec uses it to know what you can create next.
|
||||
|
||||
**Enablers, not gates.** The principle that artifact dependencies show what becomes *possible* next, not what's *required* next. You can revisit and edit any artifact at any time. See [Core Concepts at a Glance](overview.md#enablers-not-gates).
|
||||
|
||||
## Coordination across repos (beta)
|
||||
|
||||
These terms apply only if your planning spans more than one repo. They're in beta. Most users can ignore them. See the [Stores User Guide](stores-beta/user-guide.md).
|
||||
|
||||
**Store.** A standalone repo whose whole job is planning. It has the same `openspec/` shape you already know (specs and changes) plus a small identity file. You register it on your machine once, by name, and then any OpenSpec command can work in it from anywhere.
|
||||
|
||||
**Reference.** A declaration, in a code repo's `openspec/config.yaml`, of a store that repo draws on. References are read-only: the repo keeps its own root, and `openspec instructions` gains an index of the referenced store's specs, each with the exact command to fetch it.
|
||||
|
||||
**Working context.** What `openspec context` assembles for the current repo: its OpenSpec root plus every store it references, each with how to fetch it. The answer to "what am I working with?"
|
||||
|
||||
**Workset.** A personal, machine-local set of folders you open together (a store alongside the code repos you work on). Created explicitly with `openspec workset create`; nothing about those local paths is committed to the shared planning repo.
|
||||
|
||||
## See also
|
||||
|
||||
- [Core Concepts at a Glance](overview.md): the five ideas, on one page
|
||||
- [Concepts](concepts.md): the long-form explanation
|
||||
- [How Commands Work](how-commands-work.md): slash commands versus the CLI
|
||||
@@ -1,173 +0,0 @@
|
||||
# How Commands Work
|
||||
|
||||
**The one thing to know: OpenSpec has two kinds of commands, and they run in two different places.**
|
||||
|
||||
- `openspec ...` commands run in your **terminal**. (Example: `openspec init`.)
|
||||
- `/opsx:...` commands run in your **AI assistant's chat**. (Example: `/opsx:propose`.)
|
||||
|
||||
If you ever type `/opsx:propose` into your terminal and nothing happens, this page is why. You are talking to the wrong half of OpenSpec. Slash commands are not terminal commands. They are instructions you give to your AI coding assistant, in the same chat box where you'd normally type "add a login form."
|
||||
|
||||
That single distinction is the most common stumbling block for new users, so let's make it crystal clear.
|
||||
|
||||
## The two halves
|
||||
|
||||
OpenSpec is one project wearing two hats.
|
||||
|
||||
**The CLI (terminal half).** A program named `openspec` that you install and run from your shell. It sets up your project, lists and validates changes, shows a dashboard, and archives finished work. You type these into iTerm, the VS Code terminal, PowerShell, anywhere you'd run `git` or `npm`.
|
||||
|
||||
```bash
|
||||
openspec init # set up OpenSpec in this project
|
||||
openspec list # see active changes
|
||||
openspec view # open the interactive dashboard
|
||||
```
|
||||
|
||||
**The slash commands (chat half).** Short commands like `/opsx:propose` and `/opsx:apply` that you type into your AI assistant. These tell the AI to follow the OpenSpec workflow: draft a proposal, write specs, build from the task list, archive when done. You type these into Claude Code, Cursor, Devin Desktop, Copilot, or whichever assistant you use.
|
||||
|
||||
```text
|
||||
/opsx:propose add-dark-mode (typed in your AI chat)
|
||||
/opsx:apply (typed in your AI chat)
|
||||
/opsx:archive (typed in your AI chat)
|
||||
```
|
||||
|
||||
Here's the mental model in one picture:
|
||||
|
||||
```text
|
||||
YOUR TERMINAL YOUR AI ASSISTANT'S CHAT
|
||||
┌──────────────────────┐ ┌──────────────────────────────┐
|
||||
│ $ openspec init │ installs │ /opsx:propose add-dark-mode │
|
||||
│ $ openspec list │ ──────────► │ /opsx:apply │
|
||||
│ $ openspec view │ commands │ /opsx:archive │
|
||||
└──────────────────────┘ & skills └──────────────────────────────┘
|
||||
run openspec here run /opsx:* here
|
||||
```
|
||||
|
||||
Notice the arrow. Running `openspec init` in your terminal is what *installs* the slash commands into your AI tool. The terminal half sets up the chat half. After that, day-to-day driving mostly happens in chat.
|
||||
|
||||
## "How do I start interactive mode?"
|
||||
|
||||
**There is no separate interactive mode to start.** This question comes up a lot, so it deserves a plain answer.
|
||||
|
||||
You don't enter a special OpenSpec mode. You just open your AI coding assistant like you always do, and type a slash command into the chat. The slash command *is* how you "enter" OpenSpec. Your assistant recognizes it, loads the matching OpenSpec skill, and starts following the workflow.
|
||||
|
||||
So the real instructions are:
|
||||
|
||||
1. Open your AI coding assistant (Claude Code, Cursor, Devin Desktop, and so on) in your project.
|
||||
2. Type `/opsx:propose` in its chat, the same place you type any other request.
|
||||
3. Watch the autocomplete: if OpenSpec is installed, you'll see `/opsx:propose`, `/opsx:apply`, and friends appear as you type the slash.
|
||||
|
||||
That's it. No mode to toggle, no daemon to launch, no separate window.
|
||||
|
||||
One thing that *is* genuinely interactive lives in the terminal: `openspec view`. It opens a dashboard for browsing your specs and changes. But that's a viewer, not the thing you propose and build with. The building happens through slash commands in chat.
|
||||
|
||||
## Why this split exists
|
||||
|
||||
It's worth understanding, because it explains why OpenSpec works with 30+ different AI tools.
|
||||
|
||||
The CLI is the **engine**. It knows the rules: what a change folder looks like, which artifacts depend on which, how to merge a delta spec into your source of truth. It's the same everywhere.
|
||||
|
||||
The slash commands are the **steering wheel**, and every AI tool has a slightly different one. Claude Code calls them commands. Cursor and Devin Desktop have their own formats. Some tools call them skills. When you run `openspec init`, OpenSpec generates the right kind of file for each tool you selected, so the same `/opsx:propose` intent works no matter which assistant you prefer.
|
||||
|
||||
The strength of this design: you learn the workflow once and carry it across tools. The tradeoff: the exact syntax of a command can differ slightly between tools, which is the next section.
|
||||
|
||||
## Slash command syntax by tool
|
||||
|
||||
The intent is identical everywhere. The spelling follows the file your tool loads.
|
||||
|
||||
| Your tool's command file | How you type it | Example tools |
|
||||
|--------------------------|-----------------|---------------|
|
||||
| `.../commands/opsx/<id>.*` | `/opsx:propose` | Claude Code, Gemini CLI, Crush |
|
||||
| `.../opsx-<id>.*` | `/opsx-propose` | Cursor, GitHub Copilot (IDE), Devin Desktop, Trae, Oh My Pi |
|
||||
| `.amazonq/prompts/opsx-<id>.md` | `@opsx-propose` | Amazon Q Developer |
|
||||
| none — skills only | `/openspec-propose` | CodeArts, ForgeCode, Hermes, Mistral Vibe, Zed Agent, shared `.agents` |
|
||||
| none — Kimi Code | `/skill:openspec-propose` | Kimi Code |
|
||||
| none — Codex CLI | `$openspec-propose` | Codex |
|
||||
|
||||
Devin is the one tool that spans two rows. Devin Desktop reads
|
||||
`.devin/workflows/`, so `/opsx-propose` works there; [Devin Local does
|
||||
not](https://docs.devin.ai/desktop/devin-local), so on that agent use the
|
||||
`/openspec-propose` skill instead. The skills OpenSpec writes to
|
||||
`.devin/skills/` work on both, which is why they reference each other by skill
|
||||
name.
|
||||
|
||||
Every tool is listed in [How To Invoke](supported-tools.md#how-to-invoke) — that
|
||||
table is the authoritative one. Two rows are not slash commands at all: Amazon Q
|
||||
loads its files into a prompt library invoked with `@`, and the last three rows
|
||||
use the *skill* name, which is not the command id (`/opsx:apply` is the
|
||||
`openspec-apply-change` skill).
|
||||
|
||||
When in doubt, read the "Getting started" line `openspec init` printed: it already
|
||||
uses the form your tools registered. Typing a slash and watching the autocomplete
|
||||
works too, for the tools that surface slash commands at all.
|
||||
|
||||
## How the commands got there: skills and commands
|
||||
|
||||
When you run `openspec init` (or `openspec update`), OpenSpec writes small files into your project so your AI tool can find the workflow. Depending on your tool and settings, these are **skills**, **commands**, or both.
|
||||
|
||||
- **Skills** live in places like `.claude/skills/openspec-*/SKILL.md`. They're the emerging cross-tool standard: a folder of instructions your assistant auto-detects.
|
||||
- **Commands** live in places like `.cursor/commands/opsx-<id>.md` or `.claude/commands/opsx/<id>.md` — the layout is the tool's, and it decides how you type the command. They're the older per-tool slash command files. Codex does not get generated command files; use `.agents/skills/openspec-*`.
|
||||
|
||||
You don't have to care which one your tool uses. You just type the slash command and it works. But knowing these files exist helps when something goes wrong: if your commands vanish, it usually means these files are missing or stale, and `openspec update` regenerates them.
|
||||
|
||||
See [Supported Tools](supported-tools.md) for the exact paths per tool, and [Migration Guide](migration-guide.md) for how skills replaced the older command-only approach.
|
||||
|
||||
## Confirming it's installed
|
||||
|
||||
Quick checks, fastest first:
|
||||
|
||||
1. **Type a slash in your AI chat.** Start typing `/opsx` and watch for autocomplete suggestions. If they appear, you're set. On a skills-only tool (Codex, Kimi Code, CodeArts, ForgeCode, Hermes, Mistral Vibe, Zed Agent, or the shared `.agents` target) `/opsx` never completes even on a healthy install — try the skill name from the table above instead.
|
||||
2. **Look for the files.** For Claude Code, check that `.claude/skills/` contains `openspec-*` folders. Other tools use their own directories ([Supported Tools](supported-tools.md) lists them).
|
||||
3. **Re-run setup.** From your project root, run `openspec update`. This regenerates the skill and command files for whatever tools you configured.
|
||||
4. **Restart your assistant.** Many tools scan for skills and commands at startup, so a fresh window can be the missing step.
|
||||
|
||||
## Which commands do I even have?
|
||||
|
||||
By default, OpenSpec installs the **core** set of slash commands:
|
||||
|
||||
- `/opsx:explore`: think through an idea with the AI before committing to a change (great first step when you're unsure)
|
||||
- `/opsx:propose`: create a change and draft all its planning artifacts in one step
|
||||
- `/opsx:apply`: build the change by working through its task list
|
||||
- `/opsx:update`: revise a change's planning artifacts and keep them coherent
|
||||
- `/opsx:sync`: merge a change's spec updates into your main specs (usually automatic)
|
||||
- `/opsx:archive`: finish a change and file it away
|
||||
|
||||
A good default rhythm: `explore` when you're figuring out what to do, then `propose`, `apply`, `archive`. The [Explore First](explore.md) guide explains why that opening step pays off.
|
||||
|
||||
There's also an **expanded** set for people who want finer control (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:bulk-archive`, `/opsx:onboard`). You turn it on with `openspec config profile`, then apply it with `openspec update`.
|
||||
|
||||
New to all of this? `/opsx:onboard` (in the expanded set) walks you through a complete change on your own codebase, narrating each step. It's the friendliest possible introduction.
|
||||
|
||||
For what each command does in detail, see [Commands](commands.md). For when to reach for which, see [Workflows](workflows.md).
|
||||
|
||||
## A clean first run
|
||||
|
||||
Putting it together, here is the whole sequence with each step labeled by where it happens.
|
||||
|
||||
```text
|
||||
TERMINAL $ npm install -g @fission-ai/openspec@latest
|
||||
TERMINAL $ cd your-project
|
||||
TERMINAL $ openspec init
|
||||
(installs slash commands into your AI tool)
|
||||
|
||||
AI CHAT /opsx:explore
|
||||
(optional: think the idea through with the AI first)
|
||||
|
||||
AI CHAT /opsx:propose add-dark-mode
|
||||
(AI drafts proposal, specs, design, tasks)
|
||||
|
||||
AI CHAT /opsx:apply
|
||||
(AI builds it, checking off tasks)
|
||||
|
||||
AI CHAT /opsx:archive
|
||||
(change is merged into your specs and filed away)
|
||||
```
|
||||
|
||||
Two terminal steps to set up. Then you live in chat. That's the rhythm.
|
||||
|
||||
## Related
|
||||
|
||||
- [Getting Started](getting-started.md): the full first-change walkthrough
|
||||
- [Commands](commands.md): every slash command in detail
|
||||
- [CLI](cli.md): every terminal command in detail
|
||||
- [Supported Tools](supported-tools.md): per-tool syntax and file locations
|
||||
- [FAQ](faq.md): more quick answers
|
||||
- [Troubleshooting](troubleshooting.md): fixes when commands don't show up
|
||||
@@ -1,206 +0,0 @@
|
||||
# Installation
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Node.js 20.19.0 or higher** — Check your version: `node --version`
|
||||
|
||||
## Install with your AI assistant
|
||||
|
||||
Rather not do this by hand? Paste the prompt below into any coding assistant that can run shell commands — Claude Code, Codex, Cursor, Gemini CLI, Copilot, and the rest of the [supported tools](supported-tools.md). It installs the CLI, initializes this project, and reports back what actually happened.
|
||||
|
||||
The manual steps below are the source of truth — the prompt just runs them for you. If your assistant stops and hands something back, that's by design: it asks before anything privileged and never edits your shell startup files. Finish those bits yourself with [Package Managers](#package-managers) and [Troubleshooting](troubleshooting.md).
|
||||
|
||||
```text
|
||||
Install OpenSpec in this project and set it up for me. Follow these steps in
|
||||
order, and stop where a step tells you to stop.
|
||||
|
||||
1. RUNTIME. Run `node --version`. OpenSpec needs Node.js 20.19.0 or higher. If
|
||||
Node is missing or older, say so and stop — don't install Node, switch
|
||||
versions, or reconfigure my version manager for me.
|
||||
|
||||
2. INSTALL. Use whichever package manager is already on my PATH, preferring npm:
|
||||
npm install -g @fission-ai/openspec@latest
|
||||
pnpm add -g @fission-ai/openspec@latest
|
||||
bun add -g @fission-ai/openspec@latest
|
||||
yarn global add @fission-ai/openspec@latest (Yarn 1.x only)
|
||||
Don't pick based on this project's lockfile — a global install has nothing to
|
||||
do with how this repo's own dependencies are installed. If none of those four
|
||||
is available, stop and tell me — don't improvise an install. (If I'm on Nix,
|
||||
point me at the Nix section of the OpenSpec installation docs instead.)
|
||||
Show me the exact command and let me confirm before you run it; this installs
|
||||
software outside the project, and I may want a different package manager to
|
||||
own it.
|
||||
Stop and ask me again if the install needs sudo or admin rights, fails with a
|
||||
permissions error, or reports that its global bin directory is missing or
|
||||
unconfigured. Never edit my shell startup files (.bashrc, .zshrc, .profile,
|
||||
fish, PowerShell profile), and never run a setup command that edits them for
|
||||
me — show me the change and let me make it.
|
||||
|
||||
3. PATH. Run `openspec --version`. If the command isn't found, it may just be
|
||||
missing from this shell: tell me where the package manager installed it and
|
||||
how to add that directory to PATH for my shell and OS, then stop until I
|
||||
confirm. If it prints an older version than the one the install just
|
||||
reported, an earlier copy is shadowing it on PATH — tell me both versions
|
||||
instead of continuing. If I use a version manager, say so rather than editing
|
||||
PATH around it: with nvm or fnm the CLI is tied to the Node version that was
|
||||
active when you installed it, and with asdf or volta a shim may need
|
||||
regenerating.
|
||||
|
||||
4. INITIALIZE. Ask me which AI coding tool or tools I use and map each to an id
|
||||
from `openspec init --help` (Copilot is `github-copilot`, Zoo Code is
|
||||
`roocode`). `--tools` takes a comma-separated list, so name all of them.
|
||||
`openspec init --tools <ids>` deletes leftovers from older OpenSpec versions
|
||||
automatically, without asking — including `opsx-*.md` prompt files in my home
|
||||
directory (Codex keeps them in ~/.codex/prompts). Before you run it, look for
|
||||
those: `.../commands/openspec/` folders, OpenSpec marker blocks in files like
|
||||
CLAUDE.md or AGENTS.md, and home-directory `opsx-*.md` prompts. List whatever
|
||||
you find and wait for my go-ahead; if you find nothing, say so and carry on
|
||||
without asking. An existing `openspec/` folder is not a problem — init
|
||||
refreshes it and leaves my specs and changes alone.
|
||||
Confirm I'm in the right folder too: init creates `openspec/` wherever it
|
||||
runs, including inside a monorepo package.
|
||||
Then run: openspec init --tools <ids>
|
||||
|
||||
5. REPORT. Don't assume what should exist — tell me what init actually printed:
|
||||
how many skills and/or commands it created and where, the config file line,
|
||||
any "Setup required" note, and what to restart or reload. Some tools are
|
||||
skills-only and correctly create zero command files, so missing commands is
|
||||
not a failure on its own. If init said nothing was generated, relay the fix
|
||||
it suggested instead of retrying. Finish by telling me how to invoke OpenSpec
|
||||
in my tool, and take the exact spelling from the files init created rather
|
||||
than from its summary line: the punctuation differs per tool (/opsx:propose
|
||||
in some, /opsx-propose in others, @opsx-propose in Amazon Q), and tools that
|
||||
get skills instead of commands are invoked by skill name (/openspec-propose,
|
||||
or $openspec-propose in Codex, or /skill:openspec-propose in Kimi Code).
|
||||
```
|
||||
|
||||
Nothing in the prompt is vendor-specific: it's plain instructions plus the same commands documented on this page. It works on macOS, Linux, and Windows, and it deliberately stops rather than improvising when a step needs your permission. Your assistant does need to be able to run shell commands — a few IDE integrations can't.
|
||||
|
||||
## Package Managers
|
||||
|
||||
### npm
|
||||
|
||||
```bash
|
||||
npm install -g @fission-ai/openspec@latest
|
||||
```
|
||||
|
||||
### pnpm
|
||||
|
||||
```bash
|
||||
pnpm add -g @fission-ai/openspec@latest
|
||||
```
|
||||
|
||||
### yarn
|
||||
|
||||
```bash
|
||||
yarn global add @fission-ai/openspec@latest
|
||||
```
|
||||
|
||||
Yarn 2 and later (Berry) removed the `global` command. On those versions, install OpenSpec with npm, pnpm, or bun instead — a global CLI doesn't need to share your project's package manager.
|
||||
|
||||
### deno
|
||||
|
||||
Deno sometimes has issues parsing the @latest tag, but we can specify a version while installing initially.
|
||||
If that happens, you could try to change the @latest tag with the version, something like `@^1.3.1`
|
||||
|
||||
```bash
|
||||
deno install --global \
|
||||
--allow-read --allow-write --allow-env --allow-sys=cpus,homedir --allow-net=edge.openspec.dev \
|
||||
npm:@fission-ai/openspec@latest
|
||||
# or
|
||||
deno install --global \
|
||||
--allow-read --allow-write --allow-env --allow-sys=cpus,homedir --allow-net=edge.openspec.dev \
|
||||
npm:@fission-ai/openspec@^1.3.1
|
||||
```
|
||||
|
||||
Note: If your subcommands launch external tools, like config edit, feedback, or workspace open, you may need a scoped --allow-run=<program>.
|
||||
|
||||
### bun
|
||||
|
||||
Bun can install OpenSpec globally, but OpenSpec currently runs on Node.js.
|
||||
You still need Node.js 20.19.0 or higher available on `PATH`.
|
||||
|
||||
```bash
|
||||
bun add -g @fission-ai/openspec@latest
|
||||
```
|
||||
|
||||
## Nix
|
||||
|
||||
Run OpenSpec directly without installation:
|
||||
|
||||
```bash
|
||||
nix run github:Fission-AI/OpenSpec -- init
|
||||
```
|
||||
|
||||
Or install to your profile:
|
||||
|
||||
```bash
|
||||
nix profile install github:Fission-AI/OpenSpec
|
||||
```
|
||||
|
||||
Or add to your development environment in `flake.nix`:
|
||||
|
||||
```nix
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
openspec.url = "github:Fission-AI/OpenSpec";
|
||||
};
|
||||
|
||||
outputs = { nixpkgs, openspec, ... }: {
|
||||
devShells.x86_64-linux.default = nixpkgs.legacyPackages.x86_64-linux.mkShell {
|
||||
buildInputs = [ openspec.packages.x86_64-linux.default ];
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## Verify Installation
|
||||
|
||||
```bash
|
||||
openspec --version
|
||||
```
|
||||
|
||||
## Updating
|
||||
|
||||
Upgrade the package, then refresh each project's generated files:
|
||||
|
||||
```bash
|
||||
npm install -g @fission-ai/openspec@latest # or pnpm/yarn/bun equivalent
|
||||
openspec update # run inside each project
|
||||
```
|
||||
|
||||
`openspec update` regenerates the skill and command files for the tools you've configured, so your slash commands stay current with the installed version. It also checks whether a newer CLI has been published and offers to upgrade, since upgrading is what makes new workflows available in the first place — see [CLI Reference](cli.md#openspec-update).
|
||||
|
||||
## Uninstalling
|
||||
|
||||
There's no `openspec uninstall` command, because OpenSpec is just a global package plus some files in your project. Removing it is a few manual steps, and nothing here touches your source code.
|
||||
|
||||
**1. Remove the global package:**
|
||||
|
||||
```bash
|
||||
npm uninstall -g @fission-ai/openspec # or: pnpm rm -g / yarn global remove / bun rm -g
|
||||
```
|
||||
|
||||
**2. Remove OpenSpec from a project (optional).** Delete the `openspec/` directory if you no longer want its specs and changes:
|
||||
|
||||
```bash
|
||||
rm -rf openspec/
|
||||
```
|
||||
|
||||
Think before you do this: `openspec/specs/` and `openspec/changes/archive/` are your record of how the system behaves and why it changed. If you might want that history, keep the folder (or keep it in git) even after uninstalling.
|
||||
|
||||
**3. Remove generated AI tool files (optional).** OpenSpec writes skill and command files into per-tool directories like `.claude/skills/openspec-*/`, `.cursor/commands/opsx-*`, and so on. Delete the `openspec-*` skills and `opsx-*` commands for whichever tools you configured. The exact paths per tool are listed in [Supported Tools](supported-tools.md).
|
||||
|
||||
If you also have OpenSpec marker blocks in files like `CLAUDE.md` or `AGENTS.md`, remove those blocks by hand; your own content in those files is yours to keep.
|
||||
|
||||
## Next Steps
|
||||
|
||||
After installing, initialize OpenSpec in your project:
|
||||
|
||||
```bash
|
||||
cd your-project
|
||||
openspec init
|
||||
```
|
||||
|
||||
See [Getting Started](getting-started.md) for a full walkthrough.
|
||||
@@ -1,604 +0,0 @@
|
||||
# Migrating to OPSX
|
||||
|
||||
This guide helps you transition from the legacy OpenSpec workflow to OPSX. The migration is designed to be smooth—your existing work is preserved, and the new system offers more flexibility.
|
||||
|
||||
## What's Changing?
|
||||
|
||||
OPSX replaces the old phase-locked workflow with a fluid, action-based approach. Here's the key shift:
|
||||
|
||||
| Aspect | Legacy | OPSX |
|
||||
|--------|--------|------|
|
||||
| **Commands** | `/openspec:proposal`, `/openspec:apply`, `/openspec:archive` | Default: `/opsx:propose`, `/opsx:explore`, `/opsx:apply`, `/opsx:update`, `/opsx:sync`, `/opsx:archive` (expanded workflow commands optional) |
|
||||
| **Workflow** | Create all artifacts at once | Create incrementally or all at once—your choice |
|
||||
| **Going back** | Awkward phase gates | Natural—update any artifact anytime |
|
||||
| **Customization** | Fixed structure | Schema-driven, fully hackable |
|
||||
| **Configuration** | `CLAUDE.md` with markers + `project.md` | Clean config in `openspec/config.yaml` |
|
||||
|
||||
**The philosophy change:** Work isn't linear. OPSX stops pretending it is.
|
||||
|
||||
---
|
||||
|
||||
## Before You Begin
|
||||
|
||||
### Your Existing Work Is Safe
|
||||
|
||||
The migration process is designed with preservation in mind:
|
||||
|
||||
- **Active changes in `openspec/changes/`** — Completely preserved. You can continue them with OPSX commands.
|
||||
- **Archived changes** — Untouched. Your history remains intact.
|
||||
- **Main specs in `openspec/specs/`** — Untouched. These are your source of truth.
|
||||
- **Your content in CLAUDE.md, AGENTS.md, etc.** — Preserved. Only the OpenSpec marker blocks are removed; everything you wrote stays.
|
||||
|
||||
### What Gets Removed
|
||||
|
||||
Only OpenSpec-managed files that are being replaced:
|
||||
|
||||
| What | Why |
|
||||
|------|-----|
|
||||
| Legacy slash command directories/files | Replaced by the new skills system |
|
||||
| `openspec/AGENTS.md` | Obsolete workflow trigger |
|
||||
| OpenSpec markers in `CLAUDE.md`, `AGENTS.md`, etc. | No longer needed |
|
||||
|
||||
**Legacy command locations by tool** (examples—your tool may vary):
|
||||
|
||||
- Claude Code: `.claude/commands/openspec/`
|
||||
- Cursor: `.cursor/commands/openspec-*.md`
|
||||
- Devin Desktop, formerly Windsurf: `.windsurf/workflows/openspec-*.md`
|
||||
- Cline: `.clinerules/workflows/openspec-*.md`
|
||||
- Roo: `.roo/commands/openspec-*.md`
|
||||
- GitHub Copilot: `.github/prompts/openspec-*.prompt.md` (IDE extensions only; not supported in Copilot CLI)
|
||||
- Codex: OpenSpec now uses the canonical `.agents/skills/openspec-*` path. OpenSpec-managed `SKILL.md` files under the former `.codex/skills` path are reconciled only after replacements exist; custom files and divergent copies stay in place. If an unmarked `.agents` tree already contains OpenSpec skills, OpenSpec preserves its existing Codex (`$openspec-*`) or generic (`/openspec-*`) rendering instead of guessing from the legacy directory. Select `codex` explicitly with `openspec init` to switch ownership. Legacy prompt cleanup still targets only OpenSpec's allowlisted filenames in `$CODEX_HOME/prompts` or `~/.codex/prompts`.
|
||||
- And others (Augment, Continue, Amazon Q, etc.)
|
||||
|
||||
The migration detects whichever tools you have configured and cleans up their legacy files.
|
||||
|
||||
The removal list may seem long, but these are all files that OpenSpec originally created. Your own content is never deleted.
|
||||
|
||||
### What Needs Your Attention
|
||||
|
||||
One file requires manual migration:
|
||||
|
||||
**`openspec/project.md`** — This file isn't deleted automatically because it may contain project context you've written. You'll need to:
|
||||
|
||||
1. Review its contents
|
||||
2. Move useful context to `openspec/config.yaml` (see guidance below)
|
||||
3. Delete the file when ready
|
||||
|
||||
**Why we made this change:**
|
||||
|
||||
The old `project.md` was passive—agents might read it, might not, might forget what they read. We found reliability was inconsistent.
|
||||
|
||||
The new `config.yaml` context is **actively injected into every OpenSpec planning request**. This means your project conventions, tech stack, and rules are always present when the AI is creating artifacts. Higher reliability.
|
||||
|
||||
**The tradeoff:**
|
||||
|
||||
Because context is injected into every request, you'll want to be concise. Focus on what really matters:
|
||||
- Tech stack and key conventions
|
||||
- Non-obvious constraints the AI needs to know
|
||||
- Rules that frequently got ignored before
|
||||
|
||||
Don't worry about getting it perfect. We're still learning what works best here, and we'll be improving how context injection works as we experiment.
|
||||
|
||||
---
|
||||
|
||||
## Running the Migration
|
||||
|
||||
Both `openspec init` and `openspec update` detect legacy files and guide you through the same cleanup process. Use whichever fits your situation:
|
||||
|
||||
- New installs default to profile `core` (`propose`, `explore`, `apply`, `update`, `sync`, `archive`).
|
||||
- Migrated installs preserve your previously installed workflows by writing a `custom` profile when needed.
|
||||
|
||||
### Using `openspec init`
|
||||
|
||||
Run this if you want to add new tools or reconfigure which tools are set up:
|
||||
|
||||
```bash
|
||||
openspec init
|
||||
```
|
||||
|
||||
The init command detects legacy files and guides you through cleanup:
|
||||
|
||||
```
|
||||
Upgrading to the new OpenSpec
|
||||
|
||||
OpenSpec now uses agent skills, the emerging standard across coding
|
||||
agents. This simplifies your setup while keeping everything working
|
||||
as before.
|
||||
|
||||
Files to remove
|
||||
No user content to preserve:
|
||||
• .claude/commands/openspec/
|
||||
• openspec/AGENTS.md
|
||||
|
||||
Files to update
|
||||
OpenSpec markers will be removed, your content preserved:
|
||||
• CLAUDE.md
|
||||
• AGENTS.md
|
||||
|
||||
Needs your attention
|
||||
• openspec/project.md
|
||||
We won't delete this file. It may contain useful project context.
|
||||
|
||||
The new openspec/config.yaml has a "context:" section for planning
|
||||
context. This is included in every OpenSpec request and works more
|
||||
reliably than the old project.md approach.
|
||||
|
||||
Review project.md, move any useful content to config.yaml's context
|
||||
section, then delete the file when ready.
|
||||
|
||||
? Upgrade and clean up legacy files? (Y/n)
|
||||
```
|
||||
|
||||
**What happens when you say yes:**
|
||||
|
||||
1. Legacy slash command directories are removed
|
||||
2. OpenSpec markers are stripped from `CLAUDE.md`, `AGENTS.md`, etc. (your content stays)
|
||||
3. `openspec/AGENTS.md` is deleted
|
||||
4. New skills are installed in `.claude/skills/`
|
||||
5. `openspec/config.yaml` is created with a default schema
|
||||
|
||||
### Using `openspec update`
|
||||
|
||||
Run this if you just want to migrate and refresh your existing tools to the latest version:
|
||||
|
||||
```bash
|
||||
openspec update
|
||||
```
|
||||
|
||||
The update command also detects and cleans up legacy artifacts, then refreshes generated skills/commands to match your current profile and delivery settings.
|
||||
|
||||
### Non-Interactive / CI Environments
|
||||
|
||||
For scripted migrations:
|
||||
|
||||
```bash
|
||||
openspec init --force --tools claude
|
||||
```
|
||||
|
||||
The `--force` flag skips prompts and auto-accepts cleanup.
|
||||
|
||||
This includes cleanup of OpenSpec-managed Codex prompt files in the global Codex prompt directory. Cleanup only targets OpenSpec's allowlisted legacy Codex prompt filenames, removes them only after replacement `.agents/skills/openspec-*` skills exist, and preserves all other files.
|
||||
|
||||
---
|
||||
|
||||
## Migrating project.md to config.yaml
|
||||
|
||||
The old `openspec/project.md` was a freeform markdown file for project context. The new `openspec/config.yaml` is structured and—critically—**injected into every planning request** so your conventions are always present when the AI works.
|
||||
|
||||
### Before (project.md)
|
||||
|
||||
```markdown
|
||||
# Project Context
|
||||
|
||||
This is a TypeScript monorepo using React and Node.js.
|
||||
We use Jest for testing and follow strict ESLint rules.
|
||||
Our API is RESTful and documented in docs/api.md.
|
||||
|
||||
## Conventions
|
||||
|
||||
- All public APIs must maintain backwards compatibility
|
||||
- New features should include tests
|
||||
- Use Given/When/Then format for specifications
|
||||
```
|
||||
|
||||
### After (config.yaml)
|
||||
|
||||
```yaml
|
||||
schema: spec-driven
|
||||
|
||||
context: |
|
||||
Tech stack: TypeScript, React, Node.js
|
||||
Testing: Jest with React Testing Library
|
||||
API: RESTful, documented in docs/api.md
|
||||
We maintain backwards compatibility for all public APIs
|
||||
|
||||
rules:
|
||||
proposal:
|
||||
- Include rollback plan for risky changes
|
||||
specs:
|
||||
- Use Given/When/Then format for scenarios
|
||||
- Reference existing patterns before inventing new ones
|
||||
design:
|
||||
- Include sequence diagrams for complex flows
|
||||
```
|
||||
|
||||
### Key Differences
|
||||
|
||||
| project.md | config.yaml |
|
||||
|------------|-------------|
|
||||
| Freeform markdown | Structured YAML |
|
||||
| One blob of text | Separate context and per-artifact rules |
|
||||
| Unclear when it's used | Context appears in ALL artifacts; rules appear in matching artifacts only |
|
||||
| No schema selection | Explicit `schema:` field sets default workflow |
|
||||
|
||||
### What to Keep, What to Drop
|
||||
|
||||
When migrating, be selective. Ask yourself: "Does the AI need this for *every* planning request?"
|
||||
|
||||
**Good candidates for `context:`**
|
||||
- Tech stack (languages, frameworks, databases)
|
||||
- Key architectural patterns (monorepo, microservices, etc.)
|
||||
- Non-obvious constraints ("we can't use library X because...")
|
||||
- Critical conventions that often get ignored
|
||||
|
||||
**Move to `rules:` instead**
|
||||
- Artifact-specific formatting ("use Given/When/Then in specs")
|
||||
- Review criteria ("proposals must include rollback plans")
|
||||
- These only appear for the matching artifact, keeping other requests lighter
|
||||
|
||||
**Leave out entirely**
|
||||
- General best practices the AI already knows
|
||||
- Verbose explanations that could be summarized
|
||||
- Historical context that doesn't affect current work
|
||||
|
||||
### Migration Steps
|
||||
|
||||
1. **Create config.yaml** (if not already created by init):
|
||||
```yaml
|
||||
schema: spec-driven
|
||||
```
|
||||
|
||||
2. **Add your context** (be concise—this goes into every request):
|
||||
```yaml
|
||||
context: |
|
||||
Your project background goes here.
|
||||
Focus on what the AI genuinely needs to know.
|
||||
```
|
||||
|
||||
3. **Add per-artifact rules** (optional):
|
||||
```yaml
|
||||
rules:
|
||||
proposal:
|
||||
- Your proposal-specific guidance
|
||||
specs:
|
||||
- Your spec-writing rules
|
||||
```
|
||||
|
||||
4. **Delete project.md** once you've moved everything useful.
|
||||
|
||||
**Don't overthink it.** Start with the essentials and iterate. If you notice the AI missing something important, add it. If context feels bloated, trim it. This is a living document.
|
||||
|
||||
### Need Help? Use This Prompt
|
||||
|
||||
If you're unsure how to distill your project.md, ask your AI assistant:
|
||||
|
||||
```
|
||||
I'm migrating from OpenSpec's old project.md to the new config.yaml format.
|
||||
|
||||
Here's my current project.md:
|
||||
[paste your project.md content]
|
||||
|
||||
Please help me create a config.yaml with:
|
||||
1. A concise `context:` section (this gets injected into every planning request, so keep it tight—focus on tech stack, key constraints, and conventions that often get ignored)
|
||||
2. `rules:` for specific artifacts if any content is artifact-specific (e.g., "use Given/When/Then" belongs in specs rules, not global context)
|
||||
|
||||
Leave out anything generic that AI models already know. Be ruthless about brevity.
|
||||
```
|
||||
|
||||
The AI will help you identify what's essential vs. what can be trimmed.
|
||||
|
||||
---
|
||||
|
||||
## The New Commands
|
||||
|
||||
Command availability is profile-dependent:
|
||||
|
||||
**Default (`core` profile):**
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `/opsx:propose` | Create a change and generate planning artifacts in one step |
|
||||
| `/opsx:explore` | Think through ideas with no structure |
|
||||
| `/opsx:apply` | Implement tasks from tasks.md |
|
||||
| `/opsx:update` | Revise a change's planning artifacts and keep them coherent |
|
||||
| `/opsx:sync` | Merge delta specs into main specs |
|
||||
| `/opsx:archive` | Finalize and archive the change |
|
||||
|
||||
**Expanded workflow (custom selection):**
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `/opsx:new` | Start a new change scaffold |
|
||||
| `/opsx:continue` | Create the next artifact (one at a time) |
|
||||
| `/opsx:ff` | Fast-forward—create planning artifacts at once |
|
||||
| `/opsx:verify` | Validate implementation matches specs |
|
||||
| `/opsx:bulk-archive` | Archive multiple changes at once |
|
||||
| `/opsx:onboard` | Guided end-to-end onboarding workflow |
|
||||
|
||||
Enable expanded commands with `openspec config profile`, then run `openspec update`.
|
||||
|
||||
### Command Mapping from Legacy
|
||||
|
||||
| Legacy | OPSX Equivalent |
|
||||
|--------|-----------------|
|
||||
| `/openspec:proposal` | `/opsx:propose` (default) or `/opsx:new` then `/opsx:ff` (expanded) |
|
||||
| `/openspec:apply` | `/opsx:apply` |
|
||||
| `/openspec:archive` | `/opsx:archive` |
|
||||
|
||||
### New Capabilities
|
||||
|
||||
These capabilities are part of the expanded workflow command set.
|
||||
|
||||
**Granular artifact creation:**
|
||||
```
|
||||
/opsx:continue
|
||||
```
|
||||
Creates one artifact at a time based on dependencies. Use this when you want to review each step.
|
||||
|
||||
**Exploration mode:**
|
||||
```
|
||||
/opsx:explore
|
||||
```
|
||||
Think through ideas with a partner before committing to a change.
|
||||
|
||||
---
|
||||
|
||||
## Understanding the New Architecture
|
||||
|
||||
### From Phase-Locked to Fluid
|
||||
|
||||
The legacy workflow forced linear progression:
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│ PLANNING │ ───► │ IMPLEMENTING │ ───► │ ARCHIVING │
|
||||
│ PHASE │ │ PHASE │ │ PHASE │
|
||||
└──────────────┘ └──────────────┘ └──────────────┘
|
||||
|
||||
If you're in implementation and realize the design is wrong?
|
||||
Too bad. Phase gates don't let you go back easily.
|
||||
```
|
||||
|
||||
OPSX uses actions, not phases:
|
||||
|
||||
```
|
||||
┌───────────────────────────────────────────────┐
|
||||
│ ACTIONS (not phases) │
|
||||
│ │
|
||||
│ new ◄──► continue ◄──► apply ◄──► archive │
|
||||
│ │ │ │ │ │
|
||||
│ └──────────┴───────────┴─────────────┘ │
|
||||
│ any order │
|
||||
└───────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Dependency Graph
|
||||
|
||||
Artifacts form a directed graph. Dependencies are enablers, not gates:
|
||||
|
||||
```
|
||||
proposal
|
||||
(root node)
|
||||
│
|
||||
┌─────────────┴─────────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
specs design
|
||||
(requires: (requires:
|
||||
proposal) proposal)
|
||||
│ │
|
||||
└─────────────┬─────────────┘
|
||||
│
|
||||
▼
|
||||
tasks
|
||||
(requires:
|
||||
specs, design)
|
||||
```
|
||||
|
||||
When you run `/opsx:continue`, it checks what's ready and offers the next artifact. You can also create multiple ready artifacts in any order.
|
||||
|
||||
### Skills vs Commands
|
||||
|
||||
The legacy system used tool-specific command files:
|
||||
|
||||
```
|
||||
.claude/commands/openspec/
|
||||
├── proposal.md
|
||||
├── apply.md
|
||||
└── archive.md
|
||||
```
|
||||
|
||||
OPSX uses the emerging **skills** standard:
|
||||
|
||||
```
|
||||
.claude/skills/
|
||||
├── openspec-explore/SKILL.md
|
||||
├── openspec-new-change/SKILL.md
|
||||
├── openspec-continue-change/SKILL.md
|
||||
├── openspec-apply-change/SKILL.md
|
||||
└── ...
|
||||
```
|
||||
|
||||
Skills are recognized across multiple AI coding tools and provide richer metadata.
|
||||
|
||||
Codex is skills-only in OPSX. OpenSpec no longer generates Codex custom prompt files; use the generated `.agents/skills/openspec-*` directories instead.
|
||||
|
||||
---
|
||||
|
||||
## Continuing Existing Changes
|
||||
|
||||
Your in-progress changes work seamlessly with OPSX commands.
|
||||
|
||||
**Have an active change from the legacy workflow?**
|
||||
|
||||
```
|
||||
/opsx:apply add-my-feature
|
||||
```
|
||||
|
||||
OPSX reads the existing artifacts and continues from where you left off.
|
||||
|
||||
**Want to add more artifacts to an existing change?**
|
||||
|
||||
```
|
||||
/opsx:continue add-my-feature
|
||||
```
|
||||
|
||||
Shows what's ready to create based on what already exists.
|
||||
|
||||
**Need to see status?**
|
||||
|
||||
```bash
|
||||
openspec status --change add-my-feature
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## The New Config System
|
||||
|
||||
### config.yaml Structure
|
||||
|
||||
```yaml
|
||||
# Required: Default schema for new changes
|
||||
schema: spec-driven
|
||||
|
||||
# Optional: Project context (max 50KB)
|
||||
# Injected into ALL artifact instructions
|
||||
context: |
|
||||
Your project background, tech stack,
|
||||
conventions, and constraints.
|
||||
|
||||
# Optional: Per-artifact rules
|
||||
# Only injected into matching artifacts
|
||||
rules:
|
||||
proposal:
|
||||
- Include rollback plan
|
||||
specs:
|
||||
- Use Given/When/Then format
|
||||
design:
|
||||
- Document fallback strategies
|
||||
tasks:
|
||||
- Break into 2-hour maximum chunks
|
||||
```
|
||||
|
||||
### Schema Resolution
|
||||
|
||||
When determining which schema to use, OPSX checks in order:
|
||||
|
||||
1. **CLI flag**: `--schema <name>` (highest priority)
|
||||
2. **Change metadata**: `.openspec.yaml` in the change directory
|
||||
3. **Project config**: `openspec/config.yaml`
|
||||
4. **Default**: `spec-driven`
|
||||
|
||||
### Available Schemas
|
||||
|
||||
| Schema | Artifacts | Best For |
|
||||
|--------|-----------|----------|
|
||||
| `spec-driven` | proposal → specs → design → tasks | Most projects |
|
||||
|
||||
List all available schemas:
|
||||
|
||||
```bash
|
||||
openspec schemas
|
||||
```
|
||||
|
||||
### Custom Schemas
|
||||
|
||||
Create your own workflow:
|
||||
|
||||
```bash
|
||||
openspec schema init my-workflow
|
||||
```
|
||||
|
||||
Or fork an existing one:
|
||||
|
||||
```bash
|
||||
openspec schema fork spec-driven my-workflow
|
||||
```
|
||||
|
||||
See [Customization](customization.md) for details.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Legacy files detected in non-interactive mode"
|
||||
|
||||
You're running in a CI or non-interactive environment. Use:
|
||||
|
||||
```bash
|
||||
openspec init --force
|
||||
```
|
||||
|
||||
### Commands not appearing after migration
|
||||
|
||||
Restart your IDE. Skills are detected at startup.
|
||||
|
||||
### "Unknown artifact ID in rules"
|
||||
|
||||
Check that your `rules:` keys match your schema's artifact IDs:
|
||||
|
||||
- **spec-driven**: `proposal`, `specs`, `design`, `tasks`
|
||||
|
||||
Run this to see valid artifact IDs:
|
||||
|
||||
```bash
|
||||
openspec schemas --json
|
||||
```
|
||||
|
||||
### Config not being applied
|
||||
|
||||
1. Ensure the file is at `openspec/config.yaml` (not `.yml`)
|
||||
2. Validate YAML syntax
|
||||
3. Config changes take effect immediately—no restart needed
|
||||
|
||||
### project.md not migrated
|
||||
|
||||
The system intentionally preserves `project.md` because it may contain your custom content. Review it manually, move useful parts to `config.yaml`, then delete it.
|
||||
|
||||
### Want to see what would be cleaned up?
|
||||
|
||||
Run init and decline the cleanup prompt—you'll see the full detection summary without any changes being made.
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Files After Migration
|
||||
|
||||
```
|
||||
project/
|
||||
├── openspec/
|
||||
│ ├── specs/ # Unchanged
|
||||
│ ├── changes/ # Unchanged
|
||||
│ │ └── archive/ # Unchanged
|
||||
│ └── config.yaml # NEW: Project configuration
|
||||
├── .claude/
|
||||
│ └── skills/ # NEW: OPSX skills
|
||||
│ ├── openspec-propose/ # default core profile
|
||||
│ ├── openspec-explore/
|
||||
│ ├── openspec-apply-change/
|
||||
│ ├── openspec-update-change/
|
||||
│ ├── openspec-sync-specs/
|
||||
│ ├── openspec-archive-change/
|
||||
│ └── ... # expanded profile adds new/continue/ff/etc.
|
||||
├── CLAUDE.md # OpenSpec markers removed, your content preserved
|
||||
└── AGENTS.md # OpenSpec markers removed, your content preserved
|
||||
```
|
||||
|
||||
### What's Gone
|
||||
|
||||
- `.claude/commands/openspec/` — replaced by `.claude/skills/`
|
||||
- `openspec/AGENTS.md` — obsolete
|
||||
- `openspec/project.md` — migrate to `config.yaml`, then delete
|
||||
- OpenSpec marker blocks in `CLAUDE.md`, `AGENTS.md`, etc.
|
||||
|
||||
### Command Cheatsheet
|
||||
|
||||
```text
|
||||
/opsx:propose Start quickly (default core profile)
|
||||
/opsx:apply Implement tasks
|
||||
/opsx:archive Finish and archive
|
||||
|
||||
# Expanded workflow (if enabled):
|
||||
/opsx:new Scaffold a change
|
||||
/opsx:continue Create next artifact
|
||||
/opsx:ff Create planning artifacts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Getting Help
|
||||
|
||||
- **Discord**: [discord.gg/YctCnvvshC](https://discord.gg/YctCnvvshC)
|
||||
- **GitHub Issues**: [github.com/Fission-AI/OpenSpec/issues](https://github.com/Fission-AI/OpenSpec/issues)
|
||||
- **Documentation**: [docs/opsx.md](opsx.md) for the full OPSX reference
|
||||
@@ -1,132 +0,0 @@
|
||||
# Multi-Language Guide
|
||||
|
||||
Configure OpenSpec to generate artifacts in languages other than English.
|
||||
|
||||
## Quick Setup
|
||||
|
||||
For a new project, set the language during initialization:
|
||||
|
||||
```bash
|
||||
openspec init --language "Portuguese (pt-BR)"
|
||||
```
|
||||
|
||||
This writes the language instruction to `openspec/config.yaml`. If the project
|
||||
already has a config, edit its `context` field directly so existing project
|
||||
guidance is preserved.
|
||||
|
||||
You can also configure the same behavior manually:
|
||||
|
||||
Add a language instruction to your `openspec/config.yaml`:
|
||||
|
||||
```yaml
|
||||
schema: spec-driven
|
||||
|
||||
context: |
|
||||
Language: Portuguese (pt-BR)
|
||||
All artifacts must be written in Brazilian Portuguese.
|
||||
Keep OpenSpec structural headings and SHALL/MUST keywords in English.
|
||||
|
||||
# Your other project context below...
|
||||
Tech stack: TypeScript, React, Node.js
|
||||
```
|
||||
|
||||
That's it. All generated artifacts will now be in Portuguese.
|
||||
|
||||
OpenSpec's document structure and normative `SHALL`/`MUST` keywords remain in
|
||||
English because validation relies on them. The surrounding requirement and
|
||||
scenario prose can use your selected language.
|
||||
|
||||
## Language Examples
|
||||
|
||||
### Portuguese (Brazil)
|
||||
|
||||
```yaml
|
||||
context: |
|
||||
Language: Portuguese (pt-BR)
|
||||
All artifacts must be written in Brazilian Portuguese.
|
||||
```
|
||||
|
||||
### Spanish
|
||||
|
||||
```yaml
|
||||
context: |
|
||||
Idioma: Español
|
||||
Todos los artefactos deben escribirse en español.
|
||||
```
|
||||
|
||||
### Chinese (Simplified)
|
||||
|
||||
```yaml
|
||||
context: |
|
||||
语言:中文(简体)
|
||||
所有产出物必须用简体中文撰写。
|
||||
```
|
||||
|
||||
### Japanese
|
||||
|
||||
```yaml
|
||||
context: |
|
||||
言語:日本語
|
||||
すべての成果物は日本語で作成してください。
|
||||
```
|
||||
|
||||
### French
|
||||
|
||||
```yaml
|
||||
context: |
|
||||
Langue : Français
|
||||
Tous les artefacts doivent être rédigés en français.
|
||||
```
|
||||
|
||||
### German
|
||||
|
||||
```yaml
|
||||
context: |
|
||||
Sprache: Deutsch
|
||||
Alle Artefakte müssen auf Deutsch verfasst werden.
|
||||
```
|
||||
|
||||
## Tips
|
||||
|
||||
### Handle Technical Terms
|
||||
|
||||
Decide how to handle technical terminology:
|
||||
|
||||
```yaml
|
||||
context: |
|
||||
Language: Japanese
|
||||
Write in Japanese, but:
|
||||
- Keep technical terms like "API", "REST", "GraphQL" in English
|
||||
- Code examples and file paths remain in English
|
||||
```
|
||||
|
||||
### Combine with Other Context
|
||||
|
||||
Language settings work alongside your other project context:
|
||||
|
||||
```yaml
|
||||
schema: spec-driven
|
||||
|
||||
context: |
|
||||
Language: Portuguese (pt-BR)
|
||||
All artifacts must be written in Brazilian Portuguese.
|
||||
|
||||
Tech stack: TypeScript, React 18, Node.js 20
|
||||
Database: PostgreSQL with Prisma ORM
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
To verify your language config is working:
|
||||
|
||||
```bash
|
||||
# Check the instructions - should show your language context
|
||||
openspec instructions proposal --change my-change
|
||||
|
||||
# Output will include your language context
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Customization Guide](./customization.md) - Project configuration options
|
||||
- [Workflows Guide](./workflows.md) - Full workflow documentation
|
||||
-675
@@ -1,675 +0,0 @@
|
||||
# OPSX Workflow
|
||||
|
||||
> Feedback welcome on [Discord](https://discord.gg/YctCnvvshC).
|
||||
|
||||
## What Is It?
|
||||
|
||||
OPSX is now the standard workflow for OpenSpec.
|
||||
|
||||
It's a **fluid, iterative workflow** for OpenSpec changes. No more rigid phases — just actions you can take anytime.
|
||||
|
||||
## Why This Exists
|
||||
|
||||
The legacy OpenSpec workflow works, but it's **locked down**:
|
||||
|
||||
- **Instructions are hardcoded** — buried in TypeScript, you can't change them
|
||||
- **All-or-nothing** — one big command creates everything, can't test individual pieces
|
||||
- **Fixed structure** — same workflow for everyone, no customization
|
||||
- **Black box** — when AI output is bad, you can't tweak the prompts
|
||||
|
||||
**OPSX opens it up.** Now anyone can:
|
||||
|
||||
1. **Experiment with instructions** — edit a template, see if the AI does better
|
||||
2. **Test granularly** — validate each artifact's instructions independently
|
||||
3. **Customize workflows** — define your own artifacts and dependencies
|
||||
4. **Iterate quickly** — change a template, test immediately, no rebuild
|
||||
|
||||
```
|
||||
Legacy workflow: OPSX:
|
||||
┌────────────────────────┐ ┌────────────────────────┐
|
||||
│ Hardcoded in package │ │ schema.yaml │◄── You edit this
|
||||
│ (can't change) │ │ templates/*.md │◄── Or this
|
||||
│ ↓ │ │ ↓ │
|
||||
│ Wait for new release │ │ Instant effect │
|
||||
│ ↓ │ │ ↓ │
|
||||
│ Hope it's better │ │ Test it yourself │
|
||||
└────────────────────────┘ └────────────────────────┘
|
||||
```
|
||||
|
||||
**This is for everyone:**
|
||||
- **Teams** — create workflows that match how you actually work
|
||||
- **Power users** — tweak prompts to get better AI outputs for your codebase
|
||||
- **OpenSpec contributors** — experiment with new approaches without releases
|
||||
|
||||
We're all still learning what works best. OPSX lets us learn together.
|
||||
|
||||
## The User Experience
|
||||
|
||||
**The problem with linear workflows:**
|
||||
You're "in planning phase", then "in implementation phase", then "done". But real work doesn't work that way. You implement something, realize your design was wrong, need to update specs, continue implementing. Linear phases fight against how work actually happens.
|
||||
|
||||
**OPSX approach:**
|
||||
- **Actions, not phases** — create, implement, update, archive — do any of them anytime
|
||||
- **Dependencies are enablers** — they show what's possible, not what's required next
|
||||
|
||||
```
|
||||
proposal ──→ specs ──→ design ──→ tasks ──→ implement
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
# Make sure you have openspec installed — skills are automatically generated
|
||||
openspec init
|
||||
```
|
||||
|
||||
This creates skills in `.claude/skills/` (or equivalent) that AI coding assistants auto-detect.
|
||||
|
||||
By default, OpenSpec uses the `core` workflow profile (`propose`, `explore`, `apply`, `update`, `sync`, `archive`). If you want the expanded workflow commands (`new`, `continue`, `ff`, `verify`, `bulk-archive`, `onboard`), configure them with `openspec config profile` and apply with `openspec update`.
|
||||
|
||||
During setup, you'll be prompted to create a **project config** (`openspec/config.yaml`). This is optional but recommended.
|
||||
|
||||
## Project Configuration
|
||||
|
||||
Project config lets you set defaults and inject project-specific context into all artifacts.
|
||||
|
||||
### Creating Config
|
||||
|
||||
Config is created during `openspec init`, or manually:
|
||||
|
||||
```yaml
|
||||
# openspec/config.yaml
|
||||
schema: spec-driven
|
||||
|
||||
context: |
|
||||
Tech stack: TypeScript, React, Node.js
|
||||
API conventions: RESTful, JSON responses
|
||||
Testing: Vitest for unit tests, Playwright for e2e
|
||||
Style: ESLint with Prettier, strict TypeScript
|
||||
|
||||
rules:
|
||||
proposal:
|
||||
- Include rollback plan
|
||||
- Identify affected teams
|
||||
specs:
|
||||
- Use Given/When/Then format for scenarios
|
||||
design:
|
||||
- Include sequence diagrams for complex flows
|
||||
```
|
||||
|
||||
### Config Fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `schema` | string | Default schema for new changes (e.g., `spec-driven`) |
|
||||
| `context` | string | Project context injected into all artifact instructions |
|
||||
| `rules` | object | Per-artifact rules, keyed by artifact ID |
|
||||
|
||||
### How It Works
|
||||
|
||||
**Schema precedence** (highest to lowest):
|
||||
1. CLI flag (`--schema <name>`)
|
||||
2. Change metadata (`.openspec.yaml` in change directory)
|
||||
3. Project config (`openspec/config.yaml`)
|
||||
4. Default (`spec-driven`)
|
||||
|
||||
**Context injection:**
|
||||
- Context is prepended to every artifact's instructions
|
||||
- Wrapped in `<context>...</context>` tags
|
||||
- Helps AI understand your project's conventions
|
||||
|
||||
**Rules injection:**
|
||||
- Rules are only injected for matching artifacts
|
||||
- Wrapped in `<rules>...</rules>` tags
|
||||
- Appear after context, before the template
|
||||
|
||||
### Artifact IDs by Schema
|
||||
|
||||
**spec-driven** (default):
|
||||
- `proposal` — Change proposal
|
||||
- `specs` — Specifications
|
||||
- `design` — Technical design
|
||||
- `tasks` — Implementation tasks
|
||||
|
||||
### Config Validation
|
||||
|
||||
- Unknown artifact IDs in `rules` generate warnings
|
||||
- Schema names are validated against available schemas
|
||||
- Context has a 50KB size limit
|
||||
- Invalid YAML is reported with line numbers
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
**"Unknown artifact ID in rules: X"**
|
||||
- Check artifact IDs match your schema (see list above)
|
||||
- Run `openspec schemas --json` to see artifact IDs for each schema
|
||||
|
||||
**Config not being applied:**
|
||||
- Ensure file is at `openspec/config.yaml` (not `.yml`)
|
||||
- Check YAML syntax with a validator
|
||||
- Config changes take effect immediately (no restart needed)
|
||||
|
||||
**Context too large:**
|
||||
- Context is limited to 50KB
|
||||
- Summarize or link to external docs instead
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | What it does |
|
||||
|---------|--------------|
|
||||
| `/opsx:propose` | Create a change and generate planning artifacts in one step (default quick path) |
|
||||
| `/opsx:explore` | Think through ideas, investigate problems, clarify requirements |
|
||||
| `/opsx:new` | Start a new change scaffold (expanded workflow) |
|
||||
| `/opsx:continue` | Create the next artifact (expanded workflow) |
|
||||
| `/opsx:ff` | Fast-forward planning artifacts (expanded workflow) |
|
||||
| `/opsx:apply` | Implement tasks, updating artifacts as needed |
|
||||
| `/opsx:update` | Revise a change's planning artifacts and keep them coherent |
|
||||
| `/opsx:verify` | Validate implementation against artifacts (expanded workflow) |
|
||||
| `/opsx:sync` | Merge delta specs into main specs (optional) |
|
||||
| `/opsx:archive` | Archive when done |
|
||||
| `/opsx:bulk-archive` | Archive multiple completed changes (expanded workflow) |
|
||||
| `/opsx:onboard` | Guided walkthrough of an end-to-end change (expanded workflow) |
|
||||
|
||||
## Usage
|
||||
|
||||
### Explore an idea
|
||||
```
|
||||
/opsx:explore
|
||||
```
|
||||
Think through ideas, investigate problems, compare options. No structure required - just a thinking partner. When insights crystallize, transition to `/opsx:propose` (default) or `/opsx:new`/`/opsx:ff` (expanded).
|
||||
|
||||
### Start a new change
|
||||
```
|
||||
/opsx:propose
|
||||
```
|
||||
Creates the change and generates planning artifacts needed before implementation.
|
||||
|
||||
If you've enabled expanded workflows, you can instead use:
|
||||
|
||||
```text
|
||||
/opsx:new # scaffold only
|
||||
/opsx:continue # create one artifact at a time
|
||||
/opsx:ff # create all planning artifacts at once
|
||||
```
|
||||
|
||||
### Create artifacts
|
||||
```
|
||||
/opsx:continue
|
||||
```
|
||||
Shows what's ready to create based on dependencies, then creates one artifact. Use repeatedly to build up your change incrementally.
|
||||
|
||||
```
|
||||
/opsx:ff add-dark-mode
|
||||
```
|
||||
Creates all planning artifacts at once. Use when you have a clear picture of what you're building.
|
||||
|
||||
### Implement (the fluid part)
|
||||
```
|
||||
/opsx:apply
|
||||
```
|
||||
Works through tasks, checking them off as you go. If you're juggling multiple changes, you can run `/opsx:apply <name>`; otherwise it should infer from the conversation and prompt you to choose if it can't tell.
|
||||
|
||||
### Updating a change
|
||||
```
|
||||
/opsx:update add-dark-mode - we're storing the theme in a cookie now
|
||||
```
|
||||
Revises the change's existing planning artifacts and keeps them coherent in any direction (a design edit may ripple back to the proposal). It never edits code. Every edit is confirmed with you first. See [the update reference](commands.md#opsxupdate) for how it handles missing files without starting a new artifact.
|
||||
|
||||
If the change was already implemented, it recommends `/opsx:apply` so the code catches up with the revised plan. If your revision changes the change's *intent*, start fresh instead. See [When to Update vs. Start Fresh](#when-to-update-vs-start-fresh).
|
||||
|
||||
### Sync delta specs
|
||||
```text
|
||||
/opsx:sync
|
||||
```
|
||||
Merges the current change's delta specs into your main `openspec/specs/` without archiving — the change stays active. It applies the whole delta: a requirement under `## REMOVED` is deleted from the main spec and a renamed one is retitled in place, while content the delta doesn't mention is left untouched. Syncing is optional — archive prompts you to sync first if you haven't. Reach for it when you want main specs updated before archiving, when a parallel change needs to build on specs this one just added, or when you want to review the merged main spec before archiving.
|
||||
|
||||
### Finish up
|
||||
```
|
||||
/opsx:archive # Move to archive when done (prompts to sync specs if needed)
|
||||
```
|
||||
|
||||
## When to Update vs. Start Fresh
|
||||
|
||||
You can always edit your proposal or specs before implementation. But when does refining become "this is different work"?
|
||||
|
||||
### What a Proposal Captures
|
||||
|
||||
A proposal defines three things:
|
||||
1. **Intent** — What problem are you solving?
|
||||
2. **Scope** — What's in/out of bounds?
|
||||
3. **Approach** — How will you solve it?
|
||||
|
||||
The question is: which changed, and by how much?
|
||||
|
||||
### Update the Existing Change When:
|
||||
|
||||
**Same intent, refined execution**
|
||||
- You discover edge cases you didn't consider
|
||||
- The approach needs tweaking but the goal is unchanged
|
||||
- Implementation reveals the design was slightly off
|
||||
|
||||
**Scope narrows**
|
||||
- You realize full scope is too big, want to ship MVP first
|
||||
- "Add dark mode" → "Add dark mode toggle (system preference in v2)"
|
||||
|
||||
**Learning-driven corrections**
|
||||
- Codebase isn't structured how you thought
|
||||
- A dependency doesn't work as expected
|
||||
- "Use CSS variables" → "Use Tailwind's dark: prefix instead"
|
||||
|
||||
### Start a New Change When:
|
||||
|
||||
**Intent fundamentally changed**
|
||||
- The problem itself is different now
|
||||
- "Add dark mode" → "Add comprehensive theme system with custom colors, fonts, spacing"
|
||||
|
||||
**Scope exploded**
|
||||
- Change grew so much it's essentially different work
|
||||
- Original proposal would be unrecognizable after updates
|
||||
- "Fix login bug" → "Rewrite auth system"
|
||||
|
||||
**Original is completable**
|
||||
- The original change can be marked "done"
|
||||
- New work stands alone, not a refinement
|
||||
- Complete "Add dark mode MVP" → Archive → New change "Enhance dark mode"
|
||||
|
||||
### The Heuristics
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Is this the same work? │
|
||||
└──────────────┬──────────────────────┘
|
||||
│
|
||||
┌──────────────────┼──────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
Same intent? >50% overlap? Can original
|
||||
Same problem? Same scope? be "done" without
|
||||
│ │ these changes?
|
||||
│ │ │
|
||||
┌────────┴────────┐ ┌──────┴──────┐ ┌───────┴───────┐
|
||||
│ │ │ │ │ │
|
||||
YES NO YES NO NO YES
|
||||
│ │ │ │ │ │
|
||||
▼ ▼ ▼ ▼ ▼ ▼
|
||||
UPDATE NEW UPDATE NEW UPDATE NEW
|
||||
```
|
||||
|
||||
| Test | Update | New Change |
|
||||
|------|--------|------------|
|
||||
| **Identity** | "Same thing, refined" | "Different work" |
|
||||
| **Scope overlap** | >50% overlaps | <50% overlaps |
|
||||
| **Completion** | Can't be "done" without changes | Can finish original, new work stands alone |
|
||||
| **Story** | Update chain tells coherent story | Patches would confuse more than clarify |
|
||||
|
||||
### The Principle
|
||||
|
||||
> **Update preserves context. New change provides clarity.**
|
||||
>
|
||||
> Choose update when the history of your thinking is valuable.
|
||||
> Choose new when starting fresh would be clearer than patching.
|
||||
|
||||
Think of it like git branches:
|
||||
- Keep committing while working on the same feature
|
||||
- Start a new branch when it's genuinely new work
|
||||
- Sometimes merge a partial feature and start fresh for phase 2
|
||||
|
||||
## What's Different?
|
||||
|
||||
| | Legacy (`/openspec:proposal`) | OPSX (`/opsx:*`) |
|
||||
|---|---|---|
|
||||
| **Structure** | One big proposal document | Discrete artifacts with dependencies |
|
||||
| **Workflow** | Linear phases: plan → implement → archive | Fluid actions — do anything anytime |
|
||||
| **Iteration** | Awkward to go back | Update artifacts as you learn |
|
||||
| **Customization** | Fixed structure | Schema-driven (define your own artifacts) |
|
||||
|
||||
**The key insight:** work isn't linear. OPSX stops pretending it is.
|
||||
|
||||
## Architecture Deep Dive
|
||||
|
||||
This section explains how OPSX works under the hood and how it compares to the legacy workflow.
|
||||
Examples in this section use the expanded command set (`new`, `continue`, etc.); default `core` users can map the same flow to `propose → apply → sync → archive`.
|
||||
|
||||
### Philosophy: Phases vs Actions
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ LEGACY WORKFLOW │
|
||||
│ (Phase-Locked, All-or-Nothing) │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||
│ │ PLANNING │ ───► │ IMPLEMENTING │ ───► │ ARCHIVING │ │
|
||||
│ │ PHASE │ │ PHASE │ │ PHASE │ │
|
||||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||||
│ │ │ │ │
|
||||
│ ▼ ▼ ▼ │
|
||||
│ /openspec:proposal /openspec:apply /openspec:archive │
|
||||
│ │
|
||||
│ • Creates ALL artifacts at once │
|
||||
│ • Can't go back to update specs during implementation │
|
||||
│ • Phase gates enforce linear progression │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ OPSX WORKFLOW │
|
||||
│ (Fluid Actions, Iterative) │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌────────────────────────────────────────────┐ │
|
||||
│ │ ACTIONS (not phases) │ │
|
||||
│ │ │ │
|
||||
│ │ new ◄──► continue ◄──► apply ◄──► archive │ │
|
||||
│ │ │ │ │ │ │ │
|
||||
│ │ └──────────┴───────────┴───────────┘ │ │
|
||||
│ │ any order │ │
|
||||
│ └────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ • Create artifacts one at a time OR fast-forward │
|
||||
│ • Update specs/design/tasks during implementation │
|
||||
│ • Dependencies enable progress, phases don't exist │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Component Architecture
|
||||
|
||||
**Legacy workflow** uses hardcoded templates in TypeScript:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ LEGACY WORKFLOW COMPONENTS │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Hardcoded Templates (TypeScript strings) │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ Tool-specific configurators/adapters │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ Generated Command Files (.claude/commands/openspec/*.md) │
|
||||
│ │
|
||||
│ • Fixed structure, no artifact awareness │
|
||||
│ • Change requires code modification + rebuild │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**OPSX** uses external schemas and a dependency graph engine:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ OPSX COMPONENTS │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Schema Definitions (YAML) │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ name: spec-driven │ │
|
||||
│ │ artifacts: │ │
|
||||
│ │ - id: proposal │ │
|
||||
│ │ generates: proposal.md │ │
|
||||
│ │ requires: [] ◄── Dependencies │ │
|
||||
│ │ - id: specs │ │
|
||||
│ │ generates: specs/**/*.md ◄── Glob patterns │ │
|
||||
│ │ requires: [proposal] ◄── Enables after proposal │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ Artifact Graph Engine │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ • Topological sort (dependency ordering) │ │
|
||||
│ │ • State detection (filesystem existence) │ │
|
||||
│ │ • Rich instruction generation (templates + context) │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ Skill Files (.claude/skills/openspec-*/SKILL.md) │
|
||||
│ │
|
||||
│ • Cross-editor compatible (Claude Code, Cursor, Devin) │
|
||||
│ • Skills query CLI for structured data │
|
||||
│ • Fully customizable via schema files │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Dependency Graph Model
|
||||
|
||||
Artifacts form a directed acyclic graph (DAG). Dependencies are **enablers**, not gates:
|
||||
|
||||
```
|
||||
proposal
|
||||
(root node)
|
||||
│
|
||||
┌─────────────┴─────────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
specs design
|
||||
(requires: (requires:
|
||||
proposal) proposal)
|
||||
│ │
|
||||
└─────────────┬─────────────┘
|
||||
│
|
||||
▼
|
||||
tasks
|
||||
(requires:
|
||||
specs, design)
|
||||
│
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ APPLY PHASE │
|
||||
│ (requires: │
|
||||
│ tasks) │
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
**State transitions:**
|
||||
|
||||
```
|
||||
BLOCKED ────────────────► READY ────────────────► DONE
|
||||
│ │ │
|
||||
Missing All deps File exists
|
||||
dependencies are DONE on filesystem
|
||||
```
|
||||
|
||||
### Information Flow
|
||||
|
||||
**Legacy workflow** — agent receives static instructions:
|
||||
|
||||
```
|
||||
User: "/openspec:proposal"
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ Static instructions: │
|
||||
│ • Create proposal.md │
|
||||
│ • Create tasks.md │
|
||||
│ • Create design.md │
|
||||
│ • Create delta spec files │
|
||||
│ │
|
||||
│ No awareness of what exists or │
|
||||
│ dependencies between artifacts │
|
||||
└─────────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
Agent creates ALL artifacts in one go
|
||||
```
|
||||
|
||||
**OPSX** — agent queries for rich context:
|
||||
|
||||
```
|
||||
User: "/opsx:continue"
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────────────────┐
|
||||
│ Step 1: Query current state │
|
||||
│ ┌────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ $ openspec status --change "add-auth" --json │ │
|
||||
│ │ │ │
|
||||
│ │ { │ │
|
||||
│ │ "artifacts": [ │ │
|
||||
│ │ {"id": "proposal", "status": "done"}, │ │
|
||||
│ │ {"id": "specs", "status": "ready"}, ◄── First ready │ │
|
||||
│ │ {"id": "design", "status": "ready"}, │ │
|
||||
│ │ {"id": "tasks", "status": "blocked", │ │
|
||||
│ │ "missingDeps": ["specs", "design"]} │ │
|
||||
│ │ ] │ │
|
||||
│ │ } │ │
|
||||
│ └────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Step 2: Get rich instructions for ready artifact │
|
||||
│ ┌────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ $ openspec instructions specs --change "add-auth" --json │ │
|
||||
│ │ │ │
|
||||
│ │ { │ │
|
||||
│ │ "template": "# Specification\n\n## ADDED Requirements...", │ │
|
||||
│ │ "dependencies": [{"id": "proposal", "path": "...", "done": true}│ │
|
||||
│ │ "unlocks": ["tasks"] │ │
|
||||
│ │ } │ │
|
||||
│ └────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ Step 3: Read dependencies → Create ONE artifact → Show what's unlocked │
|
||||
└──────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Iteration Model
|
||||
|
||||
**Legacy workflow** — awkward to iterate:
|
||||
|
||||
```
|
||||
┌─────────┐ ┌─────────┐ ┌─────────┐
|
||||
│/proposal│ ──► │ /apply │ ──► │/archive │
|
||||
└─────────┘ └─────────┘ └─────────┘
|
||||
│ │
|
||||
│ ├── "Wait, the design is wrong"
|
||||
│ │
|
||||
│ ├── Options:
|
||||
│ │ • Edit files manually (breaks context)
|
||||
│ │ • Abandon and start over
|
||||
│ │ • Push through and fix later
|
||||
│ │
|
||||
│ └── No official "go back" mechanism
|
||||
│
|
||||
└── Creates ALL artifacts at once
|
||||
```
|
||||
|
||||
**OPSX** — natural iteration:
|
||||
|
||||
```
|
||||
/opsx:new ───► /opsx:continue ───► /opsx:apply ───► /opsx:archive
|
||||
│ │ │
|
||||
│ │ ├── "The design is wrong"
|
||||
│ │ │
|
||||
│ │ ▼
|
||||
│ │ Just edit design.md
|
||||
│ │ and continue!
|
||||
│ │ │
|
||||
│ │ ▼
|
||||
│ │ /opsx:apply picks up
|
||||
│ │ where you left off
|
||||
│ │
|
||||
│ └── Creates ONE artifact, shows what's unlocked
|
||||
│
|
||||
└── Scaffolds change, waits for direction
|
||||
```
|
||||
|
||||
### Custom Schemas
|
||||
|
||||
Create custom workflows using the schema management commands:
|
||||
|
||||
```bash
|
||||
# Create a new schema from scratch (interactive)
|
||||
openspec schema init my-workflow
|
||||
|
||||
# Or fork an existing schema as a starting point
|
||||
openspec schema fork spec-driven my-workflow
|
||||
|
||||
# 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).
|
||||
|
||||
**Schema structure:**
|
||||
```
|
||||
openspec/schemas/research-first/
|
||||
├── schema.yaml
|
||||
└── templates/
|
||||
├── research.md
|
||||
├── proposal.md
|
||||
└── tasks.md
|
||||
```
|
||||
|
||||
**Example schema.yaml:**
|
||||
```yaml
|
||||
name: research-first
|
||||
artifacts:
|
||||
- id: research # Added before proposal
|
||||
generates: research.md
|
||||
requires: []
|
||||
|
||||
- id: proposal
|
||||
generates: proposal.md
|
||||
requires: [research] # Now depends on research
|
||||
|
||||
- id: tasks
|
||||
generates: tasks.md
|
||||
requires: [proposal]
|
||||
```
|
||||
|
||||
**Dependency Graph:**
|
||||
```
|
||||
research ──► proposal ──► tasks
|
||||
```
|
||||
|
||||
### Summary
|
||||
|
||||
| Aspect | Legacy | OPSX |
|
||||
|--------|----------|------|
|
||||
| **Templates** | Hardcoded TypeScript | External YAML + Markdown |
|
||||
| **Dependencies** | None (all at once) | DAG with topological sort |
|
||||
| **State** | Phase-based mental model | Filesystem existence |
|
||||
| **Customization** | Edit source, rebuild | Create schema.yaml |
|
||||
| **Iteration** | Phase-locked | Fluid, edit anything |
|
||||
| **Editor Support** | Tool-specific configurator/adapters | Single skills directory |
|
||||
|
||||
## Schemas
|
||||
|
||||
Schemas define what artifacts exist and their dependencies. Currently available:
|
||||
|
||||
- **spec-driven** (default): proposal → specs → design → tasks
|
||||
|
||||
```bash
|
||||
# List available schemas
|
||||
openspec schemas
|
||||
|
||||
# See all schemas with their resolution sources
|
||||
openspec schema which --all
|
||||
|
||||
# Create a new schema interactively
|
||||
openspec schema init my-workflow
|
||||
|
||||
# Fork an existing schema for customization
|
||||
openspec schema fork spec-driven my-workflow
|
||||
|
||||
# Validate schema structure before use
|
||||
openspec schema validate my-workflow
|
||||
```
|
||||
|
||||
## Tips
|
||||
|
||||
- Use `/opsx:explore` to think through an idea before committing to a change
|
||||
- `/opsx:ff` when you know what you want, `/opsx:continue` when exploring
|
||||
- During `/opsx:apply`, if something's wrong — fix the artifact, then continue
|
||||
- Tasks track progress via checkboxes in `tasks.md`
|
||||
- Check status anytime: `openspec status --change "name"`
|
||||
|
||||
## Feedback
|
||||
|
||||
This is rough. That's intentional — we're learning what works.
|
||||
|
||||
Found a bug? Have ideas? Join us on [Discord](https://discord.gg/YctCnvvshC) or open an issue on [GitHub](https://github.com/Fission-AI/openspec/issues).
|
||||
@@ -1,91 +0,0 @@
|
||||
# Core Concepts at a Glance
|
||||
|
||||
**OpenSpec is a lightweight agreement layer between you and your AI.** You write down what a change should do, the AI drafts the details, you both look at the same plan, and only then does code get written. This page is the whole mental model on one screen. When you want the long version, [Concepts](concepts.md) has it.
|
||||
|
||||
Here's the entire idea in five words: **agree first, then build confidently.**
|
||||
|
||||
## The five ideas
|
||||
|
||||
Everything in OpenSpec is built from five concepts. Learn these and the rest is detail.
|
||||
|
||||
**1. Specs are the truth.** A spec describes how your system behaves *right now*. It lives in `openspec/specs/`, organized by domain (`auth/`, `payments/`, `ui/`). Specs are made of requirements ("the system SHALL expire sessions after 30 minutes") and scenarios (concrete given/when/then examples). Think of specs as the single agreed-upon answer to "what does this software do?"
|
||||
|
||||
**2. A change is one unit of work.** When you want to add, modify, or remove behavior, you create a change: a folder in `openspec/changes/` holding everything about that work in one place. A proposal, a design, a task list, and the spec edits. One change, one folder, one feature.
|
||||
|
||||
**3. Delta specs describe what's changing, not the whole world.** Inside a change, you don't rewrite the entire spec. You write a small delta: `ADDED` this requirement, `MODIFIED` that one, `REMOVED` this other one. This is the trick that makes OpenSpec good at editing existing systems, not just green-field ones. You describe the diff, not the destination.
|
||||
|
||||
**4. Artifacts build on each other.** A change contains a few documents, created in a natural order, each feeding the next:
|
||||
|
||||
```text
|
||||
proposal ──► specs ──► design ──► tasks ──► implement
|
||||
why what how steps do it
|
||||
```
|
||||
|
||||
You can revisit any of them at any time. They're enablers, not gates. (More on that below.)
|
||||
|
||||
**5. Archiving folds the change back into the truth.** When the work is done, you archive the change. Its delta specs merge into your main specs, and the change folder moves to `changes/archive/` with a date stamp. Now your specs describe the new reality, and you're ready for the next change. The cycle closes.
|
||||
|
||||
## The picture
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ openspec/ │
|
||||
│ │
|
||||
│ ┌──────────────────┐ ┌──────────────────────────┐ │
|
||||
│ │ specs/ │ │ changes/ │ │
|
||||
│ │ │ ◄───── │ │ │
|
||||
│ │ source of truth │ merge │ one folder per change │ │
|
||||
│ │ how things work │ on │ proposal · design · │ │
|
||||
│ │ today │ archive │ tasks · delta specs │ │
|
||||
│ └──────────────────┘ └──────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Two folders. `specs/` is what's true. `changes/` is what you're proposing. Archiving moves a proposal into truth.
|
||||
|
||||
## The loop you'll actually run
|
||||
|
||||
In the default setup, your day looks like this. Optionally think it through first; then one command drafts the plan, you read it, the next builds it, and the last files it away.
|
||||
|
||||
```text
|
||||
/opsx:explore → (optional) think it through with the AI first
|
||||
/opsx:propose add-dark-mode → AI drafts proposal, specs, design, tasks
|
||||
(you read and adjust the plan)
|
||||
/opsx:apply → AI builds it, checking off tasks
|
||||
/opsx:archive → specs updated, change archived
|
||||
```
|
||||
|
||||
**When in doubt, start by exploring.** `/opsx:explore` is a no-stakes thinking partner: it reads your code, lays out options, and turns a fuzzy idea into a concrete plan before any code gets written. It's the best antidote to an AI that will otherwise build *something* from a vague prompt. Already know exactly what you want? Skip straight to `/opsx:propose`. Either way, explore ships in the default profile, so it's always there. See the [Explore guide](explore.md).
|
||||
|
||||
Those are slash commands, typed in your AI assistant's chat. Setup (`openspec init`) happens in your terminal. If that split is new to you, read [How Commands Work](how-commands-work.md) first; it's the most common point of confusion.
|
||||
|
||||
## "Enablers, not gates"
|
||||
|
||||
This phrase shows up everywhere in OpenSpec, so here's what it means in plain terms.
|
||||
|
||||
Old-school spec processes are waterfalls: finish planning, *then* you're allowed to implement, and going back is painful. OpenSpec refuses that. The order `proposal → specs → design → tasks` shows what becomes *possible* next, not what you're *forced* to do next.
|
||||
|
||||
Discover during implementation that the design was wrong? Edit `design.md` and keep going. Realize the scope should shrink? Update the proposal. Nothing locks. The dependencies exist only so the AI has the context it needs (you can't write good tasks without specs to base them on), not to box you in.
|
||||
|
||||
The strength here is honesty: real work is messy and iterative, and OpenSpec lets it be. The tradeoff is discipline: because nothing forces you forward, it's on you to keep a change focused rather than letting it sprawl. The [Workflows](workflows.md) guide has good habits for that.
|
||||
|
||||
## Why this is worth the small overhead
|
||||
|
||||
Plain truth: OpenSpec adds a step. You write a short plan before building. So what do you get for it?
|
||||
|
||||
- **You catch wrong turns before they cost you.** Fixing a misunderstanding in a one-paragraph proposal is free. Fixing it after the AI wrote 400 lines is not.
|
||||
- **The plan and the code stay in the same repo.** Six months later, the spec tells you (and the next AI session) why the system works the way it does.
|
||||
- **Changes are reviewable.** A change folder is a tidy package: read the proposal, skim the deltas, check the tasks. No archaeology through chat history.
|
||||
- **It fits existing codebases.** Deltas mean you can specify a change to a 50,000-line app without first documenting the whole thing.
|
||||
|
||||
And the honest tradeoff: for a truly trivial one-line fix, the ceremony may not pay off, and that's fine. OpenSpec is designed to be lightweight, but it isn't free. Use it where agreement matters, which turns out to be most of the time once you're working with an AI that will confidently build whatever you vaguely asked for.
|
||||
|
||||
## Where to go next
|
||||
|
||||
- New here? [Getting Started](getting-started.md) walks the first change in full.
|
||||
- Not sure what to build yet? [Explore First](explore.md) is the place to start.
|
||||
- Confused about where commands run? [How Commands Work](how-commands-work.md).
|
||||
- Want the deep version of everything above? [Concepts](concepts.md).
|
||||
- Learn by example? [Examples & Recipes](examples.md).
|
||||
- Need a term defined? [Glossary](glossary.md).
|
||||
@@ -1,143 +0,0 @@
|
||||
# Reviewing a Change
|
||||
|
||||
OpenSpec's whole promise is that you and your AI **agree on what to build before any code is written.** That agreement only means something if you actually read what the AI drafted. This page is about the two minutes where you do that — what to open, in what order, and what to look for.
|
||||
|
||||
The bet is simple: catching a wrong turn in a one-paragraph plan is nearly free. Catching the same wrong turn in 300 lines of code is not. Review is where you collect on that bet.
|
||||
|
||||
## The two moments you review
|
||||
|
||||
There are exactly two:
|
||||
|
||||
```
|
||||
/opsx:propose ──► REVIEW THE PLAN ──► /opsx:apply ──► REVIEW THE CODE ──► /opsx:archive
|
||||
(before any code) (/opsx:verify)
|
||||
```
|
||||
|
||||
1. **After `/opsx:propose`** (or `/opsx:ff`), before `/opsx:apply` — read the plan while it's still just words.
|
||||
2. **After building**, with `/opsx:verify` — check that the code actually did what the plan said.
|
||||
|
||||
The first review is the one that saves you the most, and the one people skip. This page spends most of its time there.
|
||||
|
||||
## Read it in this order
|
||||
|
||||
A change is a folder of plain Markdown in `openspec/changes/<name>/`. Read the files in the order that lets you quit earliest if something's wrong:
|
||||
|
||||
```
|
||||
openspec/changes/add-dark-mode/
|
||||
├── proposal.md 1. the intent and scope ← if this is wrong, stop here
|
||||
├── specs/…/spec.md 2. the requirements ← the heart of the review
|
||||
├── design.md (only for bigger changes) — the technical approach
|
||||
└── tasks.md 3. the plan of work
|
||||
```
|
||||
|
||||
You don't need to read every line. You need to answer three questions, one per file.
|
||||
|
||||
## The proposal: is this the right problem?
|
||||
|
||||
Open `proposal.md` first. It captures the "why" and "what" — the intent, the scope, the approach in a paragraph or two.
|
||||
|
||||
**What good looks like:** one clear intent, a scope you recognize, and a reason this is worth doing now.
|
||||
|
||||
**Red flags:**
|
||||
|
||||
- It solves a slightly *different* problem than the one you asked for.
|
||||
- The scope has grown — you asked for a theme toggle and the proposal also touches auth "while we're in there."
|
||||
- It's vague. "Improve the settings page" is not a scope; "add a dark-mode toggle that respects the OS preference" is.
|
||||
|
||||
**The question to answer:** *Does this match what I actually asked for, and is anything sneaking in?* If the answer is no, stop — don't read further, fix the proposal (see [Pushing back](#pushing-back-is-cheap)).
|
||||
|
||||
## The spec deltas: is "done" defined correctly?
|
||||
|
||||
This is the heart of the review. The delta specs under `specs/` say what will be *true* when the change ships — as requirements and the scenarios that prove them:
|
||||
|
||||
```markdown
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Dark Mode Toggle
|
||||
The system SHALL let a user switch between light and dark themes.
|
||||
|
||||
#### Scenario: Respects the OS preference on first load
|
||||
- GIVEN a user who has never set a theme
|
||||
- WHEN they open the app on a device set to dark mode
|
||||
- THEN the app renders in dark mode
|
||||
```
|
||||
|
||||
**What a good requirement looks like:** one clear `SHALL`/`MUST` statement you could hand to a tester, and at least one scenario whose GIVEN/WHEN/THEN actually exercises that statement.
|
||||
|
||||
**Red flags:**
|
||||
|
||||
- **A vague requirement.** "The system SHALL be fast" can't be built or tested. What's fast?
|
||||
- **A requirement with no scenario**, or a scenario that doesn't test the requirement it sits under.
|
||||
- **The most valuable catch of all: what's missing.** The AI faithfully writes down what you *said*. Your job is to notice what you *forgot* to say. If you cared most about the OS-preference case and no scenario mentions it, that's the review paying for itself.
|
||||
|
||||
Read the deltas asking *would I be happy if the system did exactly — and only — this?* Nothing here is about code yet, so it stays cheap to change.
|
||||
|
||||
## The tasks: is the plan of work sane?
|
||||
|
||||
Open `tasks.md` last. It's the implementation checklist the AI will work through.
|
||||
|
||||
**What good looks like:** ordered steps, each traceable to a requirement, nothing mysterious.
|
||||
|
||||
**Red flags:**
|
||||
|
||||
- A task with no matching requirement (where did that come from?).
|
||||
- One giant "implement the feature" task that hides all the real decisions.
|
||||
- A task that touches something outside the scope you just approved.
|
||||
|
||||
You're not estimating or micromanaging here — you're checking that the plan matches the requirements you already accepted.
|
||||
|
||||
## Pushing back is cheap
|
||||
|
||||
If any of the three questions came back wrong, say so. There are no phases and nothing is locked — you fix it and move on. Two ways, exactly as in [Editing a change](editing-changes.md):
|
||||
|
||||
- **Edit the file yourself.** It's plain Markdown; change the scope line, tighten a requirement, delete a task.
|
||||
- **Tell the AI what's wrong** and let it revise: *"drop the auth changes — out of scope,"* *"add a scenario for when the user has already picked a theme,"* *"split task 3 into schema and UI."*
|
||||
|
||||
Then re-read the part you changed. Re-draft until it's a plan you'd sign your name to. That back-and-forth *is* the product working.
|
||||
|
||||
## After the code: verify
|
||||
|
||||
Once the work is built, `/opsx:verify` is your second review. It re-reads the artifacts and the code and reports mismatches across three dimensions:
|
||||
|
||||
| Dimension | What it checks |
|
||||
|-----------|----------------|
|
||||
| **Completeness** | Every task done, every requirement implemented, scenarios covered |
|
||||
| **Correctness** | The implementation matches the spec's intent, edge cases handled |
|
||||
| **Coherence** | Design decisions actually show up in the code |
|
||||
|
||||
```
|
||||
You: /opsx:verify
|
||||
|
||||
AI: Verifying add-dark-mode...
|
||||
|
||||
COMPLETENESS
|
||||
✓ All 8 tasks in tasks.md are checked
|
||||
✓ All requirements in specs have corresponding code
|
||||
⚠ Scenario "Respects the OS preference on first load" has no test coverage
|
||||
```
|
||||
|
||||
It flags issues as CRITICAL, WARNING, or SUGGESTION, and it does **not** block archiving — it surfaces the gaps and leaves the call to you. This is the difference between "did the AI write code" and "did it build what we agreed."
|
||||
|
||||
`/opsx:verify` is in the expanded profile. If you don't have it, turn it on with `openspec config profile` (then `openspec update`), or just re-read the change and the diff yourself.
|
||||
|
||||
## Right-size the review
|
||||
|
||||
Not every change earns the full pass. A one-file typo fix deserves a twenty-second skim. A change that touches auth, payments, or data you can't recover deserves every question above. The point was never ceremony — it's spending your attention where a mistake would be expensive, and skimming where it wouldn't.
|
||||
|
||||
## The two-minute checklist
|
||||
|
||||
- [ ] The proposal's intent matches what I asked for.
|
||||
- [ ] Nothing extra has crept into the scope.
|
||||
- [ ] Every requirement is specific enough to test.
|
||||
- [ ] Every requirement has a scenario that actually exercises it.
|
||||
- [ ] The case I care about most is covered.
|
||||
- [ ] Tasks map to requirements; nothing is mysterious or out of scope.
|
||||
- [ ] I'd be comfortable if the AI built exactly this and nothing more.
|
||||
|
||||
If all seven pass, run `/opsx:apply` with confidence. If any fail, that's not a setback — it's the two minutes doing its job.
|
||||
|
||||
## Where to go next
|
||||
|
||||
- [Writing Good Specs](writing-specs.md) — the flip side: how to draft requirements and scenarios worth approving.
|
||||
- [Editing & Iterating on a Change](editing-changes.md) — the mechanics of changing a plan after you've started.
|
||||
- [Workflows](workflows.md) — where review fits in the larger loop.
|
||||
@@ -1,462 +0,0 @@
|
||||
# Stores: Plan in Its Own Repo
|
||||
|
||||
> **Beta.** Stores, references, working context, and worksets are
|
||||
> new. Command names, flags, file formats, and JSON output may still change
|
||||
> shape between releases. Every walkthrough below was run against the
|
||||
> current build, but re-read this guide after upgrading.
|
||||
|
||||
## The problem this solves
|
||||
|
||||
OpenSpec normally lives inside one code repo: an `openspec/` folder next to
|
||||
your code, holding specs and changes for that repo.
|
||||
|
||||
That stops fitting the moment your planning is bigger than one repo:
|
||||
|
||||
- Your work spans several repos — one feature touches the API server, the
|
||||
web app, and a shared library. Whose `openspec/` folder does the plan
|
||||
live in?
|
||||
- Your team plans before code exists, or plans things that never become
|
||||
code in *this* repo.
|
||||
- Requirements are owned by one team and consumed by others. The wiki
|
||||
version drifts, and your coding agent can't read it anyway.
|
||||
|
||||
A **store** is the answer: a standalone repo whose whole job is planning.
|
||||
It has the same `openspec/` shape you already know — specs and changes —
|
||||
plus a small identity file. You register it on your machine once, by name,
|
||||
and then every normal OpenSpec command can work in it from anywhere.
|
||||
|
||||
## The shape
|
||||
|
||||
```
|
||||
team-plans (a store: planning in its own repo)
|
||||
├── .openspec-store/store.yaml identity: "I am team-plans"
|
||||
└── openspec/
|
||||
├── specs/ what is true
|
||||
└── changes/ what is in motion
|
||||
▲
|
||||
│ registered on each machine by name;
|
||||
│ shared by pushing/cloning like any repo
|
||||
┌─────────────┼─────────────┐
|
||||
│ │ │
|
||||
web-app api-server mobile-app
|
||||
(code repo) (code repo) (code repo)
|
||||
```
|
||||
|
||||
Two rules keep this simple:
|
||||
|
||||
1. **A store is just a git repo.** You commit, push, pull, and review it
|
||||
yourself. OpenSpec never clones, syncs, or pushes anything on its own.
|
||||
2. **Declarations, not machinery.** Repos can *declare* how they relate to
|
||||
stores (shown below). Declarations change what OpenSpec can tell you —
|
||||
never where your commands act.
|
||||
|
||||
## Five minutes to your first store
|
||||
|
||||
Two commands take you from nothing to a working, store-scoped change:
|
||||
|
||||
```bash
|
||||
openspec store setup team-plans --path ~/openspec/team-plans
|
||||
```
|
||||
|
||||
```
|
||||
Store ready: team-plans
|
||||
Location: /Users/you/openspec/team-plans
|
||||
OpenSpec root: ready
|
||||
Registry: registered
|
||||
|
||||
Next: run normal OpenSpec commands against this store, for example:
|
||||
openspec new change <change-id> --store team-plans
|
||||
Share this store by committing and pushing it like any Git repo.
|
||||
```
|
||||
|
||||
```bash
|
||||
openspec new change add-login --store team-plans
|
||||
```
|
||||
|
||||
```
|
||||
Using OpenSpec root: team-plans (/Users/you/openspec/team-plans)
|
||||
Created change 'add-login' at /Users/you/openspec/team-plans/openspec/changes/add-login/
|
||||
Schema: spec-driven
|
||||
Next: openspec status --change add-login --store team-plans
|
||||
```
|
||||
|
||||
That's the whole model. From here the lifecycle is exactly what you know —
|
||||
`status`, `instructions`, `validate`, `archive` — with `--store team-plans`
|
||||
on each command, and every printed hint carries the flag for you. The
|
||||
`Using OpenSpec root:` line always tells you where a command is acting.
|
||||
|
||||
## Story: one team, one planning repo
|
||||
|
||||
A team keeps its specs and changes in `team-plans` instead of scattering
|
||||
them across code repos.
|
||||
|
||||
**Day one (whoever sets it up):**
|
||||
|
||||
```bash
|
||||
openspec store setup team-plans --path ~/openspec/team-plans \
|
||||
--remote git@github.com:acme/team-plans.git
|
||||
git -C ~/openspec/team-plans push -u origin main
|
||||
```
|
||||
|
||||
Passing `--remote` records the clone URL inside the store's own identity
|
||||
file (`.openspec-store/store.yaml`), in the initial commit. Every future
|
||||
clone is born knowing where it came from, so health checks and error
|
||||
messages can print a complete, pasteable fix for teammates who don't have
|
||||
it yet.
|
||||
|
||||
**Every teammate (once per machine):**
|
||||
|
||||
```bash
|
||||
git clone git@github.com:acme/team-plans.git ~/openspec/team-plans
|
||||
openspec store register ~/openspec/team-plans
|
||||
```
|
||||
|
||||
From then on, everyone works in the same planning repo by name:
|
||||
|
||||
```bash
|
||||
openspec status --store team-plans --change add-login
|
||||
openspec show add-login --store team-plans
|
||||
```
|
||||
|
||||
**Sharing work is git, on purpose.** A change you create exists only in
|
||||
your checkout until you commit and push it — same as code. Plans get
|
||||
branches, pull requests, and review for free, because a store is an
|
||||
ordinary repo.
|
||||
|
||||
**Connecting the team's code repos.** A code repo whose planning is fully
|
||||
externalized needs exactly one line, in `openspec/config.yaml`:
|
||||
|
||||
```yaml
|
||||
# web-app/openspec/config.yaml
|
||||
store: team-plans
|
||||
```
|
||||
|
||||
Now every OpenSpec command run inside `web-app` acts on `team-plans` with
|
||||
no flags at all:
|
||||
|
||||
```bash
|
||||
cd ~/src/web-app
|
||||
openspec status --change add-login
|
||||
```
|
||||
|
||||
```
|
||||
Using OpenSpec root: team-plans (/Users/you/openspec/team-plans)
|
||||
...
|
||||
```
|
||||
|
||||
The pointer is a fallback, never an override: an explicit `--store` always
|
||||
wins, and if the repo grows real planning folders of its own, those win
|
||||
(with a warning to remove the stale pointer).
|
||||
|
||||
**One default for every repo on your machine.** If you work across many
|
||||
code repos that all plan into the same store, set it once, globally,
|
||||
instead of adding the `store:` line to each repo:
|
||||
|
||||
```bash
|
||||
openspec config set defaultStore team-plans
|
||||
```
|
||||
|
||||
Now any command run outside a planning root — and with no `--store` and no
|
||||
project pointer — resolves to `team-plans`. It sits at the bottom of the
|
||||
precedence list, so `--store`, a local root, and a project `store:` pointer
|
||||
all still win. The root banner and JSON `root` block report
|
||||
`source: "global_default"` with the store id, so you can always tell a
|
||||
machine-wide default from a repo's own pointer. Clear it with
|
||||
`openspec config unset defaultStore`. If the id is not registered, commands
|
||||
error and tell you to register it or clear the stale default.
|
||||
|
||||
## Example: one feature, two component repos
|
||||
|
||||
Suppose `add-checkout-promo` changes both `checkout-api` and
|
||||
`checkout-web`. The team wants one shared product contract, while each code
|
||||
repo still needs its own implementation tasks, branch, and review.
|
||||
|
||||
Use two layers:
|
||||
|
||||
1. Keep the shared behavior in `team-plans`.
|
||||
2. Keep implementation plans in each component repo and reference the store
|
||||
as read-only upstream context.
|
||||
|
||||
First, plan the shared contract in the store:
|
||||
|
||||
```bash
|
||||
openspec new change add-checkout-promo --store team-plans
|
||||
openspec status --change add-checkout-promo --store team-plans
|
||||
```
|
||||
|
||||
The proposal and specs should describe the behavior at the boundary between
|
||||
the components — for example, the promotion fields returned by the service
|
||||
and how the frontend handles an ineligible checkout. Review this change in
|
||||
the store repo like any other branch and pull request.
|
||||
|
||||
### What context does planning see?
|
||||
|
||||
Selecting a store changes the OpenSpec root; it does not discover or read
|
||||
every code repo that uses that store. Store instructions see the artifacts
|
||||
and configured context in the store. They see component code only when those
|
||||
folders are also available to the agent or editor and the agent reads them.
|
||||
|
||||
A workset is a convenient way to open the planning store and both code repos
|
||||
together:
|
||||
|
||||
```bash
|
||||
openspec workset create checkout-promo \
|
||||
--member ~/openspec/team-plans \
|
||||
--member ~/src/checkout-api \
|
||||
--member ~/src/checkout-web \
|
||||
--tool code
|
||||
openspec workset open checkout-promo
|
||||
```
|
||||
|
||||
This makes the folders visible in one IDE workspace. It does not copy source
|
||||
context into the store, select affected repos, or grant an agent permission
|
||||
to edit them. Put durable cross-component facts in the shared specs; do not
|
||||
rely on a planner remembering source it happened to inspect.
|
||||
|
||||
### How does implementation start in each repo?
|
||||
|
||||
When no explicit `--store` or nearer `openspec/` root applies, a
|
||||
`store: team-plans` pointer routes commands to that store. It does not split
|
||||
one store task list by the directory from which `apply` was invoked. OpenSpec
|
||||
currently does not route tasks to repos.
|
||||
|
||||
When each component needs an independently scoped apply/review cycle, give it
|
||||
a local OpenSpec root and reference the central store instead of pointing at
|
||||
it:
|
||||
|
||||
```yaml
|
||||
# checkout-api/openspec/config.yaml (and likewise in checkout-web)
|
||||
schema: spec-driven
|
||||
references:
|
||||
- team-plans
|
||||
```
|
||||
|
||||
After the shared contract is approved and available in the store's main
|
||||
specs, create a small local change for the component's part:
|
||||
|
||||
```bash
|
||||
cd ~/src/checkout-api
|
||||
openspec new change implement-checkout-promo-api
|
||||
|
||||
cd ~/src/checkout-web
|
||||
openspec new change implement-checkout-promo-ui
|
||||
```
|
||||
|
||||
The reference index in each repo's instructions supplies the store spec's
|
||||
summary and exact `openspec show ... --store team-plans` fetch command. Each
|
||||
local proposal cites that shared contract, and its tasks describe only work
|
||||
in that component. Then run `/opsx:apply` in each repo separately; root
|
||||
resolution keeps the artifacts and implementation edits scoped to that repo.
|
||||
The service and frontend changes can now be tested, reviewed, merged, and
|
||||
archived independently.
|
||||
|
||||
If implementation must begin while the shared store change is still active,
|
||||
fetch it explicitly with
|
||||
`openspec show add-checkout-promo --store team-plans`; reference indexes list
|
||||
canonical store specs, not active store changes. Keep the store branch and
|
||||
component branches linked in their pull-request descriptions so reviewers
|
||||
can see which version of the contract each implementation follows.
|
||||
|
||||
## Story: requirements that cross team lines
|
||||
|
||||
A platform team owns the requirements. Product teams build against them,
|
||||
in their own repos, with their own designs. A reference describes that
|
||||
relationship without moving anyone's work.
|
||||
|
||||
```
|
||||
platform-reqs (store) api-server (code repo)
|
||||
owned by the platform team owned by a product team
|
||||
┌──────────────────────────┐ ┌──────────────────────────┐
|
||||
│ openspec/specs/ │ ◀────────│ openspec/config.yaml │
|
||||
│ payments/spec.md │ reads │ references: │
|
||||
│ auth/spec.md │ │ - platform-reqs │
|
||||
│ │ │ openspec/specs/ │
|
||||
│ openspec/changes/ │ │ (their own designs) │
|
||||
│ platform work │ │ openspec/changes/ │
|
||||
│ │ │ (their own work) │
|
||||
│ │ └──────────────────────────┘
|
||||
└──────────────────────────┘
|
||||
```
|
||||
|
||||
**The product team declares what it draws on** in its repo's
|
||||
`openspec/config.yaml`:
|
||||
|
||||
```yaml
|
||||
references:
|
||||
- platform-reqs
|
||||
```
|
||||
|
||||
References are read-only context. The repo keeps its own `openspec/` root;
|
||||
work stays there. What changes: `openspec instructions` in that repo now
|
||||
includes an index of the referenced store's specs — each with a one-line
|
||||
summary and the exact fetch command (`openspec show <spec-id> --type spec
|
||||
--store platform-reqs`). An agent working in `api-server` can find the
|
||||
upstream payment requirements, cite them, and write its low-level design in
|
||||
the repo's own root — without anyone pasting context around.
|
||||
|
||||
A reference can carry its clone source, so teammates who don't have the
|
||||
store yet get a complete fix instead of a dead end:
|
||||
|
||||
```yaml
|
||||
references:
|
||||
- { id: platform-reqs, remote: "git@github.com:acme/platform-reqs.git" }
|
||||
```
|
||||
|
||||
**When you want the plan and code open together, make a workset.** This is
|
||||
personal and explicit: each person chooses the folders they actually work
|
||||
with on their machine. Nothing about those local checkout paths is
|
||||
committed to the shared planning repo.
|
||||
|
||||
```bash
|
||||
openspec workset create platform \
|
||||
--member ~/openspec/platform-reqs \
|
||||
--member ~/src/api-server \
|
||||
--member ~/src/web-app
|
||||
```
|
||||
|
||||
## Two questions you can always ask
|
||||
|
||||
**"Is my setup healthy?"** — `openspec doctor` checks the current root and
|
||||
its referenced stores, read-only, with a pasteable fix per finding:
|
||||
|
||||
```
|
||||
Doctor
|
||||
|
||||
Root
|
||||
Location: /Users/you/src/api-server
|
||||
OpenSpec root: ok
|
||||
|
||||
References
|
||||
- platform-reqs: ok (/Users/you/openspec/platform-reqs)
|
||||
- design-system: Referenced store 'design-system' is not registered on this machine.
|
||||
Fix: git clone -- git@github.com:acme/design-system.git '/Users/you/openspec/design-system' && openspec store register '/Users/you/openspec/design-system' --id design-system
|
||||
|
||||
```
|
||||
|
||||
**"What am I working with?"** — `openspec context` assembles the working
|
||||
set from OpenSpec declarations: the root and the stores it references.
|
||||
|
||||
```
|
||||
Working context for api-server (/Users/you/src/api-server)
|
||||
|
||||
OpenSpec root
|
||||
api-server /Users/you/src/api-server
|
||||
|
||||
Referenced stores
|
||||
platform-reqs /Users/you/openspec/platform-reqs
|
||||
Fetch: openspec show <spec-id> --type spec --store platform-reqs
|
||||
```
|
||||
|
||||
Both support `--json` for agents. `openspec context --code-workspace
|
||||
<path>` additionally writes a VS Code workspace file containing the whole
|
||||
set — the only write this command performs.
|
||||
|
||||
## Worksets: reopen the folders you work on together
|
||||
|
||||
Separate from all of the above: most people open the same few folders
|
||||
together every session — the planning repo plus two or three code repos.
|
||||
A **workset** is a personal, named view of exactly that, reopened with one
|
||||
command in your tool of choice.
|
||||
|
||||
```
|
||||
workset "platform" openspec workset open platform
|
||||
├── team-plans ~/openspec/team-plans │
|
||||
├── api-server ~/src/api-server ▼
|
||||
└── web-app ~/src/web-app all three open in your tool
|
||||
```
|
||||
|
||||
```bash
|
||||
openspec workset create platform \
|
||||
--member ~/openspec/team-plans --member ~/src/api-server \
|
||||
--tool code
|
||||
openspec workset list
|
||||
```
|
||||
|
||||
```
|
||||
platform (opens in VS Code)
|
||||
team-plans /Users/you/openspec/team-plans
|
||||
api-server /Users/you/src/api-server
|
||||
```
|
||||
|
||||
`openspec workset open platform` then launches the saved tool: editors
|
||||
(VS Code, Cursor) open one window with every member and return. The first
|
||||
member is the primary. Override the tool any time with `--tool <id>`.
|
||||
|
||||
Worksets are deliberately *not* shared state. They live on your machine,
|
||||
are never committed, and make no claims about the work — they only record
|
||||
what you like open together. Removing one never touches the member
|
||||
folders. New tools are configuration, not code: anything launched via a
|
||||
workspace file or per-folder attach flags can be added under the `openers`
|
||||
key in the global config (`openspec config edit`).
|
||||
|
||||
## How commands decide where to act
|
||||
|
||||
Every normal command resolves its root the same way, in this order:
|
||||
|
||||
```
|
||||
1. --store <id> you said so explicitly → that store
|
||||
2. nearest openspec/ a real planning root here → this repo
|
||||
(walking up from cwd)
|
||||
3. store: pointer config.yaml declares a store → that store
|
||||
4. defaultStore global config sets a machine → that store
|
||||
default
|
||||
5. none of the above stores registered on this → error with a
|
||||
machine? selection hint
|
||||
no stores registered? → the current
|
||||
directory
|
||||
(classic behavior)
|
||||
```
|
||||
|
||||
The `Using OpenSpec root:` line (and the `root` block in `--json` output)
|
||||
tells you which case you're in.
|
||||
|
||||
## Known limitations
|
||||
|
||||
- **Beta shape.** Everything on this page may change between releases —
|
||||
names, flags, file formats, JSON keys.
|
||||
- **One checkout per store id per machine.** Registering a second checkout
|
||||
under the same id fails with a hint to `store unregister` first.
|
||||
- **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.
|
||||
- **Empty planning folders can be absent.** A new store may not have
|
||||
`openspec/changes/`, `openspec/specs/`, or `openspec/changes/archive/` in Git
|
||||
yet. That is accepted during the beta; those folders appear once normal
|
||||
commands create files for them.
|
||||
- **Pointer repos stay pointers.** A config-only repo whose
|
||||
`openspec/config.yaml` declares `store: <id>` is treated as externalized
|
||||
planning, not as a store checkout to register. Remove the `store:` line first
|
||||
if you intentionally want to convert that repo into a local store root.
|
||||
- **Some commands stay where they are.** `templates` and the
|
||||
deprecated noun forms (`openspec change show`, ...) act on the current
|
||||
directory only — no `--store`. `schemas` follows the canonical root-selection
|
||||
precedence and accepts `--store <id>` while keeping its successful JSON array
|
||||
shape unchanged.
|
||||
- **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.
|
||||
- **Two launch styles for worksets.** A tool that can't be launched with a
|
||||
workspace file or per-folder attach flags can't be added as an opener.
|
||||
- **Agent JSON has a known casing split** (store-family keys are
|
||||
snake_case, workflow-family camelCase). Documented in the
|
||||
[agent contract](../agent-contract.md); unifying it is deferred to a
|
||||
versioned release.
|
||||
|
||||
## Where things live
|
||||
|
||||
| What | Where | Shared? |
|
||||
|---|---|---|
|
||||
| A store's planning | `<store>/openspec/` (specs, changes) | Yes — commit and push it |
|
||||
| A store's identity | `<store>/.openspec-store/store.yaml` | Yes — committed with the store |
|
||||
| The store registry | `<data dir>/openspec/stores/registry.yaml` | No — this machine only |
|
||||
| Worksets | `<data dir>/openspec/worksets/` | No — this machine only |
|
||||
|
||||
`<data dir>` is `~/.local/share/openspec` on macOS and Linux (or
|
||||
`$XDG_DATA_HOME/openspec` when set), and `%LOCALAPPDATA%\openspec` on
|
||||
Windows.
|
||||
|
||||
## Reference
|
||||
|
||||
Exact flags and JSON shapes for every command on this page:
|
||||
[CLI reference](../cli.md) (Stores, Doctor, Working context, Personal
|
||||
worksets) and the [agent contract](../agent-contract.md).
|
||||
@@ -1,257 +0,0 @@
|
||||
# Supported Tools
|
||||
|
||||
OpenSpec works with many AI coding assistants. When you run `openspec init`, OpenSpec configures selected tools using your active profile/workflow selection and delivery mode.
|
||||
|
||||
## How It Works
|
||||
|
||||
For each selected tool, OpenSpec can install:
|
||||
|
||||
1. **Skills** (if delivery includes skills): `.../skills/openspec-*/SKILL.md`
|
||||
2. **Commands** (if delivery includes commands): tool-specific `opsx-*` command files
|
||||
|
||||
Codex is skills-only: OpenSpec installs `.agents/skills/openspec-*/SKILL.md` for Codex even when delivery is set to `commands`, and it does not generate Codex custom prompt files. Existing OpenSpec-managed skills under the legacy `.codex/skills` path are reconciled after their replacements are written; custom and divergent files are preserved.
|
||||
|
||||
By default, OpenSpec uses the `core` profile, which includes:
|
||||
- `propose`
|
||||
- `explore`
|
||||
- `apply`
|
||||
- `update`
|
||||
- `sync`
|
||||
- `archive`
|
||||
|
||||
You can enable expanded workflows (`new`, `continue`, `ff`, `verify`, `bulk-archive`, `onboard`) via `openspec config profile`, then run `openspec update`.
|
||||
|
||||
## How To Invoke
|
||||
|
||||
These docs use `/opsx:propose` as the canonical name, but each tool spells it the
|
||||
way it loads the file OpenSpec wrote. Find your tool's command path in the
|
||||
[Tool Directory Reference](#tool-directory-reference) below, then match its shape here.
|
||||
|
||||
| Command file OpenSpec writes | You type | Tools |
|
||||
|------------------------------|----------|-------|
|
||||
| `.../commands/opsx/<id>.*` — an `opsx/` folder namespaces it | `/opsx:<id>` | Claude Code, CodeBuddy, Crush, Gemini CLI, Lingma, Qoder, ZCode |
|
||||
| `.../opsx-<id>.*` — the filename is the command | `/opsx-<id>` | Every other tool with generated command files, except Amazon Q and Devin |
|
||||
| `.devin/workflows/opsx-<id>.md` — read by only one of Devin's two agents | `/opsx-<id>` on Devin Desktop, `/openspec-<skill>` on Devin Local | Devin Desktop\*\*\*\* |
|
||||
| `.amazonq/prompts/opsx-<id>.md` — a prompt, not a command | `@opsx-<id>` | Amazon Q Developer |
|
||||
| none — skills only | `/openspec-<skill>` | CodeArts, ForgeCode, Hermes, MiniMax Code, Mistral Vibe, Zed Agent, shared `.agents` |
|
||||
| none — Kimi Code | `/skill:openspec-<skill>` | Kimi Code |
|
||||
| none — Codex CLI | `$openspec-<skill>` | Codex ([`/openspec-<skill>` is not recognized](https://github.com/openai/codex/issues/11817)) |
|
||||
|
||||
So `/opsx:propose` is `/opsx-propose` in Cursor, `@opsx-propose` in Amazon Q, and
|
||||
`$openspec-propose` in Codex.
|
||||
|
||||
Two things vary independently, which is why the rows do not collapse:
|
||||
|
||||
- **The name.** Rows 1–2 differ only in how the file names the command, and the
|
||||
`opsx-<id>` / `opsx:<id>` stem is the same for every tool with generated
|
||||
command files.
|
||||
- **The wrapper.** Amazon Q loads its files into a prompt library invoked with
|
||||
`@`. Skills-only tools generate no command files at all, so their last three
|
||||
rows use *skill* names — listed under
|
||||
[Generated Skill Names](#generated-skill-names) — which do not map one-to-one
|
||||
onto command ids (`/opsx:apply` is the `openspec-apply-change` skill).
|
||||
|
||||
The command path patterns above are extension-neutral (`.*`) on purpose: the
|
||||
extension is the tool's (`.toml` for Gemini CLI, `.prompt` for Continue,
|
||||
`.prompt.md` for Kiro and GitHub Copilot), and a few tools show the name with
|
||||
its extension in the picker. Match the directory shape, not the extension.
|
||||
|
||||
The files OpenSpec generates, and the "Getting started" hint printed after setup,
|
||||
already use the right form for the tools you selected — so the fastest answer is
|
||||
to read the hint.
|
||||
|
||||
## Tool Directory Reference
|
||||
|
||||
| Tool (ID) | Skills path pattern | Command path pattern |
|
||||
|-----------|---------------------|----------------------|
|
||||
| Amazon Q Developer (`amazon-q`) | `.amazonq/skills/openspec-*/SKILL.md` | `.amazonq/prompts/opsx-<id>.md` |
|
||||
| Antigravity (`antigravity`) | `.agent/skills/openspec-*/SKILL.md` | `.agent/workflows/opsx-<id>.md` |
|
||||
| Auggie (`auggie`) | `.augment/skills/openspec-*/SKILL.md` | `.augment/commands/opsx-<id>.md` |
|
||||
| IBM Bob Shell (`bob`) | `.bob/skills/openspec-*/SKILL.md` | `.bob/commands/opsx-<id>.md` |
|
||||
| Claude Code (`claude`) | `.claude/skills/openspec-*/SKILL.md` | `.claude/commands/opsx/<id>.md` |
|
||||
| Cline (`cline`) | `.cline/skills/openspec-*/SKILL.md` | `.clinerules/workflows/opsx-<id>.md` |
|
||||
| Command Code (`command-code`) | `.commandcode/skills/openspec-*/SKILL.md` | `.commandcode/commands/opsx-<id>.md` |
|
||||
| CodeArts (`codeartsagent`) | `.codeartsdoer/skills/openspec-*/SKILL.md` | Not generated (no command adapter; use skill-based `/openspec-*` invocations) |
|
||||
| CodeBuddy (`codebuddy`) | `.codebuddy/skills/openspec-*/SKILL.md` | `.codebuddy/commands/opsx/<id>.md` |
|
||||
| Codex (`codex`) | `.agents/skills/openspec-*/SKILL.md` | Not generated (skills-only; use `$openspec-*`) |
|
||||
| Devin Desktop, formerly Windsurf (`devin`) | `.devin/skills/openspec-*/SKILL.md` | `.devin/workflows/opsx-<id>.md`\*\*\*\* |
|
||||
| ForgeCode (`forgecode`) | `.forge/skills/openspec-*/SKILL.md` | Not generated (no command adapter; use skill-based `/openspec-*` invocations) |
|
||||
| Continue (`continue`) | `.continue/skills/openspec-*/SKILL.md` | `.continue/prompts/opsx-<id>.prompt` |
|
||||
| CoStrict (`costrict`) | `.cospec/skills/openspec-*/SKILL.md` | `.cospec/openspec/commands/opsx-<id>.md` |
|
||||
| Crush (`crush`) | `.crush/skills/openspec-*/SKILL.md` | `.crush/commands/opsx/<id>.md` |
|
||||
| Cursor (`cursor`) | `.cursor/skills/openspec-*/SKILL.md` | `.cursor/commands/opsx-<id>.md` |
|
||||
| Factory Droid (`factory`) | `.factory/skills/openspec-*/SKILL.md` | `.factory/commands/opsx-<id>.md` |
|
||||
| Gemini CLI (`gemini`) | `.gemini/skills/openspec-*/SKILL.md` | `.gemini/commands/opsx/<id>.toml` |
|
||||
| GitHub Copilot (`github-copilot`) | `.github/skills/openspec-*/SKILL.md` | `.github/prompts/opsx-<id>.prompt.md`\*\* |
|
||||
| Hermes Agent (`hermes`) | `.hermes/skills/openspec-*/SKILL.md`\*\*\* | Not generated (no command adapter; use skill-based `/openspec-*` invocations) |
|
||||
| iFlow (`iflow`) | `.iflow/skills/openspec-*/SKILL.md` | `.iflow/commands/opsx-<id>.md` |
|
||||
| Junie (`junie`) | `.junie/skills/openspec-*/SKILL.md` | `.junie/commands/opsx-<id>.md` |
|
||||
| Kilo Code (`kilocode`) | `.kilocode/skills/openspec-*/SKILL.md` | `.kilo/command/opsx-<id>.md` |
|
||||
| Kimi Code (`kimi`) | `.kimi-code/skills/openspec-*/SKILL.md` | Not generated (no command adapter; use skill-based `/skill:openspec-*` invocations) |
|
||||
| Kiro (`kiro`) | `.kiro/skills/openspec-*/SKILL.md` | `.kiro/prompts/opsx-<id>.prompt.md` |
|
||||
| Lingma (`lingma`) | `.lingma/skills/openspec-*/SKILL.md` | `.lingma/commands/opsx/<id>.md` |
|
||||
| MiniMax Code (`minimax-code`) | `~/.minimax/skills/openspec-*/SKILL.md` | Not generated (no command adapter; use MiniMax Code skills) |
|
||||
| Mistral Vibe (`vibe`) | `.vibe/skills/openspec-*/SKILL.md` | Not generated (no command adapter; use skill-based `/openspec-*` invocations) |
|
||||
| Oh My Pi (`oh-my-pi`) | `.omp/skills/openspec-*/SKILL.md` | `.omp/commands/opsx-<id>.md` |
|
||||
| OpenCode (`opencode`) | `.opencode/skills/openspec-*/SKILL.md` | `.opencode/commands/opsx-<id>.md` |
|
||||
| Pi (`pi`) | `.pi/skills/openspec-*/SKILL.md` | `.pi/prompts/opsx-<id>.md` |
|
||||
| SourceCraft Code Assistant for VS Code (`codeassistant`) | `.codeassistant/skills/openspec-*/SKILL.md` | `.codeassistant/commands/opsx-<id>.md` |
|
||||
| Qoder (`qoder`) | `.qoder/skills/openspec-*/SKILL.md` | `.qoder/commands/opsx/<id>.md` |
|
||||
| Qwen Code (`qwen`) | `.qwen/skills/openspec-*/SKILL.md` | `.qwen/commands/opsx-<id>.md` |
|
||||
| [Rovo Dev CLI](https://support.atlassian.com/rovo/docs/use-rovo-dev-cli/) (`rovodev`) | `.rovodev/skills/openspec-*/SKILL.md` | Not generated. Rovo has no slash-command surface — it matches skills automatically or by prompt (e.g. "use the openspec-propose skill"); `/skills` only manages them. Generated content references skills by name, never as `/openspec-*` commands. |
|
||||
| [Zoo Code](https://github.com/Zoo-Code-Org/Zoo-Code) (`roocode`) | `.roo/skills/openspec-*/SKILL.md` | `.roo/commands/opsx-<id>.md` |
|
||||
| Trae (`trae`) | `.trae/skills/openspec-*/SKILL.md` | `.trae/commands/opsx-<id>.md` |
|
||||
| [Zed Agent](https://zed.dev/docs/ai/skills) (`zed`) | `.agents/skills/openspec-*/SKILL.md` | Not generated (skills-only; use `/openspec-*` or `@openspec-*`) |
|
||||
| ZCode (`zcode`) | `.zcode/skills/openspec-*/SKILL.md` | `.zcode/commands/opsx/<id>.md` |
|
||||
| Shared `.agents` skills (`agents`) | `.agents/skills/openspec-*/SKILL.md` | Not generated (no command adapter; use skill-based `/openspec-*` invocations) |
|
||||
|
||||
\*\* GitHub Copilot prompt files are recognized as custom slash commands in IDE extensions (VS Code, JetBrains, Visual Studio). Copilot CLI does not currently consume `.github/prompts/*.prompt.md` directly. Selecting `github-copilot` can also set up the GitHub-hosted **cloud coding agent** — see [GitHub Copilot cloud coding agent](#github-copilot-cloud-coding-agent) below.
|
||||
|
||||
\*\*\* Hermes loads skills from `~/.hermes/skills/` by default. To use project-local OpenSpec skills, add the project `.hermes/skills/` directory to `skills.external_dirs` in `~/.hermes/config.yaml`; Hermes then exposes skills with user-facing slash invocations such as `/openspec-propose`.
|
||||
|
||||
\*\*\*\* Windsurf was [rebranded to Devin Desktop](https://docs.devin.ai/desktop/devin-desktop-faq) on June 2, 2026, and its config directory moved: `.devin/` is the preferred read + write location, `.windsurf/` a legacy read-only fallback. OpenSpec follows the rename — the tool id is `devin`, and `--tools windsurf` still resolves to it so existing setup scripts keep working. A project still holding OpenSpec files in `.windsurf/` is offered the move on the next `openspec update`; declining leaves them in place, and files you wrote yourself are never touched. Workflows are invoked by filename, so `.devin/workflows/opsx-apply.md` is `/opsx-apply`. The [Devin Local agent does not support workflows](https://docs.devin.ai/desktop/devin-local) — only skills, and it does not read `.windsurf/` at all — so whenever OpenSpec writes Devin skills it keeps their bodies, and the getting-started hint, on `/openspec-*` skill invocations, which work on both agents. Under commands-only delivery no skills are written and both fall back to `/opsx-*`.
|
||||
|
||||
SourceCraft Code Assistant support targets its VS Code extension. Its [custom commands](https://sourcecraft.dev/portal/docs/en/code-assistant/operations/agent/slash-commands) and [skills](https://sourcecraft.dev/portal/docs/ru/code-assistant/operations/agent/skills) are available only in VS Code. This integration does not configure SourceCraft web or JetBrains.
|
||||
|
||||
With skills-only delivery, ask Code Assistant to use the `openspec-propose` skill with your idea. Skills activate through request matching; OpenSpec does not generate `/openspec-*` commands for this tool.
|
||||
|
||||
MiniMax Code is a global skills-only integration. OpenSpec writes only its
|
||||
`openspec-*` directories under `~/.minimax/skills/`; it does not create
|
||||
repo-local `.minimax` or `.mavis` directories. Commands-only delivery leaves
|
||||
existing global MiniMax Code skills untouched so one project's delivery setting
|
||||
cannot remove skills used by another project.
|
||||
|
||||
### GitHub Copilot cloud coding agent
|
||||
|
||||
GitHub's [Copilot coding agent](https://docs.github.com/en/copilot/using-github-copilot/coding-agent) runs on GitHub in a GitHub Actions environment — separate from Copilot in your editor. OpenSpec can set it up to use the OpenSpec CLI by generating two files:
|
||||
|
||||
- `.github/workflows/copilot-setup-steps.yml` — installs `@fission-ai/openspec` in the agent's environment
|
||||
- `.github/agents/openspec.agent.md` — tells the agent how to drive OpenSpec
|
||||
|
||||
Because this writes a GitHub Actions workflow into your repository, it is **opt-in**:
|
||||
|
||||
| How | Behavior |
|
||||
|-----|----------|
|
||||
| `openspec init` (interactive) | Asks whether to set up cloud files. Default is **No**. |
|
||||
| `openspec init --copilot-cloud` | Sets them up without prompting (for scripts/CI). |
|
||||
| `openspec init --no-copilot-cloud` | Skips them without prompting, and removes any previously generated ones. |
|
||||
| `openspec update` | Never prompts. Refreshes the files only if you opted in (or the project already has them). If you opted out, it removes OpenSpec-managed cloud files. |
|
||||
|
||||
Your choice is saved in `openspec/config.yaml` as `githubCopilot.cloudAgent: true|false`, so non-interactive updates honor it. OpenSpec only ever writes or removes files whose content it generated — if you customize `copilot-setup-steps.yml` or `openspec.agent.md`, or already have your own, it is left untouched (and `init`/`update` tell you so).
|
||||
|
||||
### When to pick the shared `.agents` target
|
||||
|
||||
`agents` is the vendor-neutral option: it writes skills to `.agents/skills/`, the
|
||||
shared root many agent tools read, instead of a tool-specific directory.
|
||||
|
||||
| Situation | Pick |
|
||||
|-----------|------|
|
||||
| Your tool has its own row above | Its own ID — you get that tool's integration, including slash commands where it supports them |
|
||||
| Several agents on one repo, all reading `.agents/skills` | `agents` — one skill tree instead of one per tool |
|
||||
| Your tool isn't listed yet but reads `.agents/skills` | `agents` |
|
||||
|
||||
Selecting it alongside a tool-specific ID is fine; each normally writes to its
|
||||
own root. Codex and Zed Agent are the exceptions because they use the same canonical
|
||||
`.agents` root. If Codex is selected with Zed or `agents`, OpenSpec keeps one
|
||||
Codex-led tree. Its handoffs name both `$openspec-*` for Codex and
|
||||
`/openspec-*` for other agents, so `--tools all` and existing multi-agent
|
||||
setups keep working without two writers overwriting the same files.
|
||||
OpenSpec also offers it automatically once a project has a `.agents/skills/`
|
||||
directory — a bare `.agents/` is not enough, since tools use that root for rules
|
||||
and subagent definitions too. Note `.agents` is not `.agent`: the singular
|
||||
directory belongs to Antigravity.
|
||||
|
||||
Two things to know:
|
||||
|
||||
- **Skills only.** No command adapter exists, so no `opsx-*` command files are
|
||||
written; with a commands-inclusive delivery mode `openspec init` lists `agents`
|
||||
among the tools it reports under `Commands skipped for: … (no adapter)`.
|
||||
Invoke the workflows by skill name —
|
||||
most assistants that read `.agents/skills` spell that `/openspec-propose`, the form
|
||||
OpenSpec's setup hint prints. The target is vendor-neutral, so check your
|
||||
assistant's own docs if it uses another form.
|
||||
- **No `AGENTS.md` is created or edited.** The target is the `.agents/` directory.
|
||||
If your root `AGENTS.md` still carries OpenSpec marker blocks from an older
|
||||
version, `openspec update` strips them — see the [Migration Guide](migration-guide.md).
|
||||
|
||||
Zed support here is for the built-in Zed Agent. Zed External Agents and Terminal
|
||||
Threads use their own integrations. Agent Skills require
|
||||
[Zed v1.4.2](https://github.com/zed-industries/zed/releases/tag/v1.4.2) or newer.
|
||||
Project-local skills are unavailable in an untrusted worktree until you
|
||||
[grant trust](https://zed.dev/docs/worktree-trust).
|
||||
|
||||
Because `.agents/skills/` is shared by Codex, Zed Agent, and the vendor-neutral target,
|
||||
it is worth knowing what OpenSpec claims there:
|
||||
it writes, refreshes, and removes only the `openspec-*` skill directories for your
|
||||
selected workflows, plus an `.openspec-target` marker that records whether Codex,
|
||||
Zed Agent, or the vendor-neutral target rendered that shared tree. Anything else in that
|
||||
directory is left alone. Treat the `openspec-*` names and marker as OpenSpec's —
|
||||
edits inside them are replaced on the next `openspec update`, the same as for
|
||||
every other tool.
|
||||
|
||||
For pre-marker projects, OpenSpec infers ownership from managed skill references:
|
||||
`$openspec-*` means Codex and `/openspec-*` means the vendor-neutral target. A
|
||||
generic canonical tree alongside legacy `.codex/skills` is treated as an older
|
||||
dual-target install and consolidated into the compatible shared tree.
|
||||
|
||||
`openspec update` honors this ownership too. If a project owns `.agents` as the
|
||||
vendor-neutral target and a leftover Codex install is detected only from stray
|
||||
prompt files, the update leaves the established `agents` tree in place instead of
|
||||
rewriting it with Codex syntax, and preserves those legacy prompt files rather
|
||||
than deleting them. To hand the shared tree to Codex, run `openspec init --tools
|
||||
codex` explicitly.
|
||||
|
||||
## Non-Interactive Setup
|
||||
|
||||
For CI/CD or scripted setup, use `--tools` (and optionally `--profile`):
|
||||
|
||||
```bash
|
||||
# Configure specific tools
|
||||
openspec init --tools claude,cursor
|
||||
|
||||
# Configure all supported tools
|
||||
openspec init --tools all
|
||||
|
||||
# Skip tool configuration
|
||||
openspec init --tools none
|
||||
|
||||
# Override profile for this init run
|
||||
openspec init --profile core
|
||||
```
|
||||
|
||||
**Available tool IDs (`--tools`)** — `windsurf` is also accepted, as an alias for `devin`: `amazon-q`, `antigravity`, `auggie`, `bob`, `claude`, `cline`, `command-code`, `codeartsagent`, `codex`, `devin`, `forgecode`, `codebuddy`, `continue`, `costrict`, `crush`, `cursor`, `factory`, `gemini`, `github-copilot`, `hermes`, `iflow`, `junie`, `kilocode`, `kimi`, `kiro`, `lingma`, `minimax-code`, `vibe`, `oh-my-pi`, `opencode`, `pi`, `qoder`, `qwen`, `roocode`, `codeassistant`, `trae`, `zed`, `zcode`, `agents`
|
||||
|
||||
## Workflow-Dependent Installation
|
||||
|
||||
OpenSpec installs workflow artifacts based on selected workflows:
|
||||
|
||||
- **Core profile (default):** `propose`, `explore`, `apply`, `update`, `sync`, `archive`
|
||||
- **Custom selection:** any subset of all workflow IDs:
|
||||
`propose`, `explore`, `new`, `continue`, `apply`, `update`, `ff`, `sync`, `archive`, `bulk-archive`, `verify`, `onboard`
|
||||
|
||||
In other words, skill/command counts are profile-dependent and delivery-dependent, not fixed.
|
||||
|
||||
## Generated Skill Names
|
||||
|
||||
When selected by profile/workflow config, OpenSpec generates these skills:
|
||||
|
||||
- `openspec-propose`
|
||||
- `openspec-explore`
|
||||
- `openspec-new-change`
|
||||
- `openspec-continue-change`
|
||||
- `openspec-apply-change`
|
||||
- `openspec-update-change`
|
||||
- `openspec-ff-change`
|
||||
- `openspec-sync-specs`
|
||||
- `openspec-archive-change`
|
||||
- `openspec-bulk-archive-change`
|
||||
- `openspec-verify-change`
|
||||
- `openspec-onboard`
|
||||
|
||||
See [Commands](commands.md) for command behavior and [CLI](cli.md) for `init`/`update` options.
|
||||
|
||||
## Related
|
||||
|
||||
- [CLI Reference](cli.md) — Terminal commands
|
||||
- [Commands](commands.md) — Slash commands and skills
|
||||
- [Getting Started](getting-started.md) — First-time setup
|
||||
@@ -1,74 +0,0 @@
|
||||
# OpenSpec on a Team
|
||||
|
||||
Everything in the other guides works the same whether you're solo or on a team of twenty. What changes on a team is the questions around the edges: where do the specs live, how do teammates review a plan, and how does any of this fit the pull-request flow we already have?
|
||||
|
||||
The short answer: a change is just files, and OpenSpec never touches git. So it fits your existing workflow instead of replacing it. This page spells out the conventions that work well.
|
||||
|
||||
## One rule: OpenSpec doesn't touch git
|
||||
|
||||
OpenSpec reads and writes plain Markdown under `openspec/`. It never commits, branches, pushes, or pulls in your project — and it never clones or syncs a [store](stores-beta/user-guide.md) on its own. That means:
|
||||
|
||||
- **You commit `openspec/` like any source.** Specs, active changes, and the archive are part of your project's history. (Yes, commit the whole folder — see the [FAQ](faq.md#should-i-commit-the-openspec-folder-to-git).)
|
||||
- **A change is a folder you version like code.** `openspec/changes/add-dark-mode/` is just files on a branch.
|
||||
- **Everything below is convention, not enforcement.** OpenSpec won't make you do it this way; it just fits cleanly.
|
||||
|
||||
## The everyday loop
|
||||
|
||||
The workflow that works well maps a change onto a branch and a pull request:
|
||||
|
||||
```
|
||||
git switch -c add-dark-mode start a branch, as usual
|
||||
│
|
||||
/opsx:propose add-dark-mode draft the plan (proposal + specs + tasks)
|
||||
│
|
||||
REVIEW THE PLAN you read it before any code — see Reviewing a Change
|
||||
│
|
||||
/opsx:apply build it; artifacts + code change together
|
||||
│
|
||||
git commit && open a PR the PR contains the spec delta AND the code
|
||||
│
|
||||
teammate reviews, merges
|
||||
│
|
||||
/opsx:archive fold the delta into specs/, move the change to archive/
|
||||
```
|
||||
|
||||
The plan and the code live side by side in the same branch, so your teammates review both together, and six months later the archived spec still explains why the code looks the way it does.
|
||||
|
||||
## Reviewing specs in a pull request
|
||||
|
||||
This is where a team feels the payoff. When a PR includes the change's delta spec, the reviewer gets something a raw diff never gives them: **a plain-language statement of what this change is supposed to do**, before they read a single line of code.
|
||||
|
||||
A good review order for the reviewer:
|
||||
|
||||
1. **Read `proposal.md`** — is this the right problem and scope?
|
||||
2. **Read the delta under `specs/`** — is "done" defined correctly? (This is the [Reviewing a Change](reviewing-changes.md) two-minute pass, now happening in the PR.)
|
||||
3. **Then read the code diff** — does it deliver exactly those requirements?
|
||||
|
||||
A reviewer who disagrees with the *approach* can say so against the proposal, cheaply, instead of relitigating it across 300 lines of code. Put the delta spec near the top of the PR description, or point reviewers at the change folder, so they start there.
|
||||
|
||||
## When to archive
|
||||
|
||||
Archiving folds a change's deltas into your main `openspec/specs/` and moves the change folder to `openspec/changes/archive/YYYY-MM-DD-<name>/`. Because `specs/` is the **shared source of truth**, the timing matters on a team. Two workable conventions:
|
||||
|
||||
- **Archive after the PR merges (recommended).** The branch carries the active change; once it's merged to your main branch, archive there (often a tiny follow-up commit or a scheduled cleanup). This keeps the shared `specs/` moving forward only with work that actually shipped.
|
||||
- **Archive inside the PR.** Simpler for small teams: the same PR that adds the code also syncs and archives. The tradeoff is that your `specs/` diff and your code diff land together, which can make the PR noisier.
|
||||
|
||||
Pick one and be consistent. Either way, `/opsx:archive` checks that tasks are complete and offers to sync first, so nothing merges half-finished by accident.
|
||||
|
||||
## Two people, parallel changes
|
||||
|
||||
Because changes are separate folders, they don't collide:
|
||||
|
||||
- **Different changes, different people — no problem.** `add-dark-mode` and `rate-limit-login` are different folders on different branches; they never touch each other until they both archive.
|
||||
- **One change, one owner.** Two people editing the same change folder conflict exactly like two people editing the same file. Keep a change to a single author, or split it into two changes (another reason to [right-size](writing-specs.md#right-size-the-change)).
|
||||
- **The one place conflicts show up is `specs/`.** If two changes both modify the *same* requirement, archiving the second one will conflict in `openspec/specs/…/spec.md` — resolve it like any merge conflict, keeping the requirement that reflects reality. This is rare, and it's a feature: it's git telling you two changes disagreed about how the system should behave.
|
||||
|
||||
## When planning outgrows one repo
|
||||
|
||||
Everything above assumes the plan lives in the code repo's own `openspec/` folder, which is the right default. When your planning genuinely spans several repos or teams — one feature touching three services, or requirements one team owns and others consume — that's what the beta **stores** feature is for: planning gets its own repo that any code repo can point at. Start with the [Stores User Guide](stores-beta/user-guide.md).
|
||||
|
||||
## Where to go next
|
||||
|
||||
- [Reviewing a Change](reviewing-changes.md) — the review pass, now inside your PR.
|
||||
- [Writing Good Specs](writing-specs.md) — including how to right-size a change so it fits one branch.
|
||||
- [Stores User Guide](stores-beta/user-guide.md) — planning that spans repos and teams.
|
||||
@@ -1,195 +0,0 @@
|
||||
# Troubleshooting
|
||||
|
||||
Concrete fixes for concrete problems. Each entry names a symptom, explains the likely cause in a sentence, and gives you the fix. If you don't see your issue here, the [FAQ](faq.md) may help, and the [Discord](https://discord.gg/YctCnvvshC) definitely will.
|
||||
|
||||
## Installation and setup
|
||||
|
||||
### `openspec: command not found`
|
||||
|
||||
The CLI isn't installed, or your shell can't find it. Install it globally and check:
|
||||
|
||||
```bash
|
||||
npm install -g @fission-ai/openspec@latest
|
||||
openspec --version
|
||||
```
|
||||
|
||||
If it installed but still isn't found, your global npm bin directory probably isn't on your `PATH`. Run `npm prefix -g` to see where global packages live: on macOS and Linux the binaries are in that directory's `bin/`, and on Windows they sit directly in it. Make sure that path is on your `PATH`. (`npm bin -g` was removed in npm 9.)
|
||||
|
||||
If you used the [AI-assisted install](installation.md#install-with-your-ai-assistant), this is the expected hand-off point: that prompt tells your assistant to show you the `PATH` change rather than edit your shell startup files itself.
|
||||
|
||||
### "Requires Node.js 20.19.0 or higher"
|
||||
|
||||
OpenSpec runs on Node 20.19.0+. Check your version and upgrade if needed:
|
||||
|
||||
```bash
|
||||
node --version
|
||||
```
|
||||
|
||||
If you use bun to install OpenSpec, note that OpenSpec still *runs* on Node, so you need Node 20.19.0+ available on your `PATH` regardless. See [Installation](installation.md).
|
||||
|
||||
### `openspec init` didn't configure my AI tool
|
||||
|
||||
Init asks which tools to set up. If you skipped your tool or want to add another, just run it again, or use the non-interactive form:
|
||||
|
||||
```bash
|
||||
openspec init --tools claude,cursor
|
||||
```
|
||||
|
||||
The full list of tool IDs is in [Supported Tools](supported-tools.md). Use `--tools all` for everything, `--tools none` to skip tool setup.
|
||||
|
||||
## Commands don't show up
|
||||
|
||||
If `/opsx:propose` (or your tool's equivalent) doesn't appear or doesn't do anything, work down this list. They're ordered fastest-to-check first.
|
||||
|
||||
1. **You may be in the wrong place.** Slash commands go in your AI assistant's chat, not your terminal. If you typed `/opsx:propose` into your shell, that's the issue. See [How Commands Work](how-commands-work.md).
|
||||
|
||||
2. **Regenerate the files.** From your project root:
|
||||
|
||||
```bash
|
||||
openspec update
|
||||
```
|
||||
|
||||
This rewrites the skill and command files for every tool you've configured.
|
||||
|
||||
Instruction files come from the *installed* CLI, so an outdated CLI reports everything up to date without ever writing the newer workflows. `openspec update` now checks for that and offers to upgrade — take the offer if you see it.
|
||||
|
||||
3. **Restart your assistant.** Most tools scan for skills and commands at startup. A fresh window often does it.
|
||||
|
||||
4. **Confirm the files exist.** For Claude Code, check that `.claude/skills/` contains `openspec-*` folders. Other tools use their own directories, all listed in [Supported Tools](supported-tools.md).
|
||||
|
||||
5. **Check you initialized this project.** Skills are written per project. If you cloned a repo or switched folders, run `openspec init` (or `openspec update`) there.
|
||||
|
||||
6. **Confirm your tool supports command files.** Codex, CodeArts, ForgeCode, Hermes, Kimi Code, Mistral Vibe, Zed Agent, and the shared `.agents` target don't get generated `opsx-*` command files; they use skill-based invocations instead, so `/opsx` will never autocomplete for them. Type `$openspec-propose` in Codex, `/skill:openspec-propose` in Kimi Code, and `/openspec-propose` in the rest. The shared `.agents` target is vendor-neutral, so `/openspec-propose` is the common form rather than a guaranteed one — if your assistant does not answer to it, check its own docs for how it invokes a skill. Amazon Q does get command files, but loads them into its prompt library rather than its slash menu — type `@opsx-propose` there, not `/opsx`. Every tool's form is listed in [How To Invoke](supported-tools.md#how-to-invoke).
|
||||
|
||||
## Working with changes
|
||||
|
||||
### "Change not found"
|
||||
|
||||
The command couldn't tell which change you meant. Name it explicitly, or check what exists:
|
||||
|
||||
```bash
|
||||
openspec list # see active changes
|
||||
/opsx:apply add-dark-mode # name the change in chat
|
||||
```
|
||||
|
||||
Also confirm you're in the right project directory.
|
||||
|
||||
### "No artifacts ready"
|
||||
|
||||
Every artifact is either already created or blocked waiting on a dependency. See what's blocking:
|
||||
|
||||
```bash
|
||||
openspec status --change <name>
|
||||
```
|
||||
|
||||
Then create the missing dependency first. Remember the order: proposal enables specs and design; specs and design together enable tasks.
|
||||
|
||||
### `openspec validate` reports warnings or errors
|
||||
|
||||
Validation checks your specs and changes for structural problems. Read the message: it names the file and the issue.
|
||||
|
||||
```bash
|
||||
openspec validate <name> # validate one item
|
||||
openspec validate --all # validate everything
|
||||
openspec validate --all --strict # stricter checks, good for CI
|
||||
openspec validate --archived # fail if archived changes have unchecked tasks
|
||||
```
|
||||
|
||||
Common causes are a missing required section (like a spec with no scenarios) or a malformed delta header. Fix the file and re-run. The [CLI reference](cli.md#openspec-validate) documents the output format.
|
||||
|
||||
One message deserves its own note:
|
||||
|
||||
```text
|
||||
MODIFIED "<requirement>" omits scenario(s) the current spec still has: "<scenario>"
|
||||
```
|
||||
|
||||
A `MODIFIED` requirement replaces the whole requirement block, so it has to carry every scenario that survives the change, not only the ones you edited. Copy the named scenarios from `openspec/specs/<capability-path>/spec.md` back into the delta, preserving any domain directories in the path. This often appears on an older change after someone else's change added a scenario to the same requirement — archive refuses that change either way, and validation now says so before you implement it.
|
||||
|
||||
### The AI created incomplete or wrong artifacts
|
||||
|
||||
The AI didn't have enough context. A few levers help:
|
||||
|
||||
- Add project context in `openspec/config.yaml` so your stack and conventions are injected into every request. See [Customization](customization.md#project-configuration).
|
||||
- Add per-artifact `rules:` for guidance that only applies to, say, specs.
|
||||
- Give a more detailed description when you propose.
|
||||
- Use the expanded `/opsx:continue` to create one artifact at a time and review each, instead of `/opsx:ff` doing them all at once.
|
||||
|
||||
### Archive won't finish, or warns about incomplete tasks
|
||||
|
||||
Archive won't *block* on incomplete tasks, but it warns you, because archiving usually means the work is done. If tasks remain on purpose (you're filing a partial change), proceed. Otherwise finish the tasks first. Archive will also offer to sync your delta specs into the main specs if you haven't synced yet; say yes unless you have a reason not to.
|
||||
|
||||
### "User force closed the prompt with 0 null"
|
||||
|
||||
Something ran `openspec archive` where nothing can answer a question — an AI agent calling it from a tool, a CI job, or any shell with stdin closed. Archive asks up to three confirmations, and an unanswerable one used to fail with that raw message.
|
||||
|
||||
Pass `--yes` to answer them up front:
|
||||
|
||||
```bash
|
||||
openspec archive <change-name> --yes
|
||||
```
|
||||
|
||||
Keep any flags you were already passing — `--skip-specs` and `--no-validate` change what archive does, so a bare `--yes` rerun is not the same command. Current versions name the flag for you and print a `Fix:` line you can paste. If you meant to pick from a list, pass the change name explicitly: the picker needs an answer too.
|
||||
|
||||
If you instead ran archive with its output redirected to a file or captured by a tool and *did* pipe an answer (`printf 'y\n' | openspec archive …`), older versions wrote terminal escape codes into that capture while drawing the prompt — in some environments enough to bloat the file badly. Current versions read the confirmation prompts as plain text whenever stdout is not a terminal, and a no-argument `openspec archive` (which would otherwise draw an interactive change picker) asks you to pass a change name up front instead of rendering a menu into the capture. Either way, redirected and agent runs stay clean; passing `--yes` (with a change name) skips the prompts entirely.
|
||||
|
||||
## Configuration
|
||||
|
||||
### My `config.yaml` isn't being applied
|
||||
|
||||
Three usual suspects:
|
||||
|
||||
1. **Wrong filename.** It must be `openspec/config.yaml`, not `.yml`.
|
||||
2. **Invalid YAML.** Run it through any YAML validator; the CLI also reports syntax errors with line numbers.
|
||||
3. **You expected a restart.** You don't need one. Config changes take effect immediately.
|
||||
|
||||
### "Unknown artifact ID in rules: X"
|
||||
|
||||
A key under `rules:` doesn't match any artifact in your schema. For the default `spec-driven` schema the valid IDs are `proposal`, `specs`, `design`, `tasks`. To see the IDs for any schema:
|
||||
|
||||
```bash
|
||||
openspec schemas --json
|
||||
```
|
||||
|
||||
### "Context too large"
|
||||
|
||||
The `context:` field is capped at 50KB, on purpose, because it's injected into every request. Summarize it, or link out to longer docs instead of pasting them. Lean context also produces better, faster results.
|
||||
|
||||
### "Schema not found"
|
||||
|
||||
The schema name you referenced doesn't exist. List what's available and check spelling:
|
||||
|
||||
```bash
|
||||
openspec schemas # list available schemas
|
||||
openspec schema which <name> # see where a schema resolves from
|
||||
openspec schema init <name> # create a custom one
|
||||
```
|
||||
|
||||
See [Customization](customization.md#custom-schemas).
|
||||
|
||||
## Migration from the legacy workflow
|
||||
|
||||
### "Legacy files detected in non-interactive mode"
|
||||
|
||||
You're in CI or a non-interactive shell, and OpenSpec found old files to clean up but can't prompt you. Approve automatically:
|
||||
|
||||
```bash
|
||||
openspec init --force
|
||||
```
|
||||
|
||||
For Codex, OpenSpec may detect old managed prompt files in `$CODEX_HOME/prompts` or `~/.codex/prompts`. That cleanup is limited to OpenSpec's allowlisted legacy Codex prompt filenames, and non-interactive `openspec init` removes only the files whose replacement `.agents/skills/openspec-*` skills exist. Non-interactive `openspec update` leaves all legacy cleanup untouched unless you pass `--force`.
|
||||
|
||||
### Commands didn't appear after migrating
|
||||
|
||||
Restart your IDE. Skills are detected at startup. If they still don't appear, run `openspec update` and check the file locations in [Supported Tools](supported-tools.md).
|
||||
|
||||
### My old `project.md` wasn't migrated
|
||||
|
||||
That's intentional. OpenSpec never deletes `project.md` automatically because it may hold context you wrote. Move the useful parts into `config.yaml`'s `context:` section, then delete it yourself. The [Migration Guide](migration-guide.md#migrating-projectmd-to-configyaml) walks through this, including a prompt you can hand to your AI to do the distilling.
|
||||
|
||||
## Still stuck?
|
||||
|
||||
- **Discord:** [discord.gg/YctCnvvshC](https://discord.gg/YctCnvvshC)
|
||||
- **GitHub Issues:** [github.com/Fission-AI/OpenSpec/issues](https://github.com/Fission-AI/OpenSpec/issues)
|
||||
- **From your terminal:** `openspec feedback "what went wrong"` opens an issue for you.
|
||||
|
||||
When you report a problem, include your OpenSpec version (`openspec --version`), your Node version (`node --version`), your AI tool, and the exact command and output. It makes help much faster.
|
||||
@@ -1,552 +0,0 @@
|
||||
# Workflows
|
||||
|
||||
This guide covers common workflow patterns for OpenSpec and when to use each one. For basic setup, see [Getting Started](getting-started.md). For command reference, see [Commands](commands.md).
|
||||
|
||||
## Philosophy: Actions, Not Phases
|
||||
|
||||
Traditional workflows force you through phases: planning, then implementation, then done. But real work doesn't fit neatly into boxes.
|
||||
|
||||
OPSX takes a different approach:
|
||||
|
||||
```text
|
||||
Traditional (phase-locked):
|
||||
|
||||
PLANNING ────────► IMPLEMENTING ────────► DONE
|
||||
│ │
|
||||
│ "Can't go back" │
|
||||
└────────────────────┘
|
||||
|
||||
OPSX (fluid actions):
|
||||
|
||||
proposal ──► specs ──► design ──► tasks ──► implement
|
||||
```
|
||||
|
||||
**Key principles:**
|
||||
|
||||
- **Actions, not phases** - Commands are things you can do, not stages you're stuck in
|
||||
- **Dependencies are enablers** - They show what's possible, not what's required next
|
||||
|
||||
> **Customization:** OPSX workflows are driven by schemas that define artifact sequences. See [Customization](customization.md) for details on creating custom schemas.
|
||||
|
||||
## Workflow at a Glance
|
||||
|
||||
The default workflow stays fluid: exploration and verification are optional, and
|
||||
you can update planning artifacts whenever implementation reveals something new.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Idea["Idea or problem"] --> Explore["/opsx:explore<br/>(optional)"]
|
||||
Idea --> Propose["/opsx:propose"]
|
||||
Explore --> Propose
|
||||
Propose --> Review{"Planning artifacts<br/>ready?"}
|
||||
Review -->|"Refine"| Update["/opsx:update"]
|
||||
Update --> Review
|
||||
Review -->|"Implement"| Apply["/opsx:apply"]
|
||||
Apply -->|"Plan changed"| Update
|
||||
Apply --> Archive["/opsx:archive"]
|
||||
Apply --> Verify["/opsx:verify<br/>(optional, custom selection)"]
|
||||
Apply --> Sync["/opsx:sync<br/>(optional before archive)"]
|
||||
Verify --> Verified{"Ready to archive?"}
|
||||
Verified -->|"Fix implementation"| Apply
|
||||
Verified -->|"Revise plan"| Update
|
||||
Verified -->|"Ready"| Sync
|
||||
Verified -->|"Ready"| Archive
|
||||
Sync --> Archive
|
||||
```
|
||||
|
||||
The AI assistant drives the workflow, while the CLI provides deterministic
|
||||
scaffolding, status, and artifact instructions:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
actor Human
|
||||
participant Assistant as AI assistant
|
||||
participant CLI as OpenSpec CLI
|
||||
participant Files as Planning and implementation files
|
||||
|
||||
Human->>Assistant: /opsx:propose "change"
|
||||
Assistant->>CLI: openspec new change
|
||||
CLI->>Files: Scaffold change metadata
|
||||
Assistant->>CLI: Request status and artifact instructions
|
||||
CLI-->>Assistant: Build order, paths, and templates
|
||||
Assistant->>Files: Write schema-defined planning artifacts
|
||||
Assistant-->>Human: Present artifacts for review
|
||||
|
||||
Human->>Assistant: /opsx:apply
|
||||
Assistant->>CLI: Request apply instructions
|
||||
CLI-->>Assistant: Context files and task state
|
||||
Assistant->>Files: Implement tasks and update checkboxes
|
||||
Assistant-->>Human: Report implementation status
|
||||
|
||||
Human->>Assistant: /opsx:archive
|
||||
Assistant->>CLI: Request archive inputs and artifact status
|
||||
CLI-->>Assistant: Planning paths and artifact completion
|
||||
Assistant->>Files: Read task state and compare delta specs
|
||||
opt Delta specs exist
|
||||
Assistant-->>Human: Offer to sync before archiving
|
||||
alt Sync accepted
|
||||
Human->>Assistant: Confirm sync
|
||||
Assistant->>Files: Merge delta specs into main specs
|
||||
else Sync skipped
|
||||
Human->>Assistant: Archive without syncing
|
||||
end
|
||||
end
|
||||
Assistant->>Files: Move the change into the archive
|
||||
Assistant-->>Human: Report archive location and sync result
|
||||
|
||||
Note over Human,CLI: CLI alternative: openspec archive change-name --yes skips confirmation prompts. It still validates, then applies any delta specs and archives
|
||||
```
|
||||
|
||||
## Two Modes
|
||||
|
||||
### Default Quick Path (`core` profile)
|
||||
|
||||
New installs default to `core`, which provides:
|
||||
- `/opsx:explore`
|
||||
- `/opsx:propose`
|
||||
- `/opsx:apply`
|
||||
- `/opsx:update`
|
||||
- `/opsx:sync`
|
||||
- `/opsx:archive`
|
||||
|
||||
Typical flow:
|
||||
|
||||
```text
|
||||
/opsx:explore ──► /opsx:propose ──► /opsx:apply ──► /opsx:sync ──► /opsx:archive
|
||||
(optional)
|
||||
```
|
||||
|
||||
#### Start by exploring (the habit worth forming)
|
||||
|
||||
`/opsx:explore` is part of the default profile, not an advanced add-on. It's the move to make whenever you have a problem but not yet a plan, which, with an AI assistant, is most of the time.
|
||||
|
||||
```text
|
||||
You: /opsx:explore
|
||||
|
||||
AI: What would you like to explore?
|
||||
|
||||
You: Our search results feel stale. I'm not sure if it's caching,
|
||||
indexing, or the query itself.
|
||||
|
||||
AI: Let me look... [reads the search service and cache layer]
|
||||
It's the index: it only rebuilds nightly, so edits don't show
|
||||
up until the next day. Two options: rebuild on write (simple,
|
||||
more load) or a short-TTL cache invalidation (more moving parts,
|
||||
less load). Given your write volume is low, rebuild-on-write is
|
||||
the cleaner fix. Want to scope it?
|
||||
|
||||
You: Yes.
|
||||
|
||||
You: /opsx:propose rebuild-search-index-on-write
|
||||
```
|
||||
|
||||
Explore never writes code, and writes nothing else unless you ask, or say yes when it offers. It's a free, no-stakes conversation that turns a vague worry into a precise change, so the proposal that follows is sharp. Already know exactly what you want? Skip it and go straight to `/opsx:propose`. Full guide: [Explore First](explore.md).
|
||||
|
||||
### Expanded/Full Workflow (custom selection)
|
||||
|
||||
If you want explicit scaffold-and-build commands (`/opsx:new`, `/opsx:continue`, `/opsx:ff`, `/opsx:verify`, `/opsx:bulk-archive`, `/opsx:onboard`), enable them with:
|
||||
|
||||
```bash
|
||||
openspec config profile
|
||||
openspec update
|
||||
```
|
||||
|
||||
## Workflow Patterns (Expanded Mode)
|
||||
|
||||
### Quick Feature
|
||||
|
||||
When you know what you want to build and just need to execute:
|
||||
|
||||
```text
|
||||
/opsx:new ──► /opsx:ff ──► /opsx:apply ──► /opsx:verify ──► /opsx:archive
|
||||
```
|
||||
|
||||
**Example conversation:**
|
||||
|
||||
```text
|
||||
You: /opsx:new add-logout-button
|
||||
|
||||
AI: Created openspec/changes/add-logout-button/
|
||||
Ready to create: proposal
|
||||
|
||||
You: /opsx:ff
|
||||
|
||||
AI: Creating all planning artifacts...
|
||||
✓ proposal.md
|
||||
✓ specs/
|
||||
✓ design.md
|
||||
✓ tasks.md
|
||||
Ready for implementation!
|
||||
|
||||
You: /opsx:apply
|
||||
|
||||
AI: Working through tasks...
|
||||
✓ Added logout button to header
|
||||
✓ Implemented session clearing
|
||||
✓ Added confirmation dialog
|
||||
All tasks complete!
|
||||
|
||||
You: /opsx:archive
|
||||
|
||||
AI: ✓ Merged specs
|
||||
✓ Archived change
|
||||
```
|
||||
|
||||
**Best for:** Small to medium features, bug fixes, straightforward changes.
|
||||
|
||||
### Exploratory
|
||||
|
||||
When requirements are unclear or you need to investigate first:
|
||||
|
||||
```text
|
||||
/opsx:explore ──► /opsx:new ──► /opsx:continue ──► ... ──► /opsx:apply
|
||||
```
|
||||
|
||||
**Example conversation:**
|
||||
|
||||
```text
|
||||
You: /opsx:explore
|
||||
|
||||
AI: What would you like to explore?
|
||||
|
||||
You: I want to improve page load performance but I'm not sure
|
||||
where the bottlenecks are.
|
||||
|
||||
AI: Let me help investigate...
|
||||
[Analyzes bundle sizes, identifies slow queries, reviews
|
||||
component render patterns]
|
||||
|
||||
I found three main bottlenecks:
|
||||
1. Large unoptimized images
|
||||
2. Synchronous data fetching in ProductList
|
||||
3. Re-renders from context changes
|
||||
|
||||
Which would you like to address first?
|
||||
|
||||
You: Let's tackle the data fetching issue.
|
||||
|
||||
You: /opsx:new optimize-product-list-fetching
|
||||
|
||||
AI: Created change. Ready to create: proposal
|
||||
|
||||
You: /opsx:continue
|
||||
|
||||
AI: Creating proposal based on our exploration...
|
||||
[Writes proposal incorporating investigation insights]
|
||||
|
||||
Ready to create: specs, design
|
||||
Which would you like next?
|
||||
|
||||
You: /opsx:continue
|
||||
|
||||
AI: Creating specs...
|
||||
```
|
||||
|
||||
**Best for:** Performance optimization, debugging, architectural decisions, unclear requirements.
|
||||
|
||||
### Parallel Changes
|
||||
|
||||
Work on multiple changes at once:
|
||||
|
||||
```text
|
||||
Change A: /opsx:new ──► /opsx:ff ──► /opsx:apply (in progress)
|
||||
│
|
||||
context switch
|
||||
│
|
||||
Change B: /opsx:new ──► /opsx:ff ──────► /opsx:apply
|
||||
```
|
||||
|
||||
**Example conversation:**
|
||||
|
||||
```text
|
||||
You: I'm working on add-dark-mode but got pulled into a bug fix
|
||||
|
||||
You: /opsx:new fix-login-redirect
|
||||
|
||||
AI: Created openspec/changes/fix-login-redirect/
|
||||
|
||||
You: /opsx:ff
|
||||
|
||||
AI: ✓ Created planning artifacts
|
||||
|
||||
You: /opsx:apply
|
||||
|
||||
AI: Working on fix-login-redirect...
|
||||
[Implements the fix]
|
||||
All tasks complete!
|
||||
|
||||
You: /opsx:archive
|
||||
|
||||
AI: ✓ Archived fix-login-redirect
|
||||
|
||||
You: Let's get back to dark mode
|
||||
|
||||
You: /opsx:apply add-dark-mode
|
||||
|
||||
AI: Resuming add-dark-mode...
|
||||
Picking up at task 2.3: Update Header...
|
||||
```
|
||||
|
||||
**Best for:** Parallel work streams, urgent interrupts, team collaboration.
|
||||
|
||||
When you have multiple completed changes, use `/opsx:bulk-archive`:
|
||||
|
||||
```text
|
||||
You: /opsx:bulk-archive
|
||||
|
||||
AI: Found 3 completed changes:
|
||||
- add-dark-mode (all tasks done)
|
||||
- fix-login-redirect (all tasks done)
|
||||
- update-footer (all tasks done)
|
||||
|
||||
Checking for spec conflicts...
|
||||
⚠ add-dark-mode and update-footer both touch specs/ui/
|
||||
|
||||
Inspecting codebase to resolve...
|
||||
Both changes are implemented. Will apply in chronological order.
|
||||
|
||||
Archive all 3 changes?
|
||||
|
||||
You: Yes
|
||||
|
||||
AI: ✓ Archived add-dark-mode
|
||||
✓ Archived fix-login-redirect
|
||||
✓ Archived update-footer
|
||||
Specs merged in order: add-dark-mode → update-footer
|
||||
```
|
||||
|
||||
Bulk archive detects when multiple changes touch the same specs and resolves conflicts by checking what's actually implemented.
|
||||
|
||||
### Completing a Change
|
||||
|
||||
The recommended completion flow:
|
||||
|
||||
```text
|
||||
/opsx:apply ──► /opsx:verify ──► /opsx:archive
|
||||
│ │
|
||||
validates prompts to sync
|
||||
implementation if needed
|
||||
```
|
||||
|
||||
#### Verify: Check Your Work
|
||||
|
||||
`/opsx:verify` validates implementation against your artifacts across three dimensions:
|
||||
|
||||
```text
|
||||
You: /opsx:verify
|
||||
|
||||
AI: Verifying add-auth...
|
||||
|
||||
COMPLETENESS
|
||||
✓ All 12 tasks in tasks.md are checked
|
||||
✓ All requirements in specs have corresponding code
|
||||
⚠ Scenario "Session timeout after inactivity" not tested
|
||||
|
||||
CORRECTNESS
|
||||
✓ Implementation matches spec intent
|
||||
✓ Edge cases from scenarios are handled
|
||||
✓ Error states match spec definitions
|
||||
|
||||
COHERENCE
|
||||
✓ Design decisions reflected in code structure
|
||||
✓ Naming conventions consistent with design.md
|
||||
⚠ Design mentions "event-driven" but implementation uses polling
|
||||
|
||||
SUMMARY
|
||||
─────────────────────────────
|
||||
Critical issues: 0
|
||||
Warnings: 2
|
||||
Ready to archive: Yes (with warnings)
|
||||
|
||||
Recommendations:
|
||||
1. Add test for session timeout scenario
|
||||
2. Consider refactoring to event-driven as designed, or update design.md
|
||||
```
|
||||
|
||||
**What verify checks:**
|
||||
|
||||
| Dimension | What it validates |
|
||||
|-----------|------------------|
|
||||
| Completeness | All tasks done, all requirements implemented, scenarios covered |
|
||||
| Correctness | Implementation matches spec intent, edge cases handled |
|
||||
| Coherence | Design decisions reflected in code, patterns consistent |
|
||||
|
||||
Verify won't block archive, but it surfaces issues you might want to address first.
|
||||
|
||||
#### Archive: Finalize the Change
|
||||
|
||||
`/opsx:archive` completes the change and moves it to the archive:
|
||||
|
||||
```text
|
||||
You: /opsx:archive
|
||||
|
||||
AI: Archiving add-auth...
|
||||
|
||||
Artifact status:
|
||||
✓ proposal.md exists
|
||||
✓ specs/ exists
|
||||
✓ design.md exists
|
||||
✓ tasks.md exists (12/12 tasks complete)
|
||||
|
||||
Delta specs: Not yet synced to main
|
||||
→ Would you like to sync now?
|
||||
|
||||
You: Yes
|
||||
|
||||
AI: ✓ Synced specs to openspec/specs/auth/spec.md
|
||||
✓ Moved to openspec/changes/archive/2025-01-24-add-auth/
|
||||
|
||||
Change archived successfully.
|
||||
```
|
||||
|
||||
Archive will prompt if specs aren't synced. It won't block on incomplete tasks, but it will warn you.
|
||||
|
||||
## When to Use What
|
||||
|
||||
### `/opsx:ff` vs `/opsx:continue`
|
||||
|
||||
| Situation | Use |
|
||||
|-----------|-----|
|
||||
| Clear requirements, ready to build | `/opsx:ff` |
|
||||
| Exploring, want to review each step | `/opsx:continue` |
|
||||
| Want to iterate on proposal before specs | `/opsx:continue` |
|
||||
| Time pressure, need to move fast | `/opsx:ff` |
|
||||
| Complex change, want control | `/opsx:continue` |
|
||||
|
||||
**Rule of thumb:** If you can describe the full scope upfront, use `/opsx:ff`. If you're figuring it out as you go, use `/opsx:continue`.
|
||||
|
||||
### When to Update vs Start Fresh
|
||||
|
||||
A common question: when is updating an existing change okay, and when should you start a new one?
|
||||
|
||||
**Update the existing change when:**
|
||||
|
||||
- Same intent, refined execution
|
||||
- Scope narrows (MVP first, rest later)
|
||||
- Learning-driven corrections (codebase isn't what you expected)
|
||||
- Design tweaks based on implementation discoveries
|
||||
|
||||
**Start a new change when:**
|
||||
|
||||
- Intent fundamentally changed
|
||||
- Scope exploded to different work entirely
|
||||
- Original change can be marked "done" standalone
|
||||
- Patches would confuse more than clarify
|
||||
|
||||
```text
|
||||
┌─────────────────────────────────────┐
|
||||
│ Is this the same work? │
|
||||
└──────────────┬──────────────────────┘
|
||||
│
|
||||
┌──────────────────┼──────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
Same intent? >50% overlap? Can original
|
||||
Same problem? Same scope? be "done" without
|
||||
│ │ these changes?
|
||||
│ │ │
|
||||
┌────────┴────────┐ ┌──────┴──────┐ ┌───────┴───────┐
|
||||
│ │ │ │ │ │
|
||||
YES NO YES NO NO YES
|
||||
│ │ │ │ │ │
|
||||
▼ ▼ ▼ ▼ ▼ ▼
|
||||
UPDATE NEW UPDATE NEW UPDATE NEW
|
||||
```
|
||||
|
||||
**Example: "Add dark mode"**
|
||||
|
||||
- "Need to also support custom themes" → New change (scope exploded)
|
||||
- "System preference detection is harder than expected" → Update (same intent)
|
||||
- "Let's ship toggle first, add preferences later" → Update then archive, then new change
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Keep Changes Focused
|
||||
|
||||
One logical unit of work per change. If you're doing "add feature X and also refactor Y", consider two separate changes.
|
||||
|
||||
**Why it matters:**
|
||||
- Easier to review and understand
|
||||
- Cleaner archive history
|
||||
- Can ship independently
|
||||
- Simpler rollback if needed
|
||||
|
||||
### Use `/opsx:explore` for Unclear Requirements
|
||||
|
||||
Before committing to a change, explore the problem space:
|
||||
|
||||
```text
|
||||
You: /opsx:explore
|
||||
|
||||
AI: What would you like to explore?
|
||||
|
||||
You: How should we handle rate limiting for our API?
|
||||
|
||||
AI: Let me investigate your current setup and options...
|
||||
[Researches codebase, considers patterns]
|
||||
|
||||
I see three approaches we could take:
|
||||
1. Middleware-based (simple, per-endpoint)
|
||||
2. Redis-backed (scalable, shared state)
|
||||
3. Token bucket per user (fair, complex)
|
||||
|
||||
Your current stack suggests #1 or #2. What's your scale?
|
||||
```
|
||||
|
||||
Exploration clarifies thinking before any code gets written.
|
||||
|
||||
### Verify Before Archiving
|
||||
|
||||
Use `/opsx:verify` to check implementation matches artifacts:
|
||||
|
||||
```text
|
||||
You: /opsx:verify
|
||||
|
||||
AI: Verifying add-dark-mode...
|
||||
|
||||
✓ All tasks in tasks.md are checked
|
||||
✓ Requirements in specs have corresponding code
|
||||
✓ Design decisions are reflected in implementation
|
||||
|
||||
Ready to archive!
|
||||
```
|
||||
|
||||
Catches mismatches before you close out the change.
|
||||
|
||||
### Name Changes Clearly
|
||||
|
||||
Good names make `openspec list` useful:
|
||||
|
||||
```text
|
||||
Good: Avoid:
|
||||
add-dark-mode feature-1
|
||||
fix-login-redirect update
|
||||
optimize-product-query changes
|
||||
implement-2fa wip
|
||||
```
|
||||
|
||||
## Command Quick Reference
|
||||
|
||||
For full command details and options, see [Commands](commands.md).
|
||||
|
||||
| Command | Purpose | When to Use |
|
||||
|---------|---------|-------------|
|
||||
| `/opsx:propose` | Create change + planning artifacts | Fast default path (`core` profile) |
|
||||
| `/opsx:explore` | Think through ideas with the AI | Start here when unsure: unclear requirements, investigation, comparing options |
|
||||
| `/opsx:new` | Start a change scaffold | Expanded mode, explicit artifact control |
|
||||
| `/opsx:continue` | Create next artifact | Expanded mode, step-by-step artifact creation |
|
||||
| `/opsx:ff` | Create all planning artifacts | Expanded mode, clear scope |
|
||||
| `/opsx:apply` | Implement tasks | Ready to write code |
|
||||
| `/opsx:verify` | Validate implementation | Expanded mode, before archiving |
|
||||
| `/opsx:sync` | Merge delta specs | Expanded mode, optional |
|
||||
| `/opsx:archive` | Complete the change | All work finished |
|
||||
| `/opsx:bulk-archive` | Archive multiple changes | Expanded mode, parallel work |
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Writing Good Specs](writing-specs.md) - What a strong requirement and scenario look like, and how to right-size a change
|
||||
- [Reviewing a Change](reviewing-changes.md) - The two-minute pass on a drafted plan before any code
|
||||
- [OpenSpec on a Team](team-workflow.md) - How changes fit branches and pull requests
|
||||
- [Commands](commands.md) - Full command reference with options
|
||||
- [Concepts](concepts.md) - Deep dive into specs, artifacts, and schemas
|
||||
- [Customization](customization.md) - Create custom workflows
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user