Primitiv

Configuration

Configure sources, governance, and output.

primitiv.config.js

// primitiv.config.js
module.exports = {
  sources: {
    codebase: {
      root: "./src",
      patterns: ["**/*.css", "**/*.ts", "**/*.tsx"],
      ignore: ["node_modules", "dist", ".next"]
    },
    // figma: {
    //   token: process.env.FIGMA_ACCESS_TOKEN,
    //   fileId: "your-figma-file-id"
    //   // optional: false, // fail the build when this source can't be scanned
    // },
    // storybook: {
    //   url: "http://localhost:6006"
    // }
  },
  governance: {
    sourceOfTruth: "codebase", // "codebase" | "figma" | "storybook" | "manual"
    // "warn":         record conflicts as pending; build succeeds (default)
    // "error":        write the contract, then fail the build (exit 2) while conflicts are pending
    // "auto-resolve": conflicts the sourceOfTruth decides are marked resolved; standoffs stay pending
    onConflict: "warn"
  },
  output: {
    path: "./primitiv.contract.json"
  }
}

Sources

Configure which design sources Primitiv scans. Each source uses an adapter:

  • codebase — scans CSS variables, TypeScript tokens, and React components from your filesystem
  • figma — connects to Figma via the Variables API (requires access token and file ID)
  • storybook — scans components and variants via the Storybook manifest

optional

Remote sources (figma, storybook) are optional by default: if one can't be scanned, the build warns, records the failure, and continues. Set optional: false on a source to make its failure hard-fail the build (exit 1, no contract written). Your governance.sourceOfTruth is always treated as required regardless of this flag — see Failed sources.

Governance

Controls how Primitiv handles conflicts between sources:

  • sourceOfTruth — which source wins when sources disagree ("codebase", "figma", "storybook", or "manual")
  • onConflict — what to do when a conflict is detected:
    • "warn" (default) — record conflicts as pending; the build still succeeds
    • "error" — write the contract, then fail the build (exit 2) while conflicts remain pending
    • "auto-resolve" — conflicts the sourceOfTruth decides are marked resolved; genuine standoffs (no source-of-truth winner) stay pending

Same-source conflicts are never auto-resolved. When one source defines a token twice with two different values, a source can't arbitrate itself, so the conflict stays pending under every onConflict value until a human removes one definition. See Redefinition conflicts.

Failed sources

Every build records a sourceStatuses field on the contract — ok (with token/component counts), failed (with a sanitized error), or skipped (not configured) per source — so consumers can distinguish "not configured" from "configured but failed."

When a remote source (Figma, Storybook) is unreachable, the build warns, records the failure, and continues; verify skips drift reporting for that source's entries instead of reporting them all as removed. The one exception: if the failed source is your governance.sourceOfTruth (or is marked optional: false), the build hard-fails and writes nothing — running conflict resolution without its authority would be worse than no contract.

Output

  • path — where to write the resolved contract file (default: ./primitiv.contract.json)

On this page