DESIGN.md import¶
pulp import-design --from designmd reads Google's
DESIGN.md format (Apache-2.0) — a
YAML-frontmatter + Markdown-body description of a design system — and
emits a W3C Design Tokens Community Group (DTCG) tokens.json. The
upstream spec is the source of truth for the format; this page documents
the Pulp parser, its detection rules, and the tokens-only import contract.
Because DESIGN.md describes a system (colors, typography, spacing,
component recipes), not a screen, the importer does not emit a
ui.js. That's a deliberate split from the other import sources, which
all start from a screen export. Pair this importer with a separate
screen import (Figma, Stitch, Pencil, v0, Claude) when you want a full
UI; use it standalone when you only need to bring a token system into
Pulp.
Quickstart¶
Produces:
tokens.json— DTCG token tree with$typeand$valuefor every parsed key. Reference resolution is applied (see below). Composite typography references insidecomponents.*are preserved verbatim so downstream tooling can resolve them in context.
Does not produce:
ui.js— DESIGN.md has no screen. Component scaffolding fromcomponents.*remains future work; the current importer stops at tokens.classnames.json— that artifact is specific to theclaudesource.- Any bridge or React scaffold — there's no view to render.
Detect-only (no file writes):
Supported subset¶
The parser handles the canonical frontmatter keys (tracked against the
upstream format spec, pinned at tag 0.4.0). Unrecognized top-level keys
are flagged with a warning and otherwise ignored, so a typo'd key surfaces
instead of silently dropping its tokens.
| Key | Parsed | Notes |
|---|---|---|
version |
yes | Stored on the IR; not emitted into tokens.json. |
name |
yes | Required for detection. Stored on the IR. |
description |
yes | Block scalars (|, >) handled by yaml-cpp. |
omitted |
yes | Bare section names and {section, reason?} entries are retained as lint metadata. Intentional omissions suppress matching missing-section findings; unknown or redundant declarations are reported. |
colors.* |
yes | Each entry becomes a color token. The value may be any valid CSS color — hex (#RGB/#RGBA/#RRGGBB/#RRGGBBAA), a named keyword (cornflowerblue, transparent), or a functional notation (rgb(), hsl(), hwb(), oklch(), lab(), color-mix(), …) — and is preserved verbatim. Nested palettes nest up to 20 levels and key on the dot-joined path (e.g. colors.background.light → token background.light). |
typography.* |
yes | Composite typography tokens with fontFamily, fontSize, fontWeight, lineHeight, letterSpacing, fontFeature, fontVariation. Unknown sub-properties warn and remain preserved rather than being silently dropped. |
rounded.* |
yes | dimension tokens. Nested levels nest up to 20 levels (dot-joined path). |
spacing.* |
yes | dimension tokens. A bare number (e.g. base: 8) is read as px per spec; nested levels nest up to 20 levels. Genuinely non-dimensional values (e.g. auto) are preserved as strings. |
shadows.* |
yes | Pulp extension, not an upstream 0.4.0 key. shadow-<name> string tokens holding the CSS shadow value verbatim (0 1px 3px rgba(0,0,0,.2)); nested levels nest up to 20 levels (dot-joined path). The shadow-* namespace already exists via the ## Shadows body section — this gives structured frontmatter a door to it, so a DESIGN.md can declare a shadow without dropping to prose. Authors coming from ## Elevation should spell the frontmatter key shadows; elevation: warns as an unknown key. |
components.* |
yes | Each component is a flat map of token references and literal style values; numeric and boolean YAML scalars (e.g. fontWeight: 600, enabled: true) flow through as strings. References are not resolved at parse time (see below). |
| Unknown top-level keys | warn | The parser emits one designmd.unknown-key warning per unrecognized top-level key (catches typos like color:/typgrphy:) and otherwise ignores it. The file still imports. |
| Unknown component properties | passthrough | Per the spec, unknown component props are preserved as opaque strings. |
The 0.4 parser also rejects ambiguous flattened token names such as
brand-primary alongside nested brand.primary. Recursive token groups are
limited to 20 levels and dimension recognition is capped at 64 characters, so
malformed input cannot turn validation into unbounded recursion or regex work.
Pulp preserves color strings and delegates their actual rendering to its CSS
and theme consumers; it does not reimplement upstream's color evaluator, so the
0.4 grad and color-mix() evaluator fixes do not create a Pulp parsing delta.
Frontmatter is authoritative but not exclusive. The parser also scans the Markdown body for token sections and lets the body fill gaps frontmatter left: a token defined in both forms keeps its frontmatter value, and a token only the body names is still imported. Prose-authored files (common for Stitch / Brand-Kit exports) therefore keep their tokens when frontmatter is added to them, rather than silently importing an empty set.
The body scan reads name: value list items and | name | value | table
rows under these sections:
| Body section | Tokens |
|---|---|
## Colors / ## Color Palette |
color tokens (header/separator rows skipped) |
## Spacing |
spacing-<name> dimensions |
## Border Radius / ## Rounded |
rounded-<name> dimensions |
## Shadows / ## Elevation |
shadow-<name> string tokens |
A ### Light Mode / ### Dark Mode subsection under ## Colors routes
values to the bare token name (light/default) or a <name>.dark suffix
(dark) — the same multi-mode convention the Figma plugin uses, so dark
themes land in the flat token maps.
Reference resolution¶
DESIGN.md uses {group.key} for references. Pulp's resolver runs at
parse time:
| Reference | Resolves to | Behavior |
|---|---|---|
{colors.primary} |
#1A1C1E (the literal value) |
Inlined in the emitted token's $value. |
{colors} |
(group reference) | Outside components.*: emits a designmd.broken-ref warning. DTCG has no concept of a group alias. |
{typography.label-md} |
(composite) | Inside components.*: preserved verbatim in the component's $value. Outside components.*: warns. |
Cycle detection is depth-limited at 10 hops; deeper chains warn and
stop expanding. Unresolved references ({colors.does-not-exist}) emit
a designmd.broken-ref diagnostic at the reference's source line and
leave the literal {…} string in the output.
Detection¶
The designmd fingerprint in compat.json is all-of with a 95%
minimum confidence floor. All four clauses must match:
filename— the input file's basename matches^DESIGN\.md$(case-insensitive).frontmatter-fence— the file starts with a---line followed by another---line later in the document.frontmatter-key(required) — the frontmatter contains aname:key.frontmatter-key(any-of) — the frontmatter contains at least one ofcolors,typography,rounded,spacing,components.
The combination is intentionally strict. A generic Jekyll or Hugo blog
post with name: in its frontmatter will not match because it has no
canonical DESIGN.md token group. Three decoys live under
test/fixtures/imports/designmd/alpha/decoys/ and are exercised by
pulp-test-cli-import-detect:
jekyll/DESIGN.md— Jekyll post withname:andlayout:but no token groups → does not match.missing-name/DESIGN.md— hascolors:but noname:→ does not match.missing-token-groups/DESIGN.md— hasname:anddescription:but no canonical token groups → does not match.
A --detect-only invocation on a real DESIGN.md prints:
detected source: designmd
format-version: alpha
parser-version: 0.1
fingerprint match: 4/4 (filename, frontmatter-fence, frontmatter-key[name], frontmatter-key[colors|typography|rounded|spacing|components])
confidence: 100%
Exit codes¶
| Code | Meaning |
|---|---|
0 |
Success — tokens.json written (or detect-only match printed). |
1 |
Usage error or write failure (missing --file, unwritable --tokens path, permission denied). |
2 |
Detect-only run found no match. |
3 |
Parse error — malformed YAML frontmatter, duplicate top-level section, missing closing fence. |
4 |
Unsupported feature — encountered a construct the parser explicitly rejects rather than silently dropping (reserved; nothing currently triggers it). |
Diagnostics¶
The parser emits one diagnostic per line on stderr in this format:
Example:
[warning] designmd.broken-ref at colors.accent (14:12): reference {colors.does-not-exist} could not be resolved
[warning] designmd.unknown-section at extras (42:1): top-level key 'extras' is not part of the canonical schema; preserved as opaque string
[error] designmd.duplicate-section at colors (3:1): 'colors' appears more than once in frontmatter
severity is one of error (exit code 3 or 4), warning (does not
affect exit code), or info (suppressed unless --debug).
Current contract¶
The import path ships exactly the surface above:
pulp import-design --from designmd→tokens.json.- Detection in
compat.jsonwith the strict fingerprint. - Test fixtures (paws-and-paths from upstream, plus a hand-authored edge-case fixture and three decoys).
- This documentation page and the cross-references listed below.
pulp design lint <DESIGN.md>for DESIGN.md quality findings.pulp design diff <before.md> <after.md>for semantic token diffs.- CSS custom-property export via
pulp import-design --from designmd --format css-variables. This predates upstream 0.4's equivalentcss-varsspelling. Pulp does not currently expose upstream's optional--prefix; import compatibility does not depend on it.
Tailwind v3 + v4 exporters remain future work.
Treating DESIGN.md as a project source of truth remains future work:
pulp design does not yet hydrate the live theme from DESIGN.md, and
pulp design save --update-design-md does not yet round-trip changes
back. Component scaffolding from components.* into Pulp widgets is in
the same future-work bucket.
Not yet supported¶
- Tailwind v3 / v4 export.
- Live runtime hydration of Pulp's theme from a DESIGN.md file.
- Widget scaffolding from
components.*. - An
npx @google/design.md specequivalent — out of scope. Pulp ships the format documentation as this page; the upstream spec at github.com/google-labs-code/design.md remains authoritative for the format itself.
Attribution¶
- yaml-cpp (MIT) is vendored to parse the frontmatter; see
DEPENDENCIES.mdfor the pin andNOTICE.mdfor the formal license text. - The
paws-and-pathstest fixture undertest/fixtures/imports/designmd/alpha/DESIGN.mdis copied verbatim from the upstream google/design.md repository (Apache-2.0).NOTICE.mdcarries the upstream attribution alongside the project's other third-party notices.