Verify in CI
Gate the build on unresolved conflicts and stale contracts.
primitiv verify re-runs the build and exits non-zero when the contract is stale or has unresolved conflicts. Run it in CI to catch drift before it ships.
What it checks
- Unresolved conflicts — a source disagrees with the source-of-truth and no rule handles it (exit
2) - Stale contract —
primitiv.contract.jsonis older than its sources (exit3) - Build failures — config errors, unreadable sources (exit
1)
GitHub Actions
# .github/workflows/design-contract.yml
name: Design contract
on:
pull_request:
paths:
- "src/**"
- "primitiv.config.js"
- "primitiv.rationale.yml"
- "tokens/**"
jobs:
verify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- run: npx @ai-by-design/primitiv verifyReading the output
A typical failure looks like this:
$ primitiv verify
✖ 2 unresolved conflicts
• color.primary — figma vs codebase
• spacing.md — storybook vs codebase
Exit 2Each conflict points to the two sources that disagree. Resolve by either:
- Updating the losing source to match the source-of-truth, or
- Adding an explicit rule in
primitiv.config.jsundergovernance, or - Changing
sourceOfTruthif the underlying decision has shifted.
When you want build vs verify
buildwrites the contract. Run locally while authoring; run in CI onmainafter merge.verifyonly exits with a status. Run in CI on every PR — it does not write the contract, so it won't leave drift behind.
Treating verify as a required status check is the cleanest way to keep the contract honest.