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.
68
85%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Set up mechanical spec-as-source enforcement on top of OpenSpec's spec-driven workflow,
using a custom spec-as-source OpenSpec schema that extends spec.md with
file-ownership (targets:) and test-verification ([@test]) metadata.
Execute every step in order. Create each file by copying the corresponding template from this skill's templates/ directory verbatim, unless a step says to adapt something.
Prerequisites: the openspec CLI installed and on PATH. Git repo initialized.
Run openspec --version. If the command is not found, install it:
npm install -g @fission-ai/openspec(or add it as a local devDependency with npm install -D @fission-ai/openspec and prefix subsequent openspec calls with npx.)
If openspec/config.yaml does not already exist, run openspec init and follow its prompts (or pass --tools claude non-interactively if running headless). Accept the default spec-driven schema for now — Step 1 replaces it with spec-as-source.
spec-as-source OpenSpec schemaCopy this skill's templates/openspec-schema/spec-as-source/ directory verbatim to the project's openspec/schemas/spec-as-source/ directory:
mkdir -p openspec/schemas
cp -r <skill-dir>/templates/openspec-schema/spec-as-source openspec/schemas/spec-as-sourceValidate the copied schema:
openspec schema validate spec-as-sourceSet it as the project's active schema by editing openspec/config.yaml: add or update the top-level schema: field to schema: spec-as-source. If openspec/config.yaml does not exist yet, create it with exactly that one line.
Confirm resolution:
openspec schema which spec-as-sourceIt should report Source: project.
scripts/check-spec-links.shCreate the scripts/ directory if it does not exist.
Copy templates/check-spec-links.sh to scripts/check-spec-links.sh, then make it executable:
chmod +x scripts/check-spec-links.shWhat it does: verifies that every [@test] annotation in every openspec/specs/**/spec.md points to a file that actually exists on disk. A missing test file is worse than a failing test: the requirement has no verifier.
scripts/check-target-ownership.shCopy templates/check-target-ownership.sh to scripts/check-target-ownership.sh, then make it executable:
chmod +x scripts/check-target-ownership.shWhat it does: detects whether any file declared as a targets entry in a capability spec has been modified without a corresponding update to its owning spec. This is the core spec-as-source guard.
scripts/build-spec-manifest.pyCopy templates/build-spec-manifest.py to scripts/build-spec-manifest.py. No chmod needed — it is a Python script called directly.
What it does: reads all openspec/specs/**/spec.md files and writes .spec-source-manifest.json — a machine-readable map of specs → requirements → targets → tests.
scripts/verify.shCopy templates/verify.sh to scripts/verify.sh.
What it does: orchestrates steps 2–4 in sequence, then auto-detects and runs the project test suite (pytest / npm test / cargo test).
Now make every shell script executable in one step and verify the bits actually stuck — the executable bit is a separate operation that file-write tools do not set, so a freshly written .sh is 644 until you chmod it:
chmod +x scripts/check-spec-links.sh scripts/check-target-ownership.sh scripts/verify.sh
ls -l scripts/Every .sh in the listing must show x in its permissions (e.g. -rwxr-xr-x). If any does not, re-run the chmod. Without the executable bit the scripts are useless to pre-commit and CI. (build-spec-manifest.py needs no +x — it is called as python3 scripts/build-spec-manifest.py.)
Copy templates/check-plan-gate.sh to scripts/check-plan-gate.sh in the
target project and make it executable:
mkdir -p scripts
cp <skill-dir>/templates/check-plan-gate.sh scripts/check-plan-gate.sh
chmod +x scripts/check-plan-gate.sh
test -x scripts/check-plan-gate.sh
if grep -Eq '^# Source: openspec/specs/.*/spec\\.md' scripts/check-plan-gate.sh; then
echo "ERROR: installed gate references a capability spec absent from the target" >&2
exit 1
fiThe template is target-safe: its provenance must not point at a capability spec
that setup did not install. Do not create openspec/PLAN.md, add an approval
block, or modify an existing plan in this step; those actions belong to
plan-mode.
If scripts/check-plan-gate.sh already exists, stop before copying and report
the named conflict to the human. Ask whether to keep the existing file or
replace it. keep leaves its bytes and permissions unchanged. Only an
explicit replace decision permits copying the template, after which setup
must run chmod +x and test -x again. Never merge or silently overwrite a
customized gate.
.pre-commit-config.yamlCopy templates/pre-commit-config.yaml to .pre-commit-config.yaml in the project root. No adaptation needed.
.github/workflows/spec-verification.ymlCreate .github/workflows/ if it does not exist.
Copy templates/spec-verification.yml to .github/workflows/spec-verification.yml.
Auto-detect the test runner — do not block the rest of setup waiting for an answer. The CI file must exist on disk before you move on. First match wins:
pytest.ini / setup.cfg / pyproject.toml [tool.pytest] → pytestpackage.json with a test script → npm (jest/vitest if in devDependencies)Cargo.toml → cargogo.mod → goThen replace the # ADAPT: install and run tests here placeholder with the install + test steps for the detected runner (never leave the placeholder in the final file):
| Runner | steps to insert |
|---|---|
| pytest | - uses: actions/setup-python@v5 with: { python-version: "3.11" } - run: pip install -r requirements.txt - run: pytest -v |
| npm | - uses: actions/setup-node@v4 with: { node-version: "20" } - run: npm ci - run: npm test |
| cargo | - run: cargo test |
| go | - run: go test ./... |
After writing the file, surface the runner as a non-blocking confirmation (state it, then keep going — do not wait):
"I detected and configured the CI workflow accordingly. If this project uses a different runner, tell me and I'll re-sync it with spec-ci-sync."
Continue to Step 8 immediately.
After creating all files, write this checklist to SPEC_SETUP.md in the project root and print it verbatim, so the user has both a durable record and the in-session reminder:
Setup complete. Remaining steps:
1. Enable pre-commit locally:
pip install pre-commit && pre-commit install
2. On GitHub → Settings → Branches → Add rule for "main":
✓ Require status checks to pass before merging
✓ Require branches to be up to date before merging
✓ Status check: "Run spec verification"
3. Start your first change with openspec-propose (or openspec-explore), then
openspec-apply-change to implement it, then spec-verify to check it.Run verification automatically by invoking spec-verify (it runs the three spec checks plus the test suite and writes .spec-verify-report.md). This both proves the freshly installed scripts work and leaves a baseline report. Do not end the setup before this runs.
spec-as-source — built by Giuseppe Di Canosa.
.tessl-plugin
rules
skills
handoff
handoff-skill
openspec-apply-change
openspec-archive-change
openspec-explore
openspec-propose
openspec-sync-specs
plan-judge
plan-mode
prompt-loop
requirement-gathering
spec-as-source-setup
templates
openspec-schema
spec-as-source
templates
spec-ci-sync
spec-loop
spec-rebuild
spec-verify
spec-writer
work-review