How to Schedule Exports with design.md: CLI Automation Guide

The design.md CLI does not include built-in scheduling capabilities, but you can automate recurring exports using external schedulers like cron or CI/CD pipelines because the export command is idempotent and stateless.

The design.md repository from Google Labs provides a stand-alone CLI for converting DESIGN.md files into design token formats, but it lacks internal scheduling functionality. To run exports on a recurring basis, you must orchestrate the CLI yourself using external automation tools. This guide explains the export pipeline internals and provides practical examples for scheduling exports in production environments.

Understanding the Export Command Architecture

The export functionality is implemented in [packages/cli/src/commands/export.ts](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/commands/export.ts). The command provides no built-in scheduling facility—its arguments are limited to the source file path, the output format, and an optional CSS prefix. The CLI is designed to be idempotent and fast, processing a single export request and exiting immediately, which makes it safe to invoke repeatedly from external schedulers.

How the Export Pipeline Works

The export process follows a deterministic five-step pipeline:

  1. Argument validation – The command validates that the requested format matches one of the closed enum values (css-tailwind, json-tailwind, tailwind, dtcg, css-vars). The validation check occurs at lines 49-57:

    if (!FORMATS.includes(format as ExportFormat)) { … }
  2. Input reading – The CLI reads the DESIGN.md file (or stdin) via the readInput function from [packages/cli/src/utils.ts](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/utils.ts#L42-L68).

  3. Linting – The content is parsed and linted using lint(content) to produce a DesignSystemState.

  4. Emitter selection – Based on the format, the appropriate emitter handler is instantiated. The source code at lines 84-86 demonstrates the handler pattern:

    const handler = new TailwindEmitterHandler();
    const result = handler.execute(report.designSystem);

    Available handlers include TailwindEmitterHandler, TailwindV4EmitterHandler, CssVarsEmitterHandler, and DtcgEmitterHandler (re-exported from [packages/cli/src/linter/index.ts](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/index.ts)).

  5. Result handling – On success, the emitter output is transformed (via JSON.stringify, serializeTailwindV4, or serializeCssVars) and written to stdout.

The command exits with specific status codes defined at lines 118-124: 0 for success, 1 for invalid format or emitter errors, and 2 if the source file cannot be read.

Scheduling Methods for design.md Exports

Because the CLI has no internal scheduler, you must use external orchestration to run exports on a schedule.

Method 1: Cron-Based Scheduling

Add the following entry to your crontab (crontab -e) to run nightly exports at 02:00 UTC:

0 2 * * * cd /path/to/project && \
  npx @google/design.md export --format css-tailwind DESIGN.md > /var/www/assets/theme.css

This approach runs the CLI outside of your main application, redirecting output to your asset directory. The idempotent design ensures repeated executions remain safe.

Method 2: CI/CD Pipeline Automation (GitHub Actions)

Trigger exports automatically when your design tokens change:

name: Export Design Tokens
on:
  push:
    paths:
      - '**/DESIGN.md'
jobs:
  export:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npx @google/design.md export --format dtcg DESIGN.md > tokens.json
      - uses: actions/upload-artifact@v4
        with:
          name: dtcg-tokens
          path: tokens.json

This workflow regenerates DTCG JSON output every time a DESIGN.md file changes, storing artifacts for downstream consumption.

Method 3: Manual One-Off Exports

For ad-hoc generation, invoke the CLI directly:


# Export to Tailwind v3 JSON (theme.extend)

npx @google/design.md export --format json-tailwind DESIGN.md > tailwind.theme.json

Supported Export Formats and Handlers

The CLI supports five export formats, each handled by a specific emitter class:

Summary

  • The design.md CLI is stateless and idempotent, making it safe for automated scheduling.
  • No built-in scheduler exists in packages/cli/src/commands/export.ts; all scheduling must be external.
  • Use cron jobs for server-based automation or GitHub Actions for CI/CD integration.
  • The CLI returns specific exit codes (0, 1, 2) for programmatic error handling.
  • All five export formats (css-tailwind, json-tailwind, dtcg, css-vars, tailwind) support automation equally via their respective emitter handlers.

Frequently Asked Questions

Can I schedule exports directly within the design.md CLI?

No, the CLI in packages/cli/src/commands/export.ts processes single export requests and immediately exits. It has no daemon mode, internal timer, or watch functionality. You must use external schedulers like cron, GitHub Actions, or other task runners to invoke the command repeatedly.

What exit codes does the export command return?

The command returns three specific exit codes defined at lines 118-124 of export.ts: 0 indicates successful completion, 1 indicates invalid format or emitter errors (when the format argument is not in the FORMATS array), and 2 indicates the source file could not be read via readInput.

Is it safe to run multiple design.md exports concurrently?

Yes, the CLI is designed to be deterministic and stateless, with no shared state between invocations. You can safely run multiple export commands in parallel through overlapping cron schedules or parallel CI jobs without risk of file corruption or race conditions.

Which export formats support scheduled automation?

All supported formats—css-tailwind, json-tailwind, tailwind, dtcg, and css-vars—support automation equally. The scheduling mechanism operates at the process level (cron or CI), while the format-specific logic resides in individual emitter handlers (TailwindEmitterHandler, DtcgEmitterHandler, etc.) that all follow the same idempotent execution pattern.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →