AI-by-design/primitiv
your code never leaves your machine.
Ask AI about AI-by-design/primitiv
Powered by Claude Β· Grounded in docs
I know everything about AI-by-design/primitiv. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
Primitiv
The design contract layer for your agents.
Retrieval gives you data. Reconciliation gives you truth.
Primitiv sits above your design sources β Figma, codebase, Storybook, token files β scans them, reconciles conflicts between them, and exposes a single machine-readable contract via MCP. Any agent that connects gets one authoritative answer before it builds. Your code never leaves your machine.
Quick start
npx @ai-by-design/primitiv init # detect your stack, write config + MCP registration
npx @ai-by-design/primitiv build # scan sources, resolve conflicts, write the contract
npx @ai-by-design/primitiv serve # start the MCP server
init writes a .mcp.json to your project root, so Cursor, Claude Code, Codex, Windsurf, and any other MCP-compatible tool pick up the server without manual config.
If your project is on GitHub, init also installs .github/workflows/primitiv-verify.yml β a workflow that runs primitiv verify on every PR and push. Pair it with branch protection on your default branch and the merge is blocked when an agent ships UI that breaks the contract.
From here, every agent that builds UI calls get_design_context first and gets your resolved design contract back.
The problem
Design-relevant information is spread across Figma, tokens, Storybook, and the codebase itself β sources that were never meant to stay in sync. Humans reconcile the drift by inference; agents can't, so they fall back on training-data patterns and build UI that works but doesn't fit.
Primitiv resolves it: one contract, built from every source, served live to every agent.
How it works
Any source Primitiv Your agent
Figma βββ
Codebase βββ€βββΊ scan βββΊ reconcile βββΊ contract βββΊ MCP βββΊ Cursor / Claude Code / Codex / Windsurf / any MCP-compatible tool
Storybook βββ€
Tokens file βββ€
Any adapter βββ
- Scan β Primitiv ingests from any configured source via adapters
- Reconcile β Conflicts between sources are surfaced and resolved according to your governance configuration
- Infer β Design rules are extracted from actual codebase patterns and written into the contract
- Contract β A single
primitiv.contract.jsonis written as the canonical reference - MCP β Agents call
get_design_contextbefore building and receive the resolved contract
Install
npm install @ai-by-design/primitiv
# or
bun add @ai-by-design/primitiv
CLI
| Command | Description |
|---|---|
primitiv init [dir] | Detect your project and generate primitiv.config.js |
primitiv build [config] | Scan sources, resolve conflicts, write the contract |
primitiv serve [config] | Start the MCP server |
MCP tools
| Tool | Description |
|---|---|
get_design_context | Get all tokens, components, conflicts, and inferred rules. Pass category: "all" to get everything. |
get_token | Look up a specific token by name |
get_component | Look up a specific component and its props |
get_conflicts | Get unresolved conflicts between sources |
get_inferred_rules | Get the design rules Primitiv has extracted from your codebase patterns |
Primitiv works with any tool that speaks MCP β it is not tied to a specific editor or agent ecosystem.
Using Primitiv across multiple projects
Primitiv runs one MCP server process per project, each pointed at that project's contract. This is intentional β each project has its own resolved contract, and there is no global shared state.
primitiv init writes a project-scoped MCP config automatically. Do not add Primitiv to your editor's global MCP config β if you do, the global server will keep serving one project's contract regardless of which project your agent is working in.
Per-editor setup
| Editor | Project-level config | Global config (avoid for Primitiv) |
|---|---|---|
| Claude Code | .mcp.json at repo root β
| ~/.claude/settings.json |
| Cursor | .cursor/mcp.json at repo root β
| ~/.cursor/mcp.json |
| Windsurf | .windsurf/mcp_config.json at repo root β
| ~/.codeium/windsurf/mcp_config.json |
| Zed | .zed/settings.json at repo root β
| ~/.config/zed/settings.json |
primitiv init detects which editor config exists and writes to the right project-level file. If none exists, it creates .mcp.json (works with Claude Code and most modern editors).
Switching between projects
Each project needs its own primitiv init + primitiv build. When you switch projects in your editor, the project-scoped MCP config is loaded automatically β no manual switching needed, as long as you haven't added Primitiv to the global config.
If you already added Primitiv to your global editor config, remove it:
# Cursor β edit ~/.cursor/mcp.json and remove the "primitiv" entry
# Windsurf β edit ~/.codeium/windsurf/mcp_config.json and remove "primitiv"
Stale or mismatched contract warnings
If get_design_context returns a warnings array, stop and resolve before proceeding:
STALE CONTRACTβ the contract is outdated. The warning includes the exact command to rebuild, e.g.:npx @ai-by-design/primitiv build /path/to/your/primitiv.config.jsCONTRACT MISMATCHβ the server is serving a contract from a different project. This usually means Primitiv is in your global editor MCP config. Remove it from there and re-runprimitiv initin the correct project.
CI / GitHub Actions
primitiv init auto-installs .github/workflows/primitiv-verify.yml when the project's remote is on GitHub. The workflow runs on every pull request and push to your default branch and fails the check when the contract is stale or has unresolved conflicts.
To turn the failed check into a hard merge gate, enable branch protection on the default branch β init prints the exact settings URL after install (https://github.com/<owner>/<repo>/settings/branches).
The workflow uses npx --yes @ai-by-design/primitiv verify, so it works regardless of your project's package manager. Two notes:
- Monorepos β the workflow runs at repo root. If
primitiv.config.jslives in a subdirectory, add aworking-directory:to the verify step in the generated YAML. - Pinning β
npx --yes @ai-by-design/primitivfetches the latest version. To pin, edit the workflow'srun:line tonpx --yes @ai-by-design/primitiv@1.4.0 verify(or your chosen version).
The workflow is idempotent β re-running primitiv init refreshes the block between # <!-- primitiv --> markers, preserving any content you've added outside them.
Configuration
// 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"
// },
// storybook: {
// url: "http://localhost:6006"
// }
},
governance: {
sourceOfTruth: "codebase", // "codebase" | "figma" | "storybook" | "manual"
onConflict: "warn" // "error" | "warn" | "auto-resolve"
},
output: {
path: "./primitiv.contract.json"
}
}
Contributing
Local setup
git clone https://github.com/AI-by-design/primitiv.git
cd primitiv
bun install
bun run build
Running in development
To run the MCP server against local source without a build step, point your MCP config directly at the source file. Bun runs TypeScript directly so changes are picked up on the next server restart:
{
"mcpServers": {
"primitiv": {
"command": "bun",
"args": ["/path/to/primitiv/src/cli.ts", "serve", "./primitiv.config.js"]
}
}
}
The MCP server also hot-reloads primitiv.contract.json automatically whenever primitiv build runs.
Build commands
bun run build # Compile TypeScript β dist/
bun run dev # Run src/index.ts directly via ts-node
bun run lint # ESLint on src/**/*.ts
Architecture
src/
βββ cli.ts Entry point β routes init / build / serve
βββ index.ts Exports build() and serve()
βββ types.ts All shared interfaces β define types here, not inline
βββ scanner/ CodebaseScanner β extracts tokens and components from the filesystem
βββ sources/ Source adapters β Figma (Variables API), Storybook (manifest)
βββ contract/ ContractBuilder β merges sources, detects conflicts, applies governance
βββ inferrer/ inferRules() β derives design rules from token and component patterns
βββ mcp/ PrimitivMCPServer β loads the contract and registers MCP tools
βββ init/ init() β detects framework and writes primitiv.config.js
See CLAUDE.md for conventions on adding new sources, MCP tools, and types.
Releases
Releases are managed by Release Please. Commit messages must follow the Conventional Commits format:
| Prefix | Effect |
|---|---|
fix: ... | Patch release (0.1.0 β 0.1.1) |
feat: ... | Minor release (0.1.0 β 0.2.0) |
feat!: ... or BREAKING CHANGE: | Major release |
chore:, docs:, refactor: | No release |
On merge to main, Release Please opens a release PR. Merging that PR tags the release and publishes to the package registry automatically.
Design principles
Source-agnostic β Primitiv does not assume any particular toolchain. Sources are configured via adapters, and new adapters can be added for any system that holds design-relevant information. Works with Figma, Storybook, token files, raw codebase β or any combination.
Contract over documentation β The output is a machine-readable contract, not human-readable documentation. It is designed to be consumed by agents, not read by people.
Active reconciliation, not retrieval β Primitiv does not answer questions about what exists in your codebase. It resolves conflicts between sources and produces something authoritative. The distinction matters: retrieval gives you data, reconciliation gives you truth.
Inferred before prescribed β Primitiv surfaces the rules your codebase is already following before asking you to write any. The inferred rules are a starting point, not a final answer.
Governance is explicit β When sources conflict, the resolution is not silent. Conflicts are surfaced, logged, and resolved according to rules you define. Nothing is resolved by guessing.
Local-first and private β Primitiv runs entirely on your machine. Your codebase is never sent to an external service. The contract is a local file; the MCP server is a local process.
Incrementally adoptable β Start with a single source. Add more as needed. The contract remains valid at any level of completeness.
Roadmap
- Codebase scanner (CSS variables, TypeScript tokens, React components)
- Contract builder with conflict detection
- MCP server with 5 tools
-
primitiv initβ project detection and config generation - Inferred rules β extract design rules from actual codebase patterns
- AGENTS.md / CLAUDE.md integration β
primitiv initwrites agent instructions to the project's agent config file, ensuringget_design_contextis called before any UI build without manual prompting - Project-scoped MCP config β
primitiv initwrites a project-level MCP config so the server is scoped to the current project, not a global user-level server -
build-componentskill βprimitiv initinstalls a Claude Code slash command that queries the contract before building any UI component - Remediation steps on conflicts β conflicts include a
suggestedFixandactionableflag so agents know exactly what to do, not just what's wrong - Published to npm β available as
@ai-by-design/primitiv - Figma source adapter β scan Figma Variables and components via the Figma REST API
- Storybook source adapter β scan components and variants via the Storybook manifest
- Source provenance β every token and component in the contract traces back to its origin (file, line number, Figma variable ID, Storybook story ID)
- CI enforcement β
primitiv initauto-installs a GitHub Actions workflow that runsprimitiv verifyon every PR; pair with branch protection to block merges on contract drift - Token relationships β document how tokens relate and what constraints exist between them
Part of a larger system
Primitiv is the contract layer. It works alongside Design-workflow β a build system for going from idea to working product with agents. Design-workflow gives agents the process. Primitiv gives them the source of truth.
License
Apache-2.0
