Spec-driven development on OpenSpec, with mechanical spec-as-source enforcement: a custom 'spec-as-source' OpenSpec schema adds file-ownership (targets) and test-verification ([@test]) metadata to every capability spec, three scripts (link check, ownership check, manifest build) keep code and specs from drifting apart, plus requirement-gathering, spec-writer, work-review, and a session-handoff skill with a proactive context-warning hook.
71
89%
Does it follow best practices?
Impact
—
No eval scenarios have been run
Advisory
Suggest reviewing before use
Run the full spec verification suite in this order. The only exception to running all steps: if Step 1 fails, stop and report — do not run Steps 2–5.
Run:
bash scripts/check-spec-links.shThis checks that every [@test] annotation in every openspec/specs/**/spec.md points to a file that actually exists on disk.
If scripts/check-spec-links.sh is missing or cannot run, do not give up — reproduce the check directly: read every openspec/specs/**/spec.md, extract each [@test] path, resolve it relative to the project root, and test whether that file exists. The result is the same; the script is just a convenience.
[@test] path that does not exist, and why this is critical (no verifier = worse than a failing test). Tell the user to fix it by either creating the missing file at the expected path or correcting the [@test] annotation in the spec to point to an existing file, then re-run spec-verify. Record all of this in the report file described under Reporting — do not leave the findings only in chat.Run:
bash scripts/check-target-ownership.shThis checks that no file declared as a targets in a spec has been modified without a corresponding update to its owning spec.
Run:
python3 scripts/build-spec-manifest.pyThis writes .spec-source-manifest.json — a machine-readable map of specs → requirements → targets → tests.
Run the project test suite. Detect the test runner automatically:
pytest.ini, pyproject.toml, or setup.cfg exists → pytest tests/ -vpackage.json with a test script exists → npm testCargo.toml exists → cargo testSteps 1–4 are mechanical: they catch broken links, unauthorized target changes, and unparsable specs — but they cannot tell whether a target file actually still does what its spec says. This step is the qualitative complement: read the code, not just the metadata.
For each capability spec touched by the current change (or, for a periodic/full audit, every spec under openspec/specs/):
targets: file and every ### Requirement: block side by side. For each requirement, confirm the target file(s) actually implement it — not just that a [@test] link exists.targets: or [@test] path that points to a file that was renamed or moved (Step 1/2 already catch outright-missing files; this step catches the case where a different but related file silently took over the responsibility without the spec being updated to point at it).When drift is found, fix it — don't just report it:
spec-writer) to match current behavior, then re-run Steps 1–3.targets:/[@test] in the spec to the new path, then re-run Steps 1–3.After fixes, re-run Steps 1–3 (and Step 4 if code changed) before considering this step passed.
After completing the run (whether it finished all five steps or stopped early at Step 1), always produce this summary with actual results filled in — write it to .spec-verify-report.md in the project root and print it to chat. The on-disk report is the durable, CI-uploadable record; the chat copy is the in-session view. A check that was skipped because an earlier one failed is reported as SKIPPED (Step 1 failed), never as PASSED.
spec-verify results
───────────────────
check-spec-links: PASSED / FAILED / SKIPPED
check-target-ownership: PASSED / FAILED / SKIPPED
build-spec-manifest: PASSED / FAILED / SKIPPED
test suite: PASSED / FAILED / SKIPPED (N tests)
semantic drift: PASSED / FAILED / SKIPPED (N capabilities checked)
Overall: PASSED / FAILEDWhen a check FAILED, append a Findings section to the report naming exactly what broke. For a check-spec-links failure this means, for each broken annotation: the spec file (e.g. openspec/specs/auth/spec.md), the missing [@test] path (e.g. tests/auth/test_login.py), the impact (a missing [@test] leaves the requirement with no verifier — worse than a failing test), and the fix (create the missing file, or correct the [@test] path in the spec). For a semantic drift failure, name the capability, the requirement, what the spec says vs. what the code does, and which side was fixed (spec or code). Then re-run spec-verify.
When all five steps pass, the last line must read exactly: Overall: PASSED
If anything failed: stop. Do not proceed to the next task, do not declare implementation complete, do not say "you can now merge". The only valid next action is fixing what failed and re-running spec-verify.
.tessl-plugin
skills
handoff
openspec-apply-change
openspec-archive-change
openspec-explore
openspec-propose
openspec-sync-specs
requirement-gathering
spec-as-source-setup
templates
openspec-schema
spec-as-source
templates
spec-ci-sync
spec-rebuild
spec-verify
spec-writer
work-review