Primitiv

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 contractprimitiv.contract.json is older than its sources (exit 3)
  • 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 verify

Reading the output

A typical failure looks like this:

$ primitiv verify

✖ 2 unresolved conflicts
  • color.primary — figma vs codebase
  • spacing.md   — storybook vs codebase

Exit 2

Each 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.js under governance, or
  • Changing sourceOfTruth if the underlying decision has shifted.

When you want build vs verify

  • build writes the contract. Run locally while authoring; run in CI on main after merge.
  • verify only 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.

On this page