CtrlK
BlogDocsLog inGet started
Tessl Logo

spec-driven-devlopment/spec-as-source

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

Quality

89%

Does it follow best practices?

Impact

No eval scenarios have been run

SecuritybySnyk

Advisory

Suggest reviewing before use

Overview
Quality
Evals
Security
Files

SKILL.mdskills/spec-verify/

name:
spec-verify
description:
Runs all spec consistency checks (link integrity, target ownership, manifest build), the test suite, and a semantic drift spot-check, then reports results. Trigger — verify specs, spec check, run spec suite, check spec consistency, validate spec links, spec integrity, spec drift.

Spec Verify

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.

Step 1 — Check spec test links

Run:

bash scripts/check-spec-links.sh

This 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.

  • Exits zero (all links resolve) → continue to Step 2.
  • Exits non-zero (broken links found) → stop here, skip Steps 2–5. For each failing annotation report: the spec file that contains it, the [@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.

Step 2 — Check target ownership

Run:

bash scripts/check-target-ownership.sh

This checks that no file declared as a targets in a spec has been modified without a corresponding update to its owning spec.

Step 3 — Build spec manifest

Run:

python3 scripts/build-spec-manifest.py

This writes .spec-source-manifest.json — a machine-readable map of specs → requirements → targets → tests.

Step 4 — Run the test suite

Run the project test suite. Detect the test runner automatically:

  • If pytest.ini, pyproject.toml, or setup.cfg exists → pytest tests/ -v
  • If package.json with a test script exists → npm test
  • If Cargo.toml exists → cargo test
  • If unsure, ask the user which command to run before proceeding.

Step 5 — Semantic drift spot-check

Steps 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/):

  1. Read every 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.
  2. Look for contradictions: logic in a target file that handles an edge case, error, or data contract differently from what the spec describes.
  3. Look for undocumented behavior: functions, branches, parameters, or events in a target file that aren't mentioned in any requirement of its owning spec.
  4. Look for stale links: a 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:

  • If the code is right and the spec is stale → update the spec (use spec-writer) to match current behavior, then re-run Steps 1–3.
  • If the spec is right and the code drifted → flag it as a Step 4-equivalent failure: the implementation needs to be brought back in line with the spec.
  • If a path is stale (renamed/moved file) → update 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.

Reporting

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 / FAILED

When 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.

skills

spec-verify

README.md

tile.json