# DESIGN.md CLI Linting Rules: Complete Configuration Guide

> Explore DESIGN.md CLI linting rules for broken references and more. Learn how to configure these fixed rules programmatically for an optimized workflow. Master design system linting.

- Repository: [Google Labs Code/design.md](https://github.com/google-labs-code/design.md)
- Tags: how-to-guide
- Published: 2026-06-27

---

**The DESIGN.md CLI executes ten fixed linting rules—including checks for broken references, contrast ratios, and orphaned tokens—that are defined in [`packages/cli/src/linter/rules/index.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/rules/index.ts) and can only be customized programmatically via the `lint(content, options?)` function, not through CLI flags.**

The [`google-labs-code/design.md`](https://github.com/google-labs-code/design.md/blob/main/google-labs-code/design.md) repository provides a TypeScript-based CLI tool for validating DESIGN.md files against design system specifications. While the command-line interface runs a hardcoded set of DESIGN.md CLI linting rules, the underlying API exposes configuration hooks that allow you to override the default rule set or implement custom validation logic.

## Default Linting Rules in DESIGN.md CLI

The linter processes ten rules in a specific order determined by the `DEFAULT_RULE_DESCRIPTORS` constant in [`packages/cli/src/linter/rules/index.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/rules/index.ts). These descriptors are combined into the runnable `DEFAULT_RULES` array at line 54, which the CLI invokes when you run `design-md lint`.

Each rule implementation resides in `packages/cli/src/linter/linter/rules/` and performs a specific validation:

| Rule | Description | Implementation |
|------|-------------|----------------|
| **brokenRefRule** | Detects broken references to tokens, colors, and other design system elements | [`broken-ref.ts`](https://github.com/google-labs-code/design.md/blob/main/broken-ref.ts) |
| **missingPrimaryRule** | Ensures a primary color token is defined | [`missing-primary.ts`](https://github.com/google-labs-code/design.md/blob/main/missing-primary.ts) |
| **contrastCheckRule** | Validates contrast ratios for accessibility compliance | [`contrast-ratio.ts`](https://github.com/google-labs-code/design.md/blob/main/contrast-ratio.ts) |
| **orphanedTokensRule** | Flags tokens that are defined but never used | [`orphaned-tokens.ts`](https://github.com/google-labs-code/design.md/blob/main/orphaned-tokens.ts) |
| **tokenSummaryRule** | Generates token usage summaries and warns on unexpected token types | [`token-summary.ts`](https://github.com/google-labs-code/design.md/blob/main/token-summary.ts) |
| **missingSectionsRule** | Validates presence of mandatory sections (Overview, Colors, Typography, etc.) | [`missing-sections.ts`](https://github.com/google-labs-code/design.md/blob/main/missing-sections.ts) |
| **missingTypographyRule** | Guarantees every referenced typography token exists | [`missing-typography.ts`](https://github.com/google-labs-code/design.md/blob/main/missing-typography.ts) |
| **sectionOrderRule** | Enforces canonical ordering of sections and allowed aliases | [`section-order.ts`](https://github.com/google-labs-code/design.md/blob/main/section-order.ts) |
| **unknownKeyRule** | Flags unknown top-level keys in the DESIGN.md file | [`unknown-key.ts`](https://github.com/google-labs-code/design.md/blob/main/unknown-key.ts) |
| **tokenLikeIgnoredRule** | Ignores intentionally placeholder tokens without values | [`token-like-ignored.ts`](https://github.com/google-labs-code/design.md/blob/main/token-like-ignored.ts) |

## How to Configure DESIGN.md CLI Linting Rules

The CLI command defined in [`packages/cli/src/commands/lint.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/commands/lint.ts) calls the `lint()` function without passing an `options` object, meaning it always runs the full `DEFAULT_RULES` array. To customize which rules execute, you must use the programmatic API.

### Programmatic Configuration via the Lint API

The `lint()` function exported from [`packages/cli/src/linter/lint.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/lint.ts) accepts an optional `LintOptions` object containing a `rules` array. Pass a filtered subset of `DEFAULT_RULES` or a custom array to override the default behavior.

```typescript
import { lint, DEFAULT_RULES } from './packages/cli/src/linter/index.js';
import { missingPrimary } from './packages/cli/src/linter/linter/rules/missing-primary.js';

// Run with the full default set
const report1 = lint(designMdContent);

// Run with a custom subset (e.g., drop the contrast check)
const customRules = DEFAULT_RULES.filter(r => r !== missingPrimary);
const report2 = lint(designMdContent, { rules: customRules });

```

### Creating Custom CLI Wrappers

If you require a bespoke rule set for regular command-line use, create a wrapper script that imports the `lint` function and passes your own `rules` array:

```typescript
#!/usr/bin/env node
import { lint, DEFAULT_RULES } from './packages/cli/src/linter/index.js';
import { unknownKey } from './packages/cli/src/linter/linter/rules/unknown-key.js';

// Only run the "unknown key" rule
const myRules = [unknownKey];
const report = lint(process.argv[2], { rules: myRules });

console.log(JSON.stringify(report, null, 2));

```

## Implementing Custom Lint Rules

Custom rules must implement the `LintRule` type, receiving a `DesignSystemState` object and returning an array of `Finding` objects:

```typescript
// my-rule.ts
import type { LintRule, DesignSystemState } from '../model/spec.js';
import type { Finding } from '../../linter/spec.js';

export const myRule: LintRule = (state: DesignSystemState): Finding[] => {
  // Example: flag any token whose name contains a space
  return Object.entries(state.tokens)
    .filter(([k]) => k.includes(' '))
    .map(([k]) => ({
      severity: 'warning',
      path: `tokens.${k}`,
      message: `Token names should not contain spaces (found "${k}")`,
    }));
};

// Usage in your script
import { myRule } from './my-rule.js';
const report = lint(content, { rules: [...DEFAULT_RULES, myRule] });

```

## Running the Built-in CLI

For standard validation using the complete default rule set, invoke the CLI directly:

```bash
design-md lint examples/totality-festival/DESIGN.md --format json

```

This outputs a JSON object containing `findings` and a `summary` field with counts of errors, warnings, and infos.

## Key Source Files for Linting

- **[`packages/cli/src/linter/rules/index.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/rules/index.ts)** – Contains `DEFAULT_RULE_DESCRIPTORS` and `DEFAULT_RULES` (line 54), the master list of default rules.
- **`packages/cli/src/linter/linter/rules/`** – Directory containing individual rule implementations ([`broken-ref.ts`](https://github.com/google-labs-code/design.md/blob/main/broken-ref.ts), [`missing-primary.ts`](https://github.com/google-labs-code/design.md/blob/main/missing-primary.ts), etc.).
- **[`packages/cli/src/linter/lint.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/lint.ts)** – Exposes the public `lint(content, options?)` API.
- **[`packages/cli/src/commands/lint.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/commands/lint.ts)** – CLI entry point that calls `lint()` with no options.
- **[`packages/cli/src/linter/spec-config.yaml`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/spec-config.yaml)** – Defines the DESIGN.md specification schema (not a lint configuration file).

## Summary

- The DESIGN.md CLI runs **ten fixed linting rules** defined in [`packages/cli/src/linter/rules/index.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/rules/index.ts) as `DEFAULT_RULE_DESCRIPTORS`.
- **No CLI flags** exist for disabling or configuring individual rules; the CLI always runs the full `DEFAULT_RULES` array.
- **Programmatic customization** requires importing the `lint()` function from [`packages/cli/src/linter/lint.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/lint.ts) and passing a `rules` array via `LintOptions`.
- **Custom rules** can be implemented by conforming to the `LintRule` type and processing the `DesignSystemState` object.
- Rule implementations are located in `packages/cli/src/linter/linter/rules/` with filenames matching their functionality (e.g., [`contrast-ratio.ts`](https://github.com/google-labs-code/design.md/blob/main/contrast-ratio.ts)).

## Frequently Asked Questions

### Can I disable specific rules via CLI flags?

No. The CLI command in [`packages/cli/src/commands/lint.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/commands/lint.ts) does not expose flags for rule configuration. It always invokes `lint(content)` with the default options. To run a subset of rules, you must create a custom script that imports the `lint` function and passes a filtered `rules` array in the `LintOptions` object.

### How do I add a custom rule to the DESIGN.md linter?

Create a TypeScript file that exports a function conforming to the `LintRule` type, which accepts a `DesignSystemState` and returns a `Finding[]` array. Import this rule into your custom script and pass it to the `lint()` function via the `options.rules` array alongside or instead of the default rules.

### What is the difference between DEFAULT_RULE_DESCRIPTORS and DEFAULT_RULES?

`DEFAULT_RULE_DESCRIPTORS` in [`packages/cli/src/linter/rules/index.ts`](https://github.com/google-labs-code/design.md/blob/main/packages/cli/src/linter/rules/index.ts) contains metadata about each rule, while `DEFAULT_RULES` (constructed at line 54) is the runnable array of rule functions that the linter actually executes. The CLI uses `DEFAULT_RULES` when you run the `lint` command.

### Where does the lint command output its results?

By default, the CLI outputs validation results to stdout. You can specify the output format using the `--format` flag (e.g., `--format json`), which returns a structured JSON object containing a `findings` array and a `summary` object with error, warning, and information counts.