Primitree

primitree build

Check a local DTCG source and write token files, CSS, Tailwind CSS, and TypeScript.

primitree build [--config <file>] [--source <name>]
primitree build --check [--config <file>] [--source <name>]
primitree build <variables.json> [older options]

Configured DTCG source

primitree build
primitree build --source brand
primitree build --source brand --check

The configured form reads ./primitree.config.ts unless --config names a file. Use --source when the config has several sources. The source needs output settings:

outputs: {
  directory: './generated',
  formats: ['dtcg', 'css', 'typescript', 'tailwind'],
}

The format list is optional and defaults to all four values. The command checks the source and its layer and owner rules before it writes. The output directory contains the selected files and .primitree-manifest.json.

An interrupted install can leave a backup or cleanup sidecar beside the output directory. Primitree reports each matching path for that output and stops before it replaces any installed files. Inspect the retained paths and recover any needed files before removing them and running the build again. Primitree leaves them in place.

The output directory must stay under the config file's directory and cannot contain the source token file. Use a separate directory for generated files. The output directory and every resolved file path under its output, staging, backup, and cleanup directories must fit within 1,023 UTF-8 bytes. Its normalized relative path can use up to 64 components. Each intermediate component can use up to 255 UTF-8 bytes, and the final directory name can use up to 200. A config can define up to 64 named sources. Each configured source path must stay below the config directory and can use up to 64 resolved absolute components and 1,023 UTF-8 bytes, including after symbolic-link resolution, with up to 255 UTF-8 bytes in each component. A generated-file path can use up to 64 directory levels, 16,639 UTF-8 bytes relative to its output, and 255 UTF-8 bytes in each segment. The shorter final directory name keeps the transaction paths portable. Primitree accepts a missing or empty directory for the first build. Later builds refuse a missing, changed, or unlisted path in an owned directory.

--check reports missing, changed, and unexpected paths without writing. It also rechecks the output directory and its ancestors while it scans, and stops if one changes. Exit code 0 means the files match. Exit code 1 means the files differ.

OptionDefaultDescription
--config <file>primitree.config.tsRead this config file
--source <name>the single sourceSelect one source
--checkoffReport output changes without writing

Figma variables export

The older form converts a Figma variables export:

primitree build variables.json
primitree build variables.json --out tokens --name "Acme DS"
primitree build variables.json --terrazzo --no-github-action

The default build writes token JSON, a Resolver, CSS, Tailwind v4, TypeScript, a transformer config, a workflow template, and a README. See Pipeline output for the file tree.

Figma options

OptionDefaultDescription
--out <dir>design-tokensOutput directory
--name <name>Design TokensResolver document name
--style-dictionaryonScaffold Style Dictionary config
--terrazzooffScaffold Terrazzo config instead
--no-transformeroffSkip transformer config
--no-cssoffSkip css/tokens.css
--no-tailwindoffSkip Tailwind v4 file
--no-tsoffSkip TypeScript output
--no-github-actionoffSkip workflow template
--no-readmeoffSkip generated README

Programmatic use

@primitree/dtcg exports the build function:

import { buildPipeline, type BuildPipelineResult } from '@primitree/dtcg'

const result: BuildPipelineResult = buildPipeline(figmaJson, {
  transformer: 'style-dictionary',
})

for (const file of result.files) {
  console.log(file.path, file.contents)
}