OpenSpec projects
Run an OpenSpec change task by task under the same judge: scenarios become failing tests, ticks need evidence, broken deltas are caught before any model call, and archiving stays yours.
speccoder runs OpenSpec changes under the same judge as Spec Kit features. What differs:
| Spec Kit | OpenSpec | |
|---|---|---|
| Unit of work | a feature, specs/NNN-name/ | a change, openspec/changes/<id>/ |
| Acceptance examples | the task’s user story | the #### Scenario: blocks of ADDED and MODIFIED requirements |
| Task IDs | T001 | the number the task starts with (1.2), else #n |
| Order | phases, [P] runs, depends on | a chain: groups in order, tasks in order |
| Intent the model cannot edit | .specify/, specs/ | all of openspec/ |
Supported: OpenSpec 1.0 and newer, the default spec-driven schema, in the repository’s own openspec/ directory.
Running a change
speccoder inspect # the change, its requirements and its tasks
speccoder run # work the change through, task by task
speccoder run --change add-x # when more than one change is active
speccoder run --task 1.2 # one taskThe format is detected: the nearest openspec/ (with config.yaml, specs/ or changes/) or .specify/ decides. When a directory has both, choose with --format openspec, SPECCODER_FORMAT or [spec] format. --change is an alias of --feature.
Commit the change’s files before a run; the work happens on speccoder/<change-id>. A task ticked before speccoder ran it is reported as ticked without evidence. Each attempt sees config.yaml’s context (as the project’s rules), proposal.md and design.md (as the plan), and every delta of the change in full. OpenSpec does not link a task to a requirement, so acceptance tests come from the change’s scenarios that the task concerns. The archive is never shown.
Caught before any model call
openspec validate --strict accepts some deltas that openspec archive later refuses, so speccoder refuses to run while any of these hold:
| Code | Meaning |
|---|---|
missing_target | a MODIFIED, REMOVED or RENAMED requirement does not exist in openspec/specs/<capability>/spec.md |
renamed_conflict | a requirement is modified under the name this change renames |
missing_scenario | an ADDED or MODIFIED requirement has no #### Scenario: |
scenario_wrong_level | ### Scenario: instead of #### Scenario: (OpenSpec ignores it) |
no_deltas | the change has no spec delta: nothing to derive tests from |
unsupported_schema, store_root, legacy_root | a custom schema, a shared store, or the pre-1.0 layout |
textless, duplicate_id, no_tasks | tasks.md cannot be run as written |
config_unreadable | openspec/config.yaml is not valid YAML |
Warnings do not stop a run:
| Code | Meaning |
|---|---|
removed_without_reason | a REMOVED requirement has no Reason or Migration |
purpose_missing | archive would write a TBD placeholder for the purpose |
marker_not_space, empty_brackets | [~] or []: speccoder cannot tick it |
misplaced_id | a task’s number does not match its group (3.1 under ## 2.) |
in_fence | a checkbox inside a code block, which OpenSpec counts as a task |
unnumbered_section | a group heading without a number; its tasks run after everything before them |
extension_dependency | depends on 1.2 is speccoder’s extension; OpenSpec ignores it |
When openspec is on your PATH, speccoder run also runs openspec validate --strict --json and openspec instructions apply --json (read-only, sandboxed, telemetry off). Its validation errors (crosscheck_error) and a different task count (crosscheck_mismatch) stop the run. Without openspec, this cross-check is skipped.
What the model may run
openspec … (also via npx) | in an attempt | in a hosted planning skill |
|---|---|---|
list, show, view, status, instructions, validate, schemas, templates, context, --version, --help | allowed | allowed |
new change | refused | allowed |
archive, sync, init, update, config, store, schema | refused | refused |
Every command in an OpenSpec project runs with OPENSPEC_TELEMETRY=0, DO_NOT_TRACK=1 and OPENSPEC_NO_UPDATE_CHECK=1. Writes under openspec/ are refused during implementation; a command that changes them fails the verdict. OpenSpec’s per-tool commands and skills (.claude/commands/opsx/, .claude/skills/openspec-*/, …) are agent configuration, protected like any other.
Planning
speccoder spec # OpenSpec's installed skills
speccoder spec propose "add a --bye flag"
speccoder spec explore
speccoder spec update-changeOpenSpec’s own skills, run by speccoder’s model under the planning policy: they may write active changes (openspec/changes/, never the archive) and run openspec new change and the read commands. Not hosted: apply-change (use speccoder run), sync-specs and archive-change (merging into the main specs is yours: speccoder spec archive).
Archiving
Archiving rewrites the main specs, so you do it:
speccoder spec archive add-x- It needs
openspecon your PATH and no uncommitted changes underopenspec/. - A task ticked without a speccoder verdict commit stops it, named. Run it, accept it with
speccoder task accept, or name it with--allow-unverified 1.1(recorded asArchived-Unverified:on the commit). - It asks OpenSpec first without
--yes— OpenSpec’s--yesalso skips its check for open tasks — and stops if tasks are open. - It shows
openspec show <id> --diffand asks.--yesanswers in advance; without a terminal and without--yesit stops with the command to run. - On yes:
openspec archive <id> --yes, then one commitarchive <id>withArchived-By:andSpeccoder-Archive:trailers.
Run it in your checkout, typically after merging speccoder/<id>.
Not supported
Shared stores, custom schemas, parallel tasks (a change is a chain), and absence checks for REMOVED requirements.