How the Export Functionality Works in design.md: From DESIGN.md to Tailwind, DTCG, and CSS Variables
The export functionality in the google-labs-code/design.md repository (Instagit) converts DESIGN.md files into Tailwind v3 JSON, Tailwind v4 CSS, W3C Design Tokens, or CSS custom properties through a pure, functional pipeline that parses CLI arguments, lints the input, and routes to specific emitter handlers.
This export functionality lives entirely within the CLI package and follows a strict sequence: input validation, file reading, linting into a DesignSystemState, format-specific emission, and final serialization to stdout.
Command-Line Parsing and Validation
The export entry point is defined in packages/cli/src/commands/export.ts using the citty command framework. The command accepts three arguments:
file– Path to the DESIGN.md file, or-to read from stdinformat– One of five supported export formats:css-tailwind,json-tailwind,tailwind,dtcg, orcss-varsprefix– Optional CSS variable prefix (used only withcss-varsformat)
Validation occurs against a closed enum. If the provided format is invalid, the CLI immediately writes a JSON error payload to stderr and exits with status code 1:
// packages/cli/src/commands/export.ts (lines 49-57)
if (!FORMATS.includes(format as ExportFormat)) {
console.error(JSON.stringify({
error: 'INVALID_FORMAT',
message: `Invalid format "${format}". Valid formats: ${FORMATS.join(', ')}`,
}));
process.exitCode = 1;
return;
}
Input Reading and Error Handling
Before processing begins, the readInput function from packages/cli/src/utils.ts loads the source content. This utility handles both file system access and stdin streams, wrapping I/O errors in a FileReadError that triggers exit code 2 and produces a user-friendly JSON error message.
The Linting Step: Parsing DESIGN.md
Every export operation begins with linting. The raw markdown text is passed to the lint function exported from packages/cli/src/linter/index.ts. This step parses the DESIGN.md into a DesignSystemState object and validates the content against design system rules.
The linting step is mandatory and always executed because all emitters require the parsed DesignSystemState object as their input. Even when the lint step produces warnings, the export continues unless critical errors prevent state generation.
Export Format Handlers
After successful linting, the CLI instantiates a specific emitter handler based on the --format flag. Each handler implements an execute(state) method that maps the DesignSystemState to the target format through pure, side-effect-free transformations.
Tailwind v3 JSON Output
The TailwindEmitterHandler (located at packages/cli/src/linter/tailwind/handler.ts) generates a Tailwind v3 compatible theme.extend configuration object:
// Tailwind v3 emitter (excerpt, lines 24-35)
return {
success: true,
data: {
theme: {
extend: {
colors: this.mapColors(state),
fontFamily: this.mapFontFamilies(state),
fontSize: this.mapFontSizes(state),
borderRadius: this.mapDimensions(state.rounded),
spacing: this.mapDimensions(state.spacing),
},
},
},
};
This output is suitable for extending a tailwind.config.js file.
Tailwind v4 CSS Output
The TailwindV4EmitterHandler (packages/cli/src/linter/tailwind/v4/handler.ts) produces CSS for Tailwind v4's @layer theme syntax. This handler includes strict validation: every token name is verified against the CSS identifier regex /^[a-zA-Z0-9][a-zA-Z0-9-]*$/. If any token name fails validation, the emitter returns success: false with an INVALID_TOKEN_NAME error, causing the CLI to exit with status 1.
W3C Design Tokens (DTCG)
The DtcgEmitterHandler (packages/cli/src/linter/dtcg/handler.ts) converts the design system into the W3C Design Tokens Community Group format. This produces a standardized JSON payload that interoperates with design token management tools and other design system platforms.
CSS Custom Properties
The CssVarsEmitterHandler (packages/cli/src/linter/css-vars/handler.ts) outputs CSS custom properties (variables) using the optional --prefix flag. Tokens are serialized as --${prefix}var: value; declarations, making them immediately usable in modern CSS workflows.
Serialization and Output Generation
After the emitter handler executes successfully, the CLI serializes the result for stdout:
- JSON formats (
json-tailwind,tailwind,dtcg) are pretty-printed usingJSON.stringify(data, null, 2) - CSS formats (
css-tailwind,css-vars) use specialized serializers:serializeTailwindV4(frompackages/cli/src/linter/tailwind/v4/serialize.ts) andserializeCssVars(frompackages/cli/src/linter/css-vars/serializer.ts)
The entire pipeline remains pure until the final write operation, printing the formatted string to stdout or writing error details to stderr.
Exit Codes and Error Behavior
The export functionality uses specific exit codes to signal operation status:
- Exit code 0: Successful export, even if linting generated warnings
- Exit code 1: Invalid format selection, emitter validation failure (such as invalid Tailwind v4 token names), or other processing errors
- Exit code 2: File read errors (I/O failures when loading the DESIGN.md source)
Practical Usage Examples
Export to Tailwind v3 configuration:
instagit export ./examples/totality-festival/DESIGN.md json-tailwind > tailwind-theme.json
Generate Tailwind v4 CSS:
instagit export ./examples/paws-and-paths/DESIGN.md css-tailwind > tailwind-v4.css
Create W3C Design Tokens:
instagit export ./examples/atmospheric-glass/DESIGN.md dtcg > design-tokens.json
Export CSS variables with custom prefix:
instagit export ./examples/totality-festival/DESIGN.md css-vars --prefix="my-app"
# Output: --my-app-color-primary: #ff5722;
Summary
- The export functionality in
google-labs-code/design.mdconverts DESIGN.md files into Tailwind v3, Tailwind v4, DTCG, or CSS variable formats through a pipeline defined inpackages/cli/src/commands/export.ts. - The process requires three steps: command-line validation using
citty, input reading viareadInput, and mandatory linting to produce aDesignSystemStateobject. - Four emitter handlers (
TailwindEmitterHandler,TailwindV4EmitterHandler,DtcgEmitterHandler,CssVarsEmitterHandler) transform the parsed state into format-specific outputs using pure mapping functions. - Tailwind v4 output validates token names against CSS identifier requirements, returning
INVALID_TOKEN_NAMEerrors for non-compliant names. - Exit codes distinguish between success (0), processing errors (1), and file I/O failures (2), with all errors written as JSON to stderr.
Frequently Asked Questions
What file formats can the export functionality generate?
The export functionality supports five specific formats: css-tailwind (Tailwind v4 CSS), json-tailwind or tailwind (Tailwind v3 JSON), dtcg (W3C Design Tokens), and css-vars (CSS custom properties). Each format is handled by a dedicated emitter class in the packages/cli/src/linter/ directory that transforms the parsed DesignSystemState into the target specification.
Why is the linting step mandatory for all exports?
The linting step is mandatory because every emitter handler requires a validated DesignSystemState object as input. Located in packages/cli/src/linter/index.ts, the lint function parses the raw DESIGN.md markdown and constructs the state object that maps design tokens to the specific requirements of each export format. Without this parsing step, the emitters cannot access structured token data.
How does the export functionality handle invalid token names?
For Tailwind v4 CSS output, the TailwindV4EmitterHandler validates every token name against the regex /^[a-zA-Z0-9][a-zA-Z0-9-]*$/ to ensure CSS identifier compliance. If any token name contains invalid characters, the emitter returns success: false with an INVALID_TOKEN_NAME error, causing the CLI to exit with status code 1 and write a JSON error object to stderr.
What is the difference between the Tailwind v3 and v4 export handlers?
The TailwindEmitterHandler generates a JSON configuration object suitable for tailwind.config.js files, nesting values under theme.extend. The TailwindV4EmitterHandler produces raw CSS using the @layer theme syntax and includes additional validation for CSS identifier compatibility. While the v3 handler outputs configuration objects, the v4 handler outputs directly usable CSS rules.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →