Commit Graph

843 Commits

Author SHA1 Message Date
openspec-release-bot[bot] 9d4e5974e5 Version Packages (#1822)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@fission-ai/openspec@1.13.0 v1.13.0
2026-09-09 20:59:22 +00:00
Clay Good e4e112d94f chore(deps): declare pnpm overrides only in pnpm-workspace.yaml (#1816)
The security overrides were declared twice: in pnpm-workspace.yaml, with
the advisory comments explaining each pin, and again under
package.json's pnpm.overrides. The copies are not additive — pnpm 10
uses package.json's block instead of the workspace list when both are
present — and Dependabot rewrites plain-name entries in package.json
whenever it bumps the same package. So a routine bump silently
displaces the pins that patch advisories, and fails the equality test
that guards them (#1812).

Keeps one declaration, in the file that carries the reasoning, and
asserts the mirror stays gone.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 17:47:22 +00:00
Dwin Gharibi aedf4d0c64 fix(archive): preserve blank lines inside code fences (#1798)
* fix(archive): preserve blank lines inside code fences

* docs(test): document fence-preservation test helpers

* chore(changeset): track the fenced blank-line fix

The fix changes archive output for any spec documenting a fenced sample with
consecutive blank lines, so it belongs in the changelog. Release tracking only
validates changesets that exist; it never requires one, which is why CI stayed
green without it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Clay Good <hi@claygood.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 17:03:39 +00:00
Dwin Gharibi d9e1a28c38 fix(update): refresh generated files that drifted (#1808)
* fix(update): refresh generated files that drifted

* test(update): isolate command drift from missing files and host config

* chore(changeset): track the command-drift fix

`openspec update` now reports and repairs tools it previously called up to
date, so users will see a behavior change. That belongs in the changelog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Clay Good <hi@claygood.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 16:32:45 +00:00
Dwin Gharibi 8251763ecd fix(parser): apply every delta section header (#1802)
* fix(parser): apply every delta section header

* test(parser): assert section presence for a header after another section

* chore(changeset): track the repeated-section fix

Deltas that previously applied only part of what was authored now apply all of
it, which changes archive output for affected changes. That belongs in the
changelog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Clay Good <hi@claygood.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 16:32:39 +00:00
Dwin Gharibi fadac3e1c9 fix(parser): accept all CommonMark list markers in deltas (#1800)
* fix(parser): accept all CommonMark list markers in deltas

* docs(parser): document the REMOVED and RENAMED readers

* chore(changeset): track the list-marker fix

A removal or rename written with `*` or `+` now takes effect where it
previously did nothing, so existing specs can change on the next archive. That
is a user-visible behavior change and belongs in the changelog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Clay Good <hi@claygood.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 16:32:35 +00:00
Clay Good 3915db763a fix(guidance): teach the spec-inventory verb to generated guidance (#1700)
* fix(guidance): teach the spec-inventory verb to generated guidance

`openspec list --specs` appeared in no generated skill, command, or
artifact instruction, while `openspec list --json` — the in-flight
CHANGE list — appeared throughout. An agent asked to read the existing
specs first reached for the one enumeration verb it had been taught,
got the change list, found it plausible, and reported the step complete
against the wrong object.

Explore now lists the spec inventory alongside the change list and says
which is which. The spec-driven `proposal` and `specs` instructions name
the command at the two points that need it: researching existing
capabilities before filling in the Capabilities section, and confirming
a delta's path matches an existing capability.

Guidance text only — no CLI, parser, or archive behavior changes.

Closes #1689

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(guidance): carry the store qualifier wherever the command is named

A bare `openspec list --specs` reads the local inventory, so under a
selected store it confirms a capability path against the wrong root. The
proposal instruction carried the qualifier; the modified-capability
instruction did not. All four sites now use the same wording, and the
guard is scoped to the passage that names the command — every explore
body already carries the qualifier in its unrelated capture steps, so a
whole-body assertion would pass with it dropped here.

Addresses CodeRabbit review on #1700.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(guidance): read a listed capability with the store-aware command

The read step I added defeated the fix under a store. It told the agent to
list the inventory with `--store "<id>"`, then read the result back from
`openspec/specs/<capability-path>/spec.md` — a local path. Verified against
a registered store: `list --specs --store mystore` returns
`store-only-capability`, and the corresponding local read fails outright
(or, when a local capability happens to share the name, silently returns a
different one). That is the same wrong-object failure #1689 is about,
reintroduced one line later.

Capabilities are now read with
`openspec show "<spec-id>" --type spec --json --no-scenarios`, which
resolves against the same root the listing came from and returns purpose
plus requirement texts without pulling whole spec files into context.
`--type spec` is load-bearing: a change and a spec sharing a name is an
ambiguous_item error, and change names routinely mirror capability names.

Also documents `--store` on `list` and `show` in docs/cli.md. Both already
accepted the flag — the prose at line 228 says so — but neither options
table listed it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix: Use ASCII arrows instead of unicode

This fixes the issue of ambiguous unicode character width when visualizing on terminals

* fix: Update remaining docs within explore to use ASCII

* fix(explore): finish the ASCII conversion and guard it

Rebase onto main and close the gaps in the original fix:

- Regenerate skills/openspec-explore/SKILL.md. The static skills/ mirror
  landed after this branch was cut, so the parity test would have failed
  with the template and the mirror out of sync.
- Regenerate the three parity hashes through scripts/regen-parity-hashes.mjs.
- Convert the ambiguous-width glyphs the first pass missed: the bullets in
  the CLI-storage example, and the check/cross marks in its comparison
  table, which sat in the column-aligned block the bug is about.
- Tighten the ASCII guidance to two lines. It ships into every user
  project on both delivery surfaces, so the paragraph was pure overhead.
- Add regression tests (#983): every fenced example in both the skill and
  the command body must be free of box-drawing, arrow, bullet, and
  check/cross glyphs, and the guidance must state the rule and the reason.
- Add a patch changeset.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(explore): cover every check/cross dingbat in the ASCII guard

The matcher listed U+2713 and U+2717 only, so a fenced example could use
✕ (U+2715) or ✘ (U+2718) — same ambiguous width, same misalignment — and
still pass. Widen to the U+2713-U+2718 run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(explore): require explicit confirmation before writing files

* test(explore): harden write confirmation guardrail

* fix(explore): scope write confirmation precisely

* test(guidance): pin store-aware spec reads

* test(templates): regenerate explore parity hashes

The explore template now carries three independent guidance edits: the
spec-inventory verb, the ASCII diagram conversion, and the write
confirmation contract. Each pinned its own hash constants, so the pinned
values no longer describe the combined template.

Regenerate them from the merged source with `regen:parity-hashes` rather
than hand-editing, and confirm the committed skills mirror still matches
byte-for-byte.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(guidance): read complete specs before coverage decisions

* docs: drop the redundant legacy docs/cli.md edit

docs-lab/README.md makes docs-lab/ canonical and the old docs/ tree legacy.
docs-lab/reference/cli.md already documents `--store <id>` for both
`openspec list` and `openspec show`, so this branch's docs/cli.md rows added
a third copy in the stale tree and nothing else.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore(changeset): drop the docs claim this PR no longer makes

alfred-openspec on #1700: the release note still said docs/cli.md now documents
--store on list and show, but that legacy-tree edit was removed from this head
and the diff does not touch docs/cli.md. The canonical docs-lab/reference/cli.md
already documented the flag on both commands, which is why the edit went.

Removing the sentence rather than repointing it at docs-lab: nothing in
docs-lab changed either, so there is no documentation change to announce.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Shooks <justanormalme@gmail.com>
Co-authored-by: Ayman D. <ayman.bacc@gmail.com>
2026-09-09 16:25:02 +00:00
Clay Good c170dc77ad fix(archive): read a wrapped scenario bullet as one bullet (#1782)
* fix(archive): read a wrapped scenario bullet as one bullet

A repository that wraps its prose at a column limit writes most scenario
bullets over two lines. The retirement guard read the continuation line
as content the merge could not account for, so `retire_capabilities`
refused every such spec - and because the hint that names the marker is
gated on that same count, an unmarked author got the bare "must have at
least one requirement" abort and never learned the retirement path
exists.

A line indented to the content column of the item above it, with no
blank line between, is part of that item. It is accounted for when the
item was and already reported when it was not, so nothing is deleted
unmentioned either way. A blank line still ends the item, so a note
written below the scenarios is still the author's own however it is
indented.

Closes #1780

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(archive): keep an indented heading out of a bullet's continuation

Continuation is for wrapped prose. A raw HTML heading indented under a
scenario bullet was absorbed by it, so indenting a section one level
would have smuggled it past the audit and deleted it with the file. ATX
headings were already excluded; HTML ones now are too, matching how the
pass above the requirements section reads them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(archive): flag a setext heading indented under a bullet

A setext underline turns the line above it into a heading, so indenting
the pair one level under a scenario bullet let a whole section be
absorbed as continuation and deleted with the file. Checked ahead of the
continuation branch now, the same way the ATX and raw HTML forms already
are.

Found by CodeRabbit on this PR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(archive): read an unindented wrapped bullet as one bullet too

Not every wrap indents its continuation, and the indent-only rule left
the reported bug fixed for one spelling and live for the other: a
hand-wrapped scenario bullet still refused the retirement.

Inside a scenario's unbroken bullet run a lazy continuation is now read
as part of the bullet above it. This widens nothing - a sibling bullet
written in that same position is already read as the scenario's own, and
a lazy line is part of the bullet where a sibling is merely next to it.
Past the blank line that ends the run the indent is still required, so a
note bulleted below the scenarios and the line that wraps it stay the
author's.

Also covers CRLF specs, and asserts the refusal report names only the
real leftover in a wrapped multi-requirement spec rather than burying it
under continuations.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(archive): stop a lazy continuation at anything that opens a block

CommonMark lets a blockquote, thematic break, table, list item or raw
HTML interrupt a paragraph, so one written flush against a scenario
bullet starts something new rather than continuing it. The lazy
allowance absorbed all of them, which would have deleted an author's
note with the file and named nothing.

The bullet's paragraph is now tracked as its own state: opened by a
bullet, closed by a blank line, a fence, a heading, or a line that opens
a block - including one indented inside the item, whose own paragraph
ends the bullet's. Lazy continuation applies only while it is open.
Indented continuation is unaffected: a nested list or quote sitting
inside the item is still the item's own content.

Each of the six holes is pinned by a test proven to fail with the
narrower rule removed.

Found by CodeRabbit on this PR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(archive): classify a line as the list item sees it

A marker as wide as `100. ` puts the item's content past the three
columns a Markdown construct is allowed at the file's left margin, so
`## Retention` written inside such an item read as five spaces of
nothing and was absorbed as continuation - a regression against the
behavior before continuation existed, which named it.

Every syntax test in the audit now reads the line with the item's
indent removed, so a heading, a setext underline or a block start is
recognized wherever the item sits.

Found by CodeRabbit on this PR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore: drop test scratch directory committed by mistake

`test-spec-command-tmp/` is a fixture a test run leaves behind, swept up
by `git add -A` in the previous commit. It is not part of the change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(archive): share one list-marker definition with the paragraph rule

Folds in the marker coverage from the duplicate PR #1789, which fixes the same
issue (#1780) with a shallower model.

The audit named `-`, `*` and ordered items as list markers, while
INTERRUPTS_PARAGRAPH, added in this same PR, already named `+` and capped an
ordered marker at CommonMark's nine digits. The two disagreed, so a line one
called a bullet and the other did not was read as both at once.

Both now use one LIST_ITEM constant:

- `+` is the behavior fix. A spec bulleted with `+` validates like any other,
  and every one of its scenario bullets was reported as unaccounted content, so
  that capability could not be retired at all. Regression added, verified to
  fail against the old marker set.
- The nine-digit cap changes no verdict in this design, since a line the
  pattern rejects is weighed by the same rules either way. It is here for the
  consistency, and the comment says so rather than claiming a fix. The case is
  pinned so a later change cannot start deleting such a note.

LIST_ITEM also no longer requires content after the marker, so an empty `- `
reads as the bullet it is instead of falling through to the leftovers, which is
what the surrounding indent tracking already assumed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 16:24:59 +00:00
Clay Good 8ba4ac1b16 fix(apply): warn when a change is ready to implement with no specs (#1783)
* fix(apply): warn when a change is ready to implement with no specs

Apply gates on the schema's `apply.requires` (tasks) alone, so a change
whose tasks file was written ahead of its specs read as ready even though
it had no delta specs at all — the state `openspec validate` rejects.
Apply was the one surface that green-lit a change every other surface
flags, which is how agents end up implementing before the specs exist.

Report it as a warning, in the text output and in `--json`, naming both
ways out: write the specs, or declare `skip_specs: true`. Blocking would
be a policy change; naming the gap is not. Changes that have specs,
declare `skip_specs`, or are still blocked on their own required
artifacts are unaffected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor(apply): name the metadata file from its shared constant

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(apply): cover custom schemas in the no-specs warning

A schema with no spec-producing artifact must stay quiet, and one whose
spec artifact is not called `specs` must still warn - the rule keys off
the output path, not the artifact id.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(apply): stop asserting an absolute temp path on Windows

os.tmpdir() hands back the short form (C:\Users\RUNNER~1) while the CLI
resolves the long one, so the assertion pinned a path that never matched
on windows-pwsh. Assert the change-relative tail instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(apply): name the whole chain a blocked change still needs

Apply blocks on the schema's `apply.requires` alone, so its message
stopped at the first hop: a change holding only a proposal was told
"Missing artifacts: tasks" while the specs `tasks` depends on were
missing too. Taken literally that is an instruction to write the
tracking file straight from the proposal and skip everything between —
the failure reported in #834 and #869.

Walk `requires` and report the whole set, in build order, as
`missingPrerequisites` (text and `--json`). What apply blocks on is
unchanged, and the wording leaves conditional artifacts to the schema
rather than demanding them.

The remedies these messages give are now CLI commands rather than the
`openspec-continue-change` skill: `continue` is not in CORE_WORKFLOWS,
so on the default profile the old advice named a skill that is never
installed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(apply): name the schema's own spec artifact in the warning

alfred-openspec on #1783: collectApplyWarnings() discovers spec-producing
artifacts by output path, so it correctly fires for a schema whose artifact id
is `contracts`, but the remediation text then hardcoded
`openspec instructions specs`. That names an artifact such a schema does not
declare, so the advertised custom-schema support dead-ended at the exact step
meant to resolve the warning.

The command now derives its target from specArtifacts: the artifact's own id
when the schema declares one spec-producing artifact, and `<artifact-id>` as a
placeholder when it declares several, since there is no single right answer
there and a guess would read as an instruction.

The renamed-artifact test now asserts the command names `contracts` and
rejects the hardcoded `specs` spelling, and a new test pins the two-artifact
placeholder. Verified both fail against the hardcoded string.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore(changeset): bump apply warnings to minor

This adds `missingPrerequisites` and `warnings` to the documented
`instructions apply --json` contract in docs/agent-contract.md. New fields are
backward compatible, but they are new capability an agent can consume, which is
a minor under semver rather than a patch.

Taking the conservative direction deliberately: shipping new API surface as a
patch is the violation, since a consumer pinned to a patch range would receive
it without opting in. A minor costs nothing if the fields turn out to be
uninteresting.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 16:24:55 +00:00
Clay Good 3c6d318b83 fix(init): name the workflows the profile left out (#1779)
* fix(init): name the workflows the profile left out

Setup output listed the workflows it installed but never mentioned the
ones it did not, so a user on the default core profile who typed
/opsx:ff saw nothing and read it as a broken install. The docs explain
profiles; nobody reads them before typing a command that should be
there.

init now closes with the missing workflows by name and the two commands
that add them. The note is skipped when nothing was generated at all,
where the existing delivery correction is the whole story, and when the
profile already installs everything.

Also adds a troubleshooting entry for the "only some /opsx: commands
show up" symptom, which the existing list did not cover.

Relates to #1076 (the optional-workflow discoverability half; the Windows command-discovery repro in that thread is not addressed here)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore: drop a test scratch directory committed by mistake

test-show-command-tmp/ is created by a test run and does not exist on
main; it was picked up by a `git add -A`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(init): keep the workflow note off runs that generate nothing

With no tools selected (or only tools that could not receive a surface),
`openspec config profile` followed by `openspec update` writes nothing,
so naming the missing workflows pointed at the wrong problem.

Reported by CodeRabbit on this PR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor(init): drop the redundant update step from the workflow note

`openspec config profile` offers to apply to the current project before
it exits, and prints the `openspec update` guidance itself when the user
declines, so naming a second command was one step too many.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(troubleshooting): match the profile steps to what the CLI does

`openspec config profile` applies to the current project itself, so
listing `openspec update` as a second required step was wrong; it is the
fallback for declining the prompt or for other projects.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(update): name the workflows the profile left out

`openspec update` is what the troubleshooting checklist tells a user to
run when a command they read about never appeared, and it is what people
run after upgrading the CLI. Neither of its existing profile notes fires
on the default `core` profile, so that user reached "All tools up to
date" and still learned nothing about the six workflows they don't have.

The note is the fallback pointer: silent when the extra-workflow or
missing-core note already named `openspec config profile`, and when no
configured tool can receive a workflow surface under the active delivery.

Reading the two existing notes as one short-circuited `||` would have
swallowed whichever ran second; they are evaluated separately.

Relates to #1076 (the optional-workflow discoverability half; the Windows command-discovery repro in that thread is not addressed here)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor(update): gather the profile notes behind one call

The two call sites had grown identical six-line blocks. One
displayProfileNotes() keeps the ordering and the single-pointer rule in
one place, where the "evaluate every note, never chain them with ||"
constraint can be stated once.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: drop the legacy troubleshooting entry

alfred-openspec on #1779: docs-lab/README.md says the old docs/ tree is legacy,
is no longer used by the site, and must stay untouched. The canonical
docs-lab/customize/profiles.md already lists the six optional workflows and the
'openspec config profile' command that adds them, and the root README already
calls out the expanded set, so this entry was a third copy in a stale tree.

The docs-lab troubleshooting page is a heading-only skeleton held back from the
site, so there is nothing to move it to; this PR is now source and tests only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 16:24:52 +00:00
Clay Good 6d2dbe62d3 fix(propose): load project context before planning (#1657)
* fix(propose): load project context before planning

* test(propose): assert project context is applied

* fix(propose): honor project context limits

* fix(propose): fail closed on unsafe context

* fix(propose): skip config without a root

* chore(parity): regenerate hashes after merging main

* fix(propose): harden early context loading guidance

* fix(propose): require initialization before planning in bare repos

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 16:24:48 +00:00
Clay Good 1c0ee701e5 docs: add CONTRIBUTING.md (#1781)
* docs: add CONTRIBUTING.md

Require a discussion (core design changes) or an issue before a PR is
opened, and require every PR to link its issue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: add setup and PR steps to CONTRIBUTING.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: make CONTRIBUTING.md the single source for the process

The README's Contributing section said small fixes could go straight to
a PR, which contradicts the new discussion/issue requirement. Point it at
CONTRIBUTING.md and carry over the conventional-commit and AI-disclosure
policies so nothing is lost.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: close the three process gaps in CONTRIBUTING.md

alfred-openspec on #1781:

1. The OpenSpec-proposal rule was dropped from the README with nothing
   replacing it, recreating the gap in #1727. New step 2 carries the threshold
   over verbatim from the README (new features, significant refactors,
   architectural changes) plus the philosophy paragraph, says to open the
   proposal as its own PR and wait for approval, and tells anyone unsure to ask
   in the issue from step 1.

2. The discussion path contradicted itself: step 1 accepted a prior discussion
   while step 3 required 'Closes #123'. The PR step now says to link what you
   opened in step 1, 'Closes #123' for an issue or a link to the discussion
   when there is no issue. CodeRabbit's thread on README.md:227 is the same
   defect, so the README sentence says 'the issue or discussion' too.

3. The local setup was missing 'pnpm exec tsc --noEmit', which CI runs, and the
   README called the guide a development setup after 'pnpm run dev' and
   'dev:cli' were removed. The command is added, the guide states that those
   four commands are exactly what CI runs, and the README pointer now describes
   the guide as the full process rather than a setup.

Verified each documented command against this checkout: build, tsc --noEmit and
lint all pass as written.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 16:24:45 +00:00
Clay Good 0b60a0ac1f chore(deps): bump the website-dependencies group in /website with 5 updates (#1815)
Applies dependabot's website bumps (#1812) and syncs the postcss
override in website/pnpm-workspace.yaml, which dependabot does not know
about, keeping the three override declarations in agreement.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 16:24:41 +00:00
Clay Good 6981c84df0 chore(deps): bump zod to 4.5.4 and eslint to 10.9.1 (#1814)
Consolidates the two open root-lockfile dependabot bumps (#1810, #1811)
into one PR so the pinned flake.nix pnpmDeps hash only has to be
regenerated once.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 16:24:37 +00:00
Clay Good 63666c8bb2 ci: report the correct pnpmDeps hash when flake.nix is stale (#1817)
* ci: report the correct pnpmDeps hash when flake.nix is stale

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* ci: scope the reported hash to the pnpmDeps block

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* ci(flake): scope every hash rewrite to the pnpmDeps block

alfred-openspec on #1817: the workflow read is scoped now, but the script it
runs is not. update-flake.sh read CURRENT_HASH from the first hash assignment
anywhere in flake.nix, and all three in-place rewrites matched every hash
assignment. flake.nix holds one fixed-output derivation today, so that lands on
the right line by luck; add a second and the script stamps the placeholder over
both, reads back whichever mismatch Nix reported first, and writes pnpmDeps'
hash into the other derivation. Scoping only the workflow left that path
fragile, as the review says.

The address range is declared once as PNPM_DEPS_BLOCK and used by the read and
all three rewrites, so the scoping cannot drift between call sites.

Also guards the read: an unmatched block previously left CURRENT_HASH empty,
and the failure path would then restore hash = "". It now exits before
touching the file.

Verified against a three-derivation fixture with pnpmDeps in the middle, which
catches both shapes of the bug: the scoped read returns the pnpmDeps hash while
an unscoped read returns the first derivation's, the placeholder is written
once rather than three times, and the neighbouring hashes survive the restore.
That fixture is the new test, alongside a static check that no hash read or
rewrite in the script is missing the range. Verified the static check fails
when any one call site is unscoped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(flake): run the scoping fixture on its own volume

The new test failed on windows-pwsh with 'sed: cannot rename ./sedKaAflu:
Invalid cross-device link'. sed -i writes its temp file in the working
directory and renames it over the target; on a GitHub Windows runner the repo
is on D: and os.tmpdir() is on C:, so that rename crosses volumes.

bash now runs with cwd set to the fixture directory and addresses the file by
name, which keeps the temp file and its rename on one volume. The assertions
are unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 16:24:16 +00:00
openspec-release-bot[bot] e062b9572b Version Packages (#1766)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@fission-ai/openspec@1.12.0 v1.12.0
2026-09-03 00:00:56 +00:00
Tabish Bidiwale fbd4160b37 docs: reroute unfinished store reference links (#1767)
Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 23:34:01 +00:00
Clay Good 9ec0a090b8 fix(security): patch fast-uri advisories (#1768) 2026-09-02 22:50:29 +00:00
dependabot[bot] 9dfffd87b3 chore(deps): bump the website-dependencies group across 1 directory with 7 updates (#1765)
* chore(deps): bump the website-dependencies group across 1 directory with 7 updates

Bumps the website-dependencies group with 7 updates in the /website directory:

| Package | From | To |
| --- | --- | --- |
| [fumadocs-core](https://github.com/fuma-nama/fumadocs) | `16.14.5` | `16.15.2` |
| [fumadocs-mdx](https://github.com/fuma-nama/fumadocs) | `15.2.3` | `15.3.1` |
| [fumadocs-ui](https://github.com/fuma-nama/fumadocs) | `16.14.5` | `16.15.2` |
| [lucide-react](https://github.com/lucide-icons/lucide/tree/HEAD/packages/lucide-react) | `1.31.0` | `1.34.0` |
| [next](https://github.com/vercel/next.js) | `16.3.1` | `16.3.3` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `26.2.0` | `26.3.0` |
| [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) | `19.2.4` | `19.2.5` |



Updates `fumadocs-core` from 16.14.5 to 16.15.2
- [Release notes](https://github.com/fuma-nama/fumadocs/releases)
- [Commits](https://github.com/fuma-nama/fumadocs/compare/fumadocs@16.14.5...fumadocs@16.15.2)

Updates `fumadocs-mdx` from 15.2.3 to 15.3.1
- [Release notes](https://github.com/fuma-nama/fumadocs/releases)
- [Commits](https://github.com/fuma-nama/fumadocs/compare/fumadocs-mdx@15.2.3...fumadocs-mdx@15.3.1)

Updates `fumadocs-ui` from 16.14.5 to 16.15.2
- [Release notes](https://github.com/fuma-nama/fumadocs/releases)
- [Commits](https://github.com/fuma-nama/fumadocs/compare/fumadocs@16.14.5...fumadocs@16.15.2)

Updates `lucide-react` from 1.31.0 to 1.34.0
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/commits/1.34.0/packages/lucide-react)

Updates `next` from 16.3.1 to 16.3.3
- [Release notes](https://github.com/vercel/next.js/releases)
- [Commits](https://github.com/vercel/next.js/compare/v16.3.1...v16.3.3)

Updates `@types/node` from 26.2.0 to 26.3.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `@types/react-dom` from 19.2.4 to 19.2.5
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

---
updated-dependencies:
- dependency-name: fumadocs-core
  dependency-version: 16.15.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: website-dependencies
- dependency-name: fumadocs-mdx
  dependency-version: 15.3.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: website-dependencies
- dependency-name: fumadocs-ui
  dependency-version: 16.15.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: website-dependencies
- dependency-name: lucide-react
  dependency-version: 1.34.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: website-dependencies
- dependency-name: next
  dependency-version: 16.3.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: website-dependencies
- dependency-name: "@types/node"
  dependency-version: 26.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: website-dependencies
- dependency-name: "@types/react-dom"
  dependency-version: 19.2.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: website-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(website): align esbuild build approval

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 22:22:14 +00:00
dependabot[bot] cb5ae2cd16 ci: bump changesets/action from 1.9.0 to 2.1.1 in the github-actions group (#1746)
* ci: bump changesets/action in the github-actions group

Bumps the github-actions group with 1 update: [changesets/action](https://github.com/changesets/action).


Updates `changesets/action` from 1.9.0 to 2.1.1
- [Release notes](https://github.com/changesets/action/releases)
- [Changelog](https://github.com/changesets/action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/changesets/action/compare/a45c4d594aa4e2c509dc14a9f2b3b67ba3780d0d...8488615a623b1b9c987934bb89eae8af6a946ac1)

---
updated-dependencies:
- dependency-name: changesets/action
  dependency-version: 2.1.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(ci): complete changesets action v2 migration

* fix(nix): invalidate pnpm dependency hash

* fix(nix): use calculated dependency hash

* fix(nix): refresh pnpm dependency hash

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 21:55:12 +00:00
Marzx13 db03c6c4b0 feat(validate): add findings-only bulk reports (#1713)
* feat(validate): propose findings report

* docs(validate): clarify findings report contract

* feat(validate): implement and harden bulk findings reports

* test(validate): canonicalize store paths natively

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 21:07:46 +00:00
Ryan de Melo a4fcdbece6 feat(validate): report the deltas archive would refuse (#1710)
* feat(validate): report the deltas archive would refuse

validate checked a change's deltas against themselves and, for MODIFIED
blocks, against the main spec's scenarios. It never checked whether the
main spec can supply the target a delta acts on, so a MODIFIED naming a
requirement that is not there, a RENAMED whose source is gone, or an
ADDED whose name already exists all validated clean and failed at
archive instead - typically weeks later, after the implementing PR had
shipped and the authoring session was gone.

Run the merge archive runs and report what it refuses. buildUpdatedSpec
returns the rebuilt content without writing it, so the preflight is the
same function on the same inputs with the result discarded, and cannot
disagree with the code that does the writing. That matters here: several
of those preconditions deliberately read a missing target as
already-synced rather than as a failure, and a second copy of the rules
would be free to drift.

Reported as INFO so no verdict changes in any mode. A MODIFIED whose
target is missing is also what a change modifying a sibling's unarchived
requirement looks like, and validate stays valid for that case today;
telling the two apart needs the opt-in marker #1112 asks for. What is
missing until then is the information, not the verdict.

Refs #1112

* fix(validate): skip preflight for deltas whose errors come after the loop

missingHeaderSpecs and emptySectionSpecs are collected inside the
per-spec loop but only become issues after it, so a suppression set
built from the issues raised so far could not see them. A headerless or
empty-section delta has nothing for the merge to apply, so the preflight
reported that as a blocker of its own, on top of the error that names
the actual mistake.

* fix(validate): harden archive preflight diagnostics

* fix(validate): preserve reports when archive preflight cannot start

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 20:59:09 +00:00
Br1an 0296401b82 fix(init): add .gitkeep files to empty directories (#786)
* fix(init): add .gitkeep files to empty directories

After running openspec init, the specs/, changes/, and changes/archive/
directories are empty. Since git does not track empty directories, these
folders are lost when the repository is cloned, causing openspec list to
recommend re-initialization.

Added .gitkeep file creation to createDirectoryStructure() for both
normal and extend modes, ensuring empty directories are preserved in
version control.

Fixes #269

* fix(init): preserve directory anchors without overwriting user files

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 20:50:59 +00:00
Aron Lee cd724449ac refactor(core): share the IDE restart hint between init and update (#1725)
* refactor(core): share the IDE restart hint between init and update

init named the surface it generated ("the new commands" / "the new skills");
update printed a generic "changes" for the same event, decided by the same
rule. Extract that rule and its wording into shared/ide-restart.ts so both
commands say the same thing, and update now names the surface too.

No condition changed: the hint still requires one tool that is both
IDE-resident and actually received a generated surface under the active
delivery, so a CLI tool's commands can never speak for an IDE tool that got
nothing.

Verified by mutation: dropping the IDE-resident filter turns 9 tests red
across the helper, init and update; swapping the commands/skills precedence
turns 5 red.

* test(core): harden shared IDE restart guidance

* fix(core): describe restart guidance for removed workflows

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 20:41:20 +00:00
Clay Good 954d4796a4 docs(community): add a community showcase (#1739)
* docs(readme): list the independent openspec ui project

* docs(community): move the showcase out of the readme
2026-09-02 20:32:42 +00:00
Clay Good 98bf53e59e fix(workflows): ground proposals in relevant project code (#1737) 2026-09-02 20:25:06 +00:00
Howard 2fd175c8b0 docs(cli): document managed PowerShell completion setup (#1070)
* docs(cli): add Windows PowerShell completion example

The shell completion documentation only showed Unix/bash examples,
making it unusable for Windows users. Added platform-specific examples
for both Unix/macOS (bash) and Windows (PowerShell).

Changes:
- Add Unix/macOS (bash) example with ~/.bash_completion.d path
- Add Windows (PowerShell) example with C:\Users\y00031947\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 path
- Improve clarity with platform labels

Fixes: Windows users cannot use shell completion manual installation

* fix(cli): use append operator for PowerShell profile to avoid data loss

Critical fix: Using '>' operator would overwrite the user's PowerShell
profile, deleting existing configurations. Changed to '>>' to append
instead of overwrite, preserving user's existing settings.

* docs(cli): harden PowerShell completion setup

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 20:14:57 +00:00
Dan (Danilo) Rio (Ribeiro) b976106d95 fix(explore): guide planning with focused discovery questions (#1017)
* feat: improve explore discovery questions

* chore: add changeset for explore guidance

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 20:07:20 +00:00
openspec-cloud[bot] cdd06a0594 docs(specs): align four requirements with current behavior (#1707)
* docs(openspec): correct 4 requirements that the code has outgrown

- ai-tool-paths/path-configuration-for-supported-tools#2: Changed the windsurf scenario's required skillsDir from `.windsurf` to `.devin`.
- cli-update/slash-command-updates#6: Require $ARGUMENTS to be placed in the file body (not frontmatter) for OpenCode archive commands.
- rules-injection/validate-artifact-ids-during-instruction-loading#6: Updated the expected warning text to use double quotes and to state it matches no artifact in any available schema, listing known artifact IDs.
- specs-sync-skill/skill-output#3: Changed the expected no-changes message to 'Specs already in sync; no files changed.' to match the code.

None of these reduce what a requirement demands.

Scanned at 1ebddd17f4 by openai/gpt-5-mini.

* docs(openspec): correct 3 requirements that the code has outgrown

- ai-tool-paths/path-configuration-for-supported-tools#2: Updated the Windsurf scenario to expect skillsDir '.devin' instead of '.windsurf'.
- cli-artifact-workflow/experimental-isolation#8: Updated the file-path in the Single file implementation scenario from src/commands/artifact-workflow.ts to src/commands/workflow to match current code organization.
- command-generation/toolcommandadapter-interface#2: Updated the Windsurf adapter file path pattern to use '.devin/workflows/opsx-<id>.md' to match the implemented adapter.

None of these reduce what a requirement demands.

Scanned at 1ebddd17f4 by openai/gpt-5-mini.

* docs(openspec): correct 4 requirements that the code has outgrown

- ai-tool-paths/path-configuration-for-supported-tools#2: Updated the windsurf scenario to require skillsDir `.devin` instead of `.windsurf` to match current mapping.
- cli-artifact-workflow/experimental-isolation#8: Updated the path in the 'Single file implementation' scenario from src/commands/artifact-workflow.ts to src/commands/workflow/*.
- context-injection/format-context-with-xml-style-tags#2: Updated tag name from <context> to <project_context> in the requirement and scenarios to match implementation.
- specs-sync-skill/skill-output#3: Updated the No changes needed scenario message to match the actual output: changed text to 'Specs already in sync; no files changed.'

None of these reduce what a requirement demands.

Scanned at 1ebddd17f4 by openai/gpt-5-mini.

* docs(openspec): correct 5 requirements that the code has outgrown

- cli-artifact-workflow/experimental-isolation#8: Updated the single-file path from src/commands/artifact-workflow.ts to src/cli/index.ts to match code.
- ai-tool-paths/path-configuration-for-supported-tools#2: Updated the Windsurf scenario to require skillsDir `.devin` instead of `.windsurf` to match the alias to Devin.
- command-generation/toolcommandadapter-interface#2: Updated the Windsurf adapter file path requirement to use the .devin/workflows/opsx-<id>.md path.
- cli-artifact-workflow/schema-apply-block#9: Updated the default instruction text to include the word "required", matching the implemented string.
- opsx-onboard-skill/graceful-exit-handling#8: Updated the continuation command from `/opsx:continue <name>` to `/openspec-continue-change <name>` to match the implemented command.

None of these reduce what a requirement demands.

Scanned at f1b521dffa by openai/gpt-5-mini.

* docs(openspec): correct 5 requirements that the code has outgrown

- ai-tool-paths/path-configuration-for-supported-tools#2: Updated the 'windsurf' scenario to require skillsDir '.devin' to match the current mapping of 'windsurf' to 'devin'.
- cli-init/exit-codes#7: Updated the exit code for user-cancelled operations from 3 to 130.
- context-injection/format-context-with-xml-style-tags#2: Replaced <context> tag name with <project_context> in requirement text and both scenarios to match the implemented tag.
- specs-sync-skill/skill-output#3: Replaced the no-changes message text to match the actual logged message ('Specs already in sync; no files changed.').
- telemetry/first-run-telemetry-notice#5: Updated the quoted one-line notice text to include the additional opt-out instruction 'or openspec config set telemetry.enabled false' to match the implemented message.

None of these reduce what a requirement demands.

Scanned at f1b521dffa by openai/gpt-5-mini.

* docs(openspec): correct 4 requirements that the code has outgrown

- ai-tool-paths/path-configuration-for-supported-tools#2: Updated the Windsurf scenario to require skillsDir '.devin' instead of '.windsurf'.
- cli-init/progress-indicators#1: Replaced the grouped spinner text '⠋ Configuring AI tools...' with the per-tool spinner text 'Setting up <tool.name>...'.
- specs-sync-skill/skill-output#3: Replaced the no-changes message to match the code: "Specs already in sync; no files changed."
- telemetry/first-run-telemetry-notice#5: Updated the quoted first-run notice text to include the alternative opt-out command 'or openspec config set telemetry.enabled false'.

None of these reduce what a requirement demands.

Scanned at f1b521dffa by openai/gpt-5-mini.

* docs(openspec): correct 6 requirements that the code has outgrown

- ai-tool-paths/path-configuration-for-supported-tools#2: Updated the Windsurf scenario to require skillsDir '.devin' to match the code mapping.
- cli-change/legacy-compatibility#2: Changed the deprecated command in both scenarios from 'openspec list' to 'openspec change list' and updated the deprecation notice to point users to 'openspec list'.
- cli-init/exit-codes#7: Updated the exit code for user-cancelled operations from 3 to 130 to match implemented behavior.
- cli-artifact-workflow/schema-apply-block#9: Updated default instruction text to match code: changed "All artifacts complete. Proceed with implementation." to "All required artifacts complete. Proceed with implementation."
- cli-artifact-workflow/output-messaging#12: Updated the expected skipped-commands message to match the actual output format: "Commands skipped for: <tools> (no adapter)".
- specs-sync-skill/skill-output#3: Updated the exact no-changes message to match the code's wording.

None of these reduce what a requirement demands.

Scanned at a0ddb60d04 by openai/gpt-5-mini-2025-08-07.

* docs(specs): verify drift corrections against current behavior

---------

Co-authored-by: openspec-cloud[bot] <311461291+openspec-cloud[bot]@users.noreply.github.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 19:59:42 +00:00
Pablo Formoso 1bcdf1b032 fix(build): prepare npm git installs without pnpm (#792)
* fix: handle npm git dep installation for GitHub installs

npm v11's git dep preparation runs `prepare` before node_modules exist
in the temp clone directory, causing TypeScript compilation to fail.

Changes:
- build.js: skip build gracefully when node_modules absent
- package.json: use `node build.js` directly in prepare/prepack for
  npm compatibility (avoids pnpm dependency during git dep install)

Note: postinstall.js already handles all errors internally via
main().catch(() => process.exit(0)), so no `|| true` wrapper needed.

Install from GitHub with:
  npm pack github:user/repo#branch
  npm install -g ./fission-ai-openspec-x.y.z.tgz

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(build): prepare npm git installs without pnpm

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 19:49:03 +00:00
Александр Мелентьев 44a39eb24b feat(core): add codeassistant support (#1171)
* feat(core): add codeassistant support

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>

* chore: change format file and add test

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>

* chore: add tests

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>

* fix: escaped description yaml values

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>

* chore: add test

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>

* chore: change adapter

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>

* chore: handle \r in description

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>

* chore: use common escapeYamlValue helper

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>

* chore(release): track sourcecraft support

---------

Signed-off-by: Александр Мелентьев <aleksandr4842@ya.ru>
Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 19:40:20 +00:00
Jason Hindley 142b8a9203 fix(docs): route OpenSpec pixel through Pages (#1757)
* Route /openspec-pixel.svg to the docs Pages deployment

The docs nav logo is referenced via the root-relative path
/openspec-pixel.svg, which isn't matched by isDocsRoute() and so falls
through to the Astro landing site instead of the docs Pages project
that actually has the asset - a 404. /icon.svg already has this exact
special case; this adds the same for the pixel logo.

Fixes #1756

* fix(docs): route pixel logo through worker

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 19:31:59 +00:00
dependabot[bot] 6911f55175 fix(deps): preserve Node 20 chalk compatibility (#1747)
* chore(deps): bump chalk from 5.6.2 to 6.0.0

Bumps [chalk](https://github.com/chalk/chalk) from 5.6.2 to 6.0.0.
- [Release notes](https://github.com/chalk/chalk/releases)
- [Commits](https://github.com/chalk/chalk/compare/v5.6.2...v6.0.0)

---
updated-dependencies:
- dependency-name: chalk
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(nix): refresh dependency hash

* fix(nix): use calculated dependency hash

* fix(deps): preserve Node 20 chalk compatibility

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 19:24:39 +00:00
dependabot[bot] c5c38a7aca chore(deps-dev): bump eslint from 10.8.1 to 10.9.0 in the development-dependencies group (#1745)
* chore(deps-dev): bump eslint in the development-dependencies group

Bumps the development-dependencies group with 1 update: [eslint](https://github.com/eslint/eslint).


Updates `eslint` from 10.8.1 to 10.9.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v10.8.1...v10.9.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-version: 10.9.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(nix): refresh dependency hash

* fix(nix): use calculated dependency hash

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-09-02 19:15:51 +00:00
Clay Good d0071d7326 docs(archive): show how to retire capabilities (#1751) 2026-09-01 00:16:02 +00:00
openspec-release-bot[bot] a0ddb60d04 Version Packages (#1728)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
v1.11.0
2026-08-26 21:19:57 +00:00
Ryan de Melo 2fa679f180 fix(schema): make schema init --default actually set the default (#1709)
* fix(schema): make schema init --default actually set the default

--default wrote defaultSchema to openspec/config.yaml, but the config
loader only reads schema, so new changes kept using spec-driven while
the command reported success. Write the key that is read, and drop the
dead one a previous run may have left behind.

Fixes #1708

* fix(schema): preserve supported configs when setting default

* docs(schema): specify default config file handling

* docs(schema): protect default config migration

* fix(schema): make default initialization atomic

* fix(schema): hide init staging and backup dirs from discovery

`schema init` stages into `.init-staging-<rand>` and moves an existing
schema aside to `<name>.init-backup-<pid>-<ts>`, both inside the schemas
dir. `schema fork` already did this and the resolver filters its temp
names out of discovery; the init names were never added, so `listSchemas`
and `listSchemasWithInfo` surfaced them as real schemas -- in shell
completions, "available schemas" error lists, and change-metadata
validation.

The backup is the durable case: cleanup failure is deliberately tolerated
with a warning, so a blocked cleanup (or a crash mid-transaction) leaves a
permanent phantom schema behind.

Generalize the fork-only filter to cover both commands' staging and backup
names. Real schema names are kebab-case, so excluding these dot-bearing
names can never hide a legitimate schema.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Clay Good <hi@claygood.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 20:42:30 +00:00
Shooks e5e350d04b fix(explore): use ASCII in diagram examples (#1010)
* fix: Use ASCII arrows instead of unicode

This fixes the issue of ambiguous unicode character width when visualizing on terminals

* fix: Update remaining docs within explore to use ASCII

* fix(explore): finish the ASCII conversion and guard it

Rebase onto main and close the gaps in the original fix:

- Regenerate skills/openspec-explore/SKILL.md. The static skills/ mirror
  landed after this branch was cut, so the parity test would have failed
  with the template and the mirror out of sync.
- Regenerate the three parity hashes through scripts/regen-parity-hashes.mjs.
- Convert the ambiguous-width glyphs the first pass missed: the bullets in
  the CLI-storage example, and the check/cross marks in its comparison
  table, which sat in the column-aligned block the bug is about.
- Tighten the ASCII guidance to two lines. It ships into every user
  project on both delivery surfaces, so the paragraph was pure overhead.
- Add regression tests (#983): every fenced example in both the skill and
  the command body must be free of box-drawing, arrow, bullet, and
  check/cross glyphs, and the guidance must state the rule and the reason.
- Add a patch changeset.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(explore): cover every check/cross dingbat in the ASCII guard

The matcher listed U+2713 and U+2717 only, so a fenced example could use
✕ (U+2715) or ✘ (U+2718) — same ambiguous width, same misalignment — and
still pass. Widen to the U+2713-U+2718 run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(explore): require explicit confirmation before writing files

* test(explore): harden write confirmation guardrail

* fix(explore): scope write confirmation precisely

---------

Co-authored-by: Clay Good <hi@claygood.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Ayman D. <ayman.bacc@gmail.com>
2026-08-26 20:18:06 +00:00
bsmedberg-xometry dd7cea3ffe feat(show): diff delta requirements against the main specs (#980)
* Proposed feature: openspec show --diff to see changed requirements more clearly

* Implementation of the --diff feature, which led to some spec changes during implementation.

* Update the proposal to be clearer. Thanks coderabbit

* Fix a bug identified by coderabbit with excessive trimming, and add a testcase for it.

* fix(show): harden --diff for review feedback

Keeps `openspec show <change>` without `--diff` a raw proposal
passthrough, reports when a change has no delta specs instead of
returning silently, preserves the Reason/Migration body of a REMOVED
requirement, and resolves main specs through the command's root so
`--store <id>` diffs against that store.

Text mode and JSON mode now render from one shared collection pass, the
CLI tests drive argv arrays from a mkdtemp project instead of
interpolated shell strings, `--diff` is registered for shell
completions, and the stray package-lock.json is gone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* build(deps): declare the diff dependency and refresh the flake hash

Adds the `diff` runtime dependency that requirement-diff.ts imports,
updates pnpm-lock.yaml, and regenerates the flake's pnpmDeps hash so
`nix build` matches the new lockfile.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(show): diff nested capabilities too

collectSpecDiffs enumerated only top-level directories under the
change's specs/, so a nested capability (specs/<area>/<id>/spec.md) was
skipped: text mode printed nothing for it and its MODIFIED deltas came
back from --json with no diff. It now uses the same discoverSpecFiles()
helper ChangeParser uses, so the capability ids match the `spec` field
of the JSON deltas.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(show): report header mismatches instead of hiding them

Two cases where --diff quietly showed something misleading:

A MODIFIED requirement whose capability has no main spec was rendered as
all-additions, which reads like a new capability. It is an authoring
error archive will reject, so it now prints the raw text with a warning
naming the missing spec.

A header that differs from the main spec only in case or interior
spacing found no match at all under exact lookup, or matched under a
lowercase-only comparison that let a real mismatch through silently.
Lookup is now exact first, then the shared foldRequirementName fallback,
and a folded match prints the diff the author meant alongside a warning
that archive matches names exactly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor(show): name the main spec as such in collectSpecDiffs

Comment and locals still called the main spec the "base" spec, and the
no-main-spec comment described the old all-additions behavior.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* chore(deps-dev): bump the development-dependencies group with 2 updates

Bumps the development-dependencies group with 2 updates: [smol-toml](https://github.com/squirrelchat/smol-toml) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).


Updates `smol-toml` from 1.7.1 to 1.8.0
- [Release notes](https://github.com/squirrelchat/smol-toml/releases)
- [Commits](https://github.com/squirrelchat/smol-toml/compare/v1.7.1...v1.8.0)

Updates `typescript-eslint` from 8.66.0 to 8.67.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.67.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: smol-toml
  dependency-version: 1.8.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: typescript-eslint
  dependency-version: 8.67.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(nix): invalidate pnpm dependency hash

* fix(nix): update pnpm dependency hash

* fix(show): harden requirement diff output

* build(nix): pin combined dependency hash

* test(show): assert proposal precedes diffs

* docs(show): clarify JSON diff diagnostics

* fix(show): retain unified diff hunk headers

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Clay Good <hi@claygood.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-26 20:18:03 +00:00
Leonardo Rojas ab81a4b43a fix(completions): stop Fish completions falling back to filenames (#1199)
* fix(completions): suppress filesystem fallback in Fish completions

* fix(completions): force files back on for path positionals in Fish

Fish never restores filesystem completion once a matching rule sets
--no-files, so a path positional needs an explicit --force-files rule.
Without it, `openspec store register <TAB>` lost file completion because
the sibling subcommand rules in the same context now carry -f.

Also drop retired "context store" vocabulary from the test fixtures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(completions): preserve workset member paths in fish

* fix(completions): force Fish path fallback

* fix(completions): harden Fish option handling

* fix(completions): scope Fish path fallback

* fix(completions): match Fish command paths exactly

* fix(completions): skip parent options in Fish paths

---------

Co-authored-by: Clay Good <hi@claygood.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 19:27:27 +00:00
Alfred 109f81f17d fix(antigravity): update skill and workflow paths from .agent to .agents (#830)
* fix(antigravity): update skill and workflow paths from .agent to .agents

Antigravity has migrated from .agent (singular) to .agents (plural) for
workspace skills and workflows. The old .agent path still works via
backward compatibility, but the official docs now specify .agents.

Changes:
- config.ts: skillsDir '.agent' -> '.agents'
- antigravity adapter: workflow path '.agent/workflows/' -> '.agents/workflows/'
- legacy-cleanup: add patterns for old .agent/ artifacts cleanup
- docs: update supported-tools.md table
- tests: update expected path assertions

Closes #0 (reported by BugsCreator and Minh Pham in Discord)

* fix(antigravity): migrate an existing .agent install to .agents

Pointing Antigravity at `.agents` leaves every existing `.agent/` install
behind, so this registers the move instead of only changing the target:

- `.agent` becomes Antigravity's legacy skills root and legacy tool root, so
  update relocates managed skills and commands after generating their
  replacement, keeping a file the user customized.
- Detection keys off `.agent` and `.agents/workflows`. The bare `.agents` root
  is shared with Codex, Zed, and the vendor-neutral target, so it cannot stand
  in for "Antigravity is set up here".
- Delivery inference reads a tool's legacy roots for command files too.
  Without it the first update after the move saw skills but no commands,
  wrote `delivery: skills`, and the next update deleted every slash command.
- Legacy slash-command cleanup stays scoped to the pre-opsx `openspec-*` names
  under `.agent`; the migration owns the `opsx-*` files, and a shared root is
  never glob-swept.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: record the Antigravity root move

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(antigravity): require a generated command before moving its legacy copy

migrateCommandFiles relocated a legacy command file whether or not the
current root held a replacement. Codex never reached that path — it has no
command adapter — so Antigravity is the first after-generation move where it
matters: under skills-only delivery, or for a deselected workflow, the move
recreated a command OpenSpec had just decided not to install.

Gate the move on an existing destination, the same way migrateSkillDirs
already does for after-generation timing.

Reported by CodeRabbit on #830.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(antigravity): arbitrate shared agent skills

* test(antigravity): cover Windows migration paths

* fix(antigravity): harden shared-root migration

---------

Co-authored-by: Clay Good <hi@claygood.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 19:25:46 +00:00
Marzx13 04b37ac1d5 fix(archive): preserve requirement order when renaming (#1712)
* fix(archive): preserve requirement order when renaming

* chore(archive): add rename-order changeset

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-08-26 19:25:43 +00:00
mark 126c5d6c59 fix(validate): report a Purpose left as the archive placeholder (#1671)
* docs(openspec): propose warn-on-purpose-placeholder

When a delta introduces a capability with no usable `## Purpose`, archive
writes `TBD - created by archiving change <name>. Update Purpose after
archive.` into the new main spec. Three places already tell authors to
replace it -- the `specs` instruction ("including a leftover `TBD`
placeholder"), the sync-specs summary step ("so it gets written now rather
than lingering"), and the cli-archive contract -- but nothing reports that
it is still there.

`--strict` cannot reach it. The check meant to catch a Purpose nobody wrote
is a 50-character floor and the placeholder is 91 characters, so the one
rule that exists to catch a thin Purpose is satisfied by the exact text
meaning nobody wrote one: a Purpose reading "Does stuff." fails --strict
today, while one saying nothing at all passes.

Proposes reporting it as a warning against the spec's Purpose -- silent by
default, failing under --strict, so a project already carrying placeholders
keeps validating until it opts into the stricter gate. Detection is narrow:
the generated sentence wherever it appears, and otherwise only a `TBD`
opening the Purpose, so prose raising an open question is left alone.

Planning artifacts only; no source changes.

Refs #369

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(validate): report a Purpose left as the archive placeholder

When a delta introduces a capability with no usable `## Purpose`, archive
writes a placeholder into the new main spec. Nothing read it afterwards, so
the capability kept a to-do in it while every command reported success.

`--strict` could not reach it. The check that exists to catch a Purpose
nobody wrote is a 50-character floor, and the placeholder clears it: a spec
whose Purpose read "Does stuff." failed --strict, while a spec whose Purpose
said nothing at all passed. #369 reported agents leaving the placeholder
behind and stayed open seven months; every remedy since has been an
instruction, which is the mechanism that report described as unreliable.

validate now reports it as a warning against the Purpose, naming the line
and saying to edit the main spec directly -- a delta's `## Purpose` is read
only when the capability is created, so it cannot replace an existing one.

Warning rather than error, because strict mode already means "warnings
fail": a project carrying placeholders keeps validating by default and only
--strict fails. Archive is untouched -- it validates rebuilt specs without
--strict, so a spec archive writes still passes the validation it would have
passed before, and the text archive writes is byte-identical.

The placeholder is recognised through the same constants the writer composes
it from, so the check cannot drift from the sentence it looks for -- the
failure mode of a second, hand-copied spelling being a check that matches
nothing and looks exactly like a check that found nothing. The one case that
cannot be a lookup is an agent-written placeholder, kept to a `TBD` opening
the Purpose: "the retry budget is TBD pending benchmarks" is authored prose
and is left alone.

Verified: 209 archive tests pass unchanged (the placeholder text is
asserted literally, so the output is provably identical); full suite 138
files / 3993 tests; 36/36 strict spec validations; build, lint and typecheck
clean. Against a project carrying four real placeholders, default mode still
exits 0 and --strict fails exactly those four.

Cross-platform CI is not yet confirmed -- it needs a pushed branch. Line
endings are covered by tests asserting a CRLF spec and an LF spec produce
identical findings, and the module does no path handling.

Refs #369

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(validate): make every placeholder guard load-bearing

A mutation pass over the seven guards -- revert one, see which tests die --
found two that no test held.

The prefix/suffix test did not exercise the guard it named. Its Purpose read
"Explains what happens when archiving change my-change runs twice", which
contains neither half of the generated sentence, so it passed whether or not
the suffix was required. Matching on the prefix alone killed nothing. The
Purpose now embeds the real prefix constant and asserts the suffix is absent,
so the case is the one the name claims; the mutation kills it.

The empty-Purpose early return was genuinely dead. Neither rule matches empty
text, so removing the branch changed no behaviour and failed no test. Rather
than keep a guard nothing can hold, the branch is gone and the comment says
why an empty Purpose still yields null. The tests asserting that behaviour
are unchanged and still pass.

Every guard now dies under mutation:

  whole check removed from applySpecRules ......... 6 tests
  brevity no longer suppressed (else -> if) ....... 1
  word boundary dropped from the TBD marker ....... 1
  generated placeholder matched on prefix alone ... 1
  line-ending normalisation removed ............... 2
  section-boundary guard removed from locator ..... 1

Full suite 138 files / 3993 tests, lint and typecheck clean.

Refs #1670

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(openspec): record the mutation pass in the task list

The mutation work changed the implementation -- a test rewritten and a dead
branch removed -- but no task covered it, so the plan claimed less work than
was done. Added as group 6, marked complete, with why it was not planned.

5.4 now says what blocks it. It needs a pushed branch for the cross-platform
matrix, and the note records that line endings are covered locally by tests
asserting a CRLF spec and an LF spec produce identical findings, so a reader
can tell the difference between unverified and unverifiable-from-here.

The specs, proposal and design are unchanged and were checked: the delta's
empty-Purpose clause constrains behaviour, not structure, and that behaviour
is the same -- the redundant branch went, the rule did not.

26 of 27 tasks complete; the change still validates --strict.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* docs(openspec): close 5.4 on a green cross-platform matrix

CI dispatched on the fork against this branch: lint & typecheck, and the test
suite on linux-bash, macos-bash and windows-pwsh -- all green. The Windows job
installed, built and ran the suite rather than short-circuiting, which is the
part 5.4 existed to check, since the placeholder locator counts lines in files
that may carry either ending.

Recorded as a workflow_dispatch run on the fork, not the upstream pull-request
run, because those are not the same gate and the note should not let a reader
assume otherwise. Nix Flake Validation and Validate Release Tracking skipped:
this branch touches neither the flake nor release tracking.

27 of 27 tasks complete.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(validate): name the placeholder's line, not the prose above it

The warning tells you which line to fix, and named the wrong one when the
generated sentence did not open the Purpose:

     3  ## Purpose
     4  Handles widget retries.            <- warning pointed here
     5
     6  TBD - created by archiving ...     <- placeholder is here

The locator asked "what is the first non-blank line after ## Purpose?"
rather than "where is the placeholder?". Those are the same line in five of
the six shapes a placeholder can take -- a leading TBD marker is the first
non-blank line by definition, and archive writes the generated sentence as
the section's only content -- so the two questions only diverge when a human
types prose above a leftover placeholder.

Pointing at that prose is worse than pointing nowhere: the reader sees a
sentence that is plainly fine and concludes the check is broken. design.md
already said a wrong line number is worse than none, and the delta already
required naming the line the placeholder is on, so this is the
implementation meeting a contract that was already written, not a change of
contract.

The locator is now told which rule matched. A leading marker keeps the
first-non-blank behaviour, because that is where it sits; the generated
sentence is located by its own text. When both match the leading marker
wins, being the earlier of the two.

Found by CodeRabbit on #1671. The finding was real despite its own
"Addressed" marker, which only tracked the file changing in a later commit.

Two test gaps let it through. The case that covered this input asserted
only that something was reported, never which line -- so it now asserts the
line, and a table pins every position a placeholder can occupy, each case
first checking that the line it expects really carries the placeholder. The
mutation pass could not have caught it either: mutation proves a test dies
when a guard is broken, and cannot invent an assertion nobody wrote.

Reverting the branch fails exactly the three new expectations. Full suite
4000 tests / 138 files, lint and typecheck clean.

Refs #1670

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor(validate): set the placeholder line unconditionally

ValidationIssue.line is optional and the project does not enable
exactOptionalPropertyTypes, so a plain assignment typechecks and
JSON output is unchanged - JSON.stringify drops undefined values.
findPurposePlaceholderIssue already returns the key unconditionally,
and the neighbouring push sites assign line plainly, so the
conditional spread was the odd one out.

* fix(validate): widen the placeholder check to TODO and read fences as quoted

#1670 left two questions open. Both are answered here, against how OpenSpec
already reads a spec.

A `TODO` opening the Purpose now reports as the same finding as a `TBD`.
Nothing OpenSpec writes produces one, but the marker an author leaves behind is
whichever word they reached for, and a Purpose reading `TODO: fill this in` is
as unwritten as one reading `TBD`. Only the opening position counts, as before,
so `TODOs are tracked in the linked issue` is still authored prose.

Fenced code inside a Purpose is now read as quoted material rather than as the
Purpose speaking, through the `buildCodeFenceMask` the requirement and structure
parsers already share. Without it a spec documenting the sentence archive writes
is reported as carrying it, which is the check failing the one document that
explains it - and a warning that fires on the docs teaches people to ignore the
warning. Fenced lines are skipped when locating the placeholder too, so a
`## Purpose` or `## Requirements` quoted in a fence can neither be mistaken for
the section header nor end the section early.

The message now names both what archive writes and a marker left in its place,
since one message covers both. Severity is unchanged: still a warning, so a
project carrying placeholders keeps validating and only --strict fails.

Every new guard is mutation-checked: dropping `TODO` kills 3 tests, unmasking
detection kills 2, unmasking the line locator kills 3, unmasking the header
search kills 1.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(validate): read the marker boundary in any script, not just ASCII

Review found `\b` reading `TODOé` and `TBD١` as a marker followed by
punctuation, because `\b` only knows ASCII word characters. A Purpose is prose
and prose is not always Latin script, so the rule that a longer word beginning
with those letters is not a marker has to hold in any script.

The lookahead rejects letters, digits, combining marks and `_`, and nothing
else, so `TODO:`, `TBD -` and `TODO(owner):` are still the marker they look
like. Held in both directions: loosening it back to `\b` kills 1 test,
tightening it to reject punctuation kills 4.

Also reworded a task line that opened with `#1670`, which markdownlint reads as
a heading missing its space.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(validate): locate the matched purpose placeholder

* docs(validate): remove trailing task whitespace

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-08-26 19:25:40 +00:00
Tanner a7353aea9a feat(status): add --all for batch status of every active change (#1301)
* feat(status): add --all for batch status of every active change

`openspec status --all --json` reports every active change in one
process instead of one CLI spawn (~500ms module-load) per change,
mirroring the existing `validate --all`. Emits a single
`{ changes: [ChangeStatus, ...], root }` envelope sorted by change
name; a change that fails to load contributes a per-change error entry
instead of failing the sweep. `--all` and `--change` are mutually
exclusive, honoring the --json null-shape on failure.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(status): harden --all per adversarial review findings

- Validate --schema before the no-changes early return so a bogus
  schema fails consistently whether or not any change exists.
- Text mode now exits 1 when any change fails to load (mirrors
  validate --all); JSON mode still exits 0 with per-change diagnostics.
- Add tests for the --all --schema interaction (unknown schema
  null-shape, override propagation, broken-metadata precedence) and
  text-mode failure rendering.
- Changeset heading to "### New Features" per repo convention; add
  status --all to the agent quick-reference table in docs/cli.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(status): thread batch null-shape through root resolution, align sort with validate

Code-review findings on --all:
- Pass failurePayload: { changes: [] } to resolveRootForCommand so a
  root-selection failure under --all --json still emits the documented
  batch null-shape (siblings like list/doctor/context already do this).
- Sort with localeCompare to match validate --all's ordering for
  mixed-case change names.
- Extract a shared loadStatus helper so the batch and single-change
  payloads cannot drift apart.
- Changeset no longer claims exact validate --all parity (JSON exit
  semantics deliberately differ).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(status): give the --all failure null-shape a single owner

Simplify pass on the --all diff: hoist the { changes: [] } batch
null-shape into an exported BATCH_STATUS_FAILURE_PAYLOAD constant so
the root-resolution and CLI-wrapper failure paths cannot drift, replace
the conditional spread with the plain ternary the sibling call site
already uses, drop a redundant array copy before sort, and narrow the
text-mode failure counter to the boolean it actually is.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(status): point the missing-target error at --all, correct the docs

`openspec status` with neither --change nor --all listed the available
changes and named only --change, so the batch path was discoverable
only from --help. The error now offers both.

Also corrects two stale claims in the status section of docs/cli.md
that the new row sits next to: the command never prompts for a change
(it errors), and bare `openspec status` is not an interactive check.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(status): assert --all carries store context like the single-change path

The batch sweep resolves the root once and threads the store id into
every entry. Nothing pinned that: a regression would have shown up only
as a wrong path inside an agent's JSON. Assert the sweep's envelope root
and per-change payload match `status --change` in a registered store.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(status): fail incomplete batch reports

* docs(status): clarify empty and batch output

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-08-26 19:25:39 +00:00
dependabot[bot] c0c50f9a4c chore(deps-dev): bump the development-dependencies group with 2 updates (#1718)
* chore(deps-dev): bump the development-dependencies group with 2 updates

Bumps the development-dependencies group with 2 updates: [smol-toml](https://github.com/squirrelchat/smol-toml) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint).


Updates `smol-toml` from 1.7.1 to 1.8.0
- [Release notes](https://github.com/squirrelchat/smol-toml/releases)
- [Commits](https://github.com/squirrelchat/smol-toml/compare/v1.7.1...v1.8.0)

Updates `typescript-eslint` from 8.66.0 to 8.67.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.67.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: smol-toml
  dependency-version: 1.8.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
- dependency-name: typescript-eslint
  dependency-version: 8.67.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: development-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>

* chore(nix): invalidate pnpm dependency hash

* fix(nix): update pnpm dependency hash

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Clay Good <hi@claygood.com>
2026-08-26 19:25:07 +00:00
Ayman A. 7010e26890 fix(explore): require explicit confirmation before writing files (#1716)
* fix(explore): require explicit confirmation before writing files

* test(explore): harden write confirmation guardrail

* fix(explore): scope write confirmation precisely

---------

Co-authored-by: Clay Good <hi@claygood.com>
2026-08-26 19:24:57 +00:00
dependabot[bot] 6926ccb18a chore(deps): bump the website-dependencies group (#1719)
Bumps the website-dependencies group in /website with 2 updates: [fumadocs-core](https://github.com/fuma-nama/fumadocs) and [fumadocs-ui](https://github.com/fuma-nama/fumadocs).


Updates `fumadocs-core` from 16.14.4 to 16.14.5
- [Release notes](https://github.com/fuma-nama/fumadocs/releases)
- [Commits](https://github.com/fuma-nama/fumadocs/compare/fumadocs@16.14.4...fumadocs@16.14.5)

Updates `fumadocs-ui` from 16.14.4 to 16.14.5
- [Release notes](https://github.com/fuma-nama/fumadocs/releases)
- [Commits](https://github.com/fuma-nama/fumadocs/compare/fumadocs@16.14.4...fumadocs@16.14.5)

---
updated-dependencies:
- dependency-name: fumadocs-core
  dependency-version: 16.14.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: website-dependencies
- dependency-name: fumadocs-ui
  dependency-version: 16.14.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: website-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-24 14:00:04 +00:00
Tabish Bidiwale f1b521dffa docs: rebuild docs site from docs-lab (#1649)
* docs: rebuild docs site from docs-lab

Replace the docs site's source tree with docs-lab, a page-by-page rebuild
of the OpenSpec docs (40 pages: Start / Guides / Customize / Multi-repo /
Reference / Help).

- Point website/docs.sync.config.mjs at ../docs-lab and restructure the
  sidebar into nested groups; sync script gains nested meta.json emission,
  leading-quote descriptions, idempotent writes, and diagram asset copying
- Remove the marketing landing page; / now redirects to /docs
  (meta-refresh page + Cloudflare _redirects)
- Add remark plugins (faq, file-steps, gfm-alert) and the FileSteps
  component backing the new page formats
- Add install.md at the repo root, curled by docs-lab/start/installation.md
  as an agent-executable install prompt
- Add the docs authoring skills (.agents/skills/{write,draft,verify}-
  openspec-docs); docs-lab/README.md links into write-openspec-docs

The old docs/ tree is now unused by the site and left for a follow-up.

Claude-Session: https://claude.ai/code/session_01BMMLYNJQPKXx1QHpnDn4ho

* docs: hold back unwritten pages, add worksets, drop diagram drafts

- website: comment out Overview, Guides, Architecture, Help, Legacy in
  docs.sync.config.mjs until those pages are written; temporary
  /docs -> /docs/installation redirect (Cloudflare _redirects + static
  export meta-refresh fallback in page.tsx)
- docs-lab: new multi-repo/worksets.md page, published under Multi-repo
- docs-lab: content revisions across start/, customize/, reference/,
  help/, multi-repo/; add review notes (Notes.md)
- remove docs-lab/diagrams option-* drafts and their website copies
- write-openspec-docs skill: add spoken-flow sentence rule

* docs: address review on PR #1649

- sync-docs: read the existing output directly instead of exists-then-read
  (CodeQL TOCTOU alert)
- hold back the headings-only Environment variables and Stores reference
  pages until written; links to them fall back to their GitHub source
- sources.md: cutover keeps docs/ in place and points at public/_redirects
- setup.md: label the workflow tree as the default set plus two optional ones

* docs: two review nits (spoken-flow rule, XDG_DATA_HOME note)
2026-08-21 20:45:19 +00:00
openspec-release-bot[bot] 1ebddd17f4 Version Packages (#1705)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
v1.10.0
2026-08-19 22:23:30 +00:00
Clay Good 7da3f34fb6 fix(tasks): include verification in generated plans (#1660)
* fix(tasks): include verification in generated plans

* test(tasks): enforce inline verification guidance

* fix(tasks): harden verification guidance

* test(tasks): verify every onboarding checkbox
2026-08-19 21:07:20 +00:00