Drive an implementation
These specs are packaged for consumption — an implementation proves it satisfies them; it never redefines them. Agents do the building; the specs supply their context and their gates. The same loop applies to every service; each service overview carries its own current pin.
The loop below is carried end-to-end by the implement-service skill (and consume-servicefor UIs and clients building against the mocks). Install the plugin — /plugin marketplace add hungovercoders/sysspec, then /plugin install — and ask to implement a service; the skill runs everything on this page, from interview to verified definition of done. What follows is the shape of that loop, so you can recognise it, review it, or run it by hand.
flowchart TD tag["spec repo: merge to main cuts service/vX.Y.Z"] lock["contracts.lock pins the tag + its commit sha"] fetch["task contracts:fetch - read-only .contracts/ (specs + mocks + kit)"] build["build: bind the feature files, strict"] verify["task contracts:verify - contract tests, bound scenarios, negative control, schema fuzz"] done(["implementation satisfies the pinned surface"]) tag -->|"pin the newest tag"| lock lock --> fetch --> build --> verify verify -->|green| done verify -->|red| build tag -.->|"each new tag: Renovate re-pins"| lock
1. Pin the released surface
A merge to the spec repo's main publishes each changed service as a lightweight git tag <service>/v<version>. The implementation records which surface it satisfies in a contracts.lock at its root:
# contract pin - version is the specs release tag, sha its commit
version: <service>/v<version>
sha: <commit sha of that tag>2. Fetch read-only, never vendor
A contracts:fetch task sparse-checks-out specs/<service> — plus the spec repo's mocks/ and kit/, so the whole toolchain is versioned by the pin — at the pinned sha into a write-protected .contracts/ directory. Every run re-fetches, so a local edit cannot survive — and the sha, not the tag, is what gets checked out, so a re-cut tag cannot silently change what you build against. The Microcks mock stack then runs straight from the pin: task -d .contracts mocks:load, nothing copied or installed.
3. Build with the specs in context, over MCP
The agent implementing the service reads these specs as it works — never from a remembered or vendored copy. Interactive sessions use the sysspec MCP server:
claude mcp add sysspec --scope project \
--env SPECS_DIR=/path/to/checkout/specs \
-- uvx --from sysspec sysspec-mcpThen list_services() → get_service(name) → narrow reads (get_acceptance_criteria, get_message_schema, get_artifact); trace_channel(address) shows who a change would break. CI and anything needing reproducible file paths read the same surface from .contracts/ — one source, two access routes. The implement-service and consume-service skills (hungovercoders/sysspec) carry the deeper process the agent follows — written to be read as documentation and executed as agent process.
4. Bind the acceptance criteria, strict
The feature files run from .contracts/ as-is — the specs own the sentences, the implementation owns the step definitions. Strict mode is mandatory: an unbound or pending scenario fails the build, because an unbound scenario is a spec obligation silently dropped. Strict mode has one blind spot — a bound-but-empty step passes — which is exactly what the negative control in the next section exists to catch.
5. Verify — the definition of done
One task, contracts:verify, run with the implementation up. It chains four checks:
- Contract tests —
task -d .contracts contract:test SERVICE=<name> REST_ENDPOINT=… ASYNC_ENDPOINT=…— Microcks replays every spec operation against the running implementation and validates the real responses and emitted events against the schemas. - The bound scenario suite against the running implementation.
- The negative control —
task -d .contracts null:run …replays the same suite against a null service the kit serves, answering200 {}to every request and emitting no events; red unless zero scenarios pass. Strict mode catches unbound steps, this catches bound-but-empty ones: a suite is only trustworthy if it is fully red against a service that does nothing. The fake answer is deliberately a plausible 200 rather than an error, so scenarios that assert nothing beyond a status code get flagged too. - Schema fuzz —
uvx schemathesis run .contracts/specs/<name>/openapi/*.yaml --url …for declared-but-unexampled paths.
One trap worth knowing: the endpoint overrides in check 1 resolve frominside the Microcks containers, so an implementation on your host is host.docker.internal, never localhost— while checks 2 and 3 run on the host and use the local URL. Two views of the same running service.
These gates are deterministic and live with the specs, not the implementation — they cannot be softened to make failing code pass. Mocking is deliberately not on this page: the mocks:*tasks serve consumers and the spec repo's own conformance checks, and have their own loop — see Build a consumer.
6. Stay converged
The specs never push work at implementations; they pull. When a new release tag lands, Renovate opens a pin-bump PR on the implementation and the gates above run against the new surface. Green — typical for additive minors — auto-merges with no human and no agent. Red, or a major bump, means the gates have proven code changes are needed — and only then does an agent wake to converge the implementation, with the failing checks as its scope.