How to Use the Programmatic API to Lint DESIGN.md Files

The @google/design.md package exports a lint function that parses DESIGN.md content, resolves design tokens into a typed model, runs configurable validation rules, and returns a structured LintReport containing findings, severity counts, and a Tailwind-compatible configuration.

The google-labs-code/design.md repository provides a self-contained linting engine for design system documentation. While the CLI handles file system operations, the programmatic API allows you to integrate DESIGN.md validation directly into CI pipelines, custom tooling, or editor extensions. This guide covers the core lint function and its supporting handlers as implemented in the TypeScript source.

Importing the Linter Entry Point

The public API surface is exposed through the package's linter entry point. Import the lint function and associated types from @google/design.md/linter to begin processing DESIGN.md content programmatically.

import { lint, type LintReport, type LintOptions } from '@google/design.md/linter';
import { readFileSync } from 'node:fs';

The main entry file at packages/cli/src/linter/index.ts re-exports the core implementation from packages/cli/src/linter/lint.ts along with type definitions and rule helpers.

Understanding the Linting Pipeline

When you invoke lint(content, options?), the function executes a five-stage pipeline defined in packages/cli/src/linter/lint.ts:

  1. ParsingParserHandler reads the raw Markdown, extracts YAML front-matter (if present), and constructs a ParsedDesignSystem structure.
  2. Model resolutionModelHandler resolves token references, normalizes colors, dimensions, and typography into a fully typed DesignSystemState.
  3. Rule executionrunLinter applies the DEFAULT_RULES set or any custom LintRules supplied in options, aggregating findings and severity counts.
  4. Tailwind emissionTailwindEmitterHandler generates a Tailwind-compatible theme configuration from the resolved design system.
  5. Report assembly – Results are packaged into a LintReport containing findings, the model, Tailwind config, and a section map.

The function gracefully handles documents missing YAML front-matter by falling back to a simple heading scan (extractSectionsFromContent) and returning a warning-level finding rather than throwing an exception.

Basic Linting Example

Load your DESIGN.md content and call lint to receive a complete validation report.

// Load raw markdown content
const designMd = readFileSync('examples/totality-festival/DESIGN.md', 'utf8');

// Run the linter with default options
const report: LintReport = lint(designMd);

// Inspect results
console.log('Resolved tokens:', report.designSystem.tokens?.length ?? 0);
console.log('Findings:', report.findings.length);

report.findings.forEach(f => {
  console.log(`[${f.severity.toUpperCase()}] ${f.message}`);
});

// Access generated Tailwind configuration
console.log('Tailwind config:', JSON.stringify(report.tailwindConfig, null, 2));

Customizing Validation Rules

Pass a LintOptions object to override the default rule set. Import DEFAULT_RULES and individual rules like brokenRef from packages/cli/src/linter/rules/index.ts to compose custom validation logic.

import { DEFAULT_RULES, brokenRef } from '@google/design.md/linter';

const customOptions: LintOptions = {
  rules: [
    ...DEFAULT_RULES,
    // Add custom validation for broken references
    brokenRef,
  ],
};

const report = lint(designMd, customOptions);

Advanced Programmatic Workflows

Beyond basic linting, the API exposes handlers for additional processing.

Key Types and Source Files

Reference these core types when building integrations.

Type Description Source Location
LintReport Complete result including findings, design system, and Tailwind config packages/cli/src/linter/lint.ts
LintOptions Configuration interface accepting custom rule arrays packages/cli/src/linter/lint.ts
Finding Individual issue with severity level and message packages/cli/src/linter/spec.ts
DesignSystemState Fully resolved design tokens model packages/cli/src/model/spec.ts

The rule execution logic resides in packages/cli/src/linter/runner.ts, while the Tailwind configuration emitter is implemented in packages/cli/src/tailwind/handler.ts.

Summary

  • Import the lint function from @google/design.md/linter to validate DESIGN.md content programmatically.
  • The pipeline parses Markdown, resolves tokens via ModelHandler, executes rules via runLinter, and generates Tailwind config via TailwindEmitterHandler.
  • The function handles missing YAML front-matter gracefully by falling back to heading extraction with a warning.
  • Customize validation by passing custom rules through the LintOptions interface.
  • Access auxiliary handlers like fixSectionOrder and DtcgEmitterHandler for fixing and exporting operations.

Frequently Asked Questions

What happens if my DESIGN.md file lacks YAML front matter?

The lint function detects missing front-matter and automatically falls back to extractSectionsFromContent for basic heading analysis. It returns a warning-level finding in the report rather than throwing an error, allowing the linting process to continue with reduced metadata extraction.

How do I add custom lint rules to the programmatic API?

Construct a LintOptions object with a rules array containing your custom LintRule implementations. Import the DEFAULT_RULES array from packages/cli/src/linter/rules/index.ts and spread it into your custom array alongside additional rules like brokenRef to extend or replace the default validation behavior.

Can I export the linted design system to other formats?

Yes. After linting, use the DtcgEmitterHandler (located in packages/cli/src/dtcg/handler.ts) to serialize the DesignSystemState into a DTCG (Design Tokens Community Group) compatible token file format for integration with other design tools and pipelines.

Where is the lint function defined in the source code?

The lint function is implemented in packages/cli/src/linter/lint.ts and re-exported as the public API entry point in packages/cli/src/linter/index.ts. The function orchestrates the parsing, modeling, and rule execution phases while delegating specific tasks to specialized handlers like ParserHandler and ModelHandler.

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 →