Using design-system.json

design-system.json is the same content as design-system.md, in a shape a script can parse without natural-language tricks. Reach for it when you're writing tooling.

The shape

interface DesignSystemJson {
  name: string                      // library name
  generatedAt: string               // ISO timestamp
  tokens: {
    primitive: DesignToken[]
    semantic:  DesignToken[]
    shadcn:    DesignToken[]
  }
  principles: LayoutPrinciple[]
  designRules: DesignRules
}

Token, principle, and rules shapes are documented in Reference → Schemas.

When to use the JSON instead of the Markdown

Use case Pick
Feeding context to an AI agent design-system.md
Documenting for humans design-system.md
Reading from a Node script design-system.json
Writing a custom lint rule design-system.json
Validating that a built page matches the system design-system.json
Round-tripping back into Tostada the library JSON via importLibrary (different file — see re-importing)

Example — a build-time lint

// scripts/lint-tokens.mjs
import ds from './design-system.json' assert { type: 'json' }

const allowed = new Set(ds.tokens.shadcn.map(t => t.id))
const usedInCode = scanCodebaseForCssVars() // your scanner

for (const used of usedInCode) {
  if (!allowed.has(used)) {
    console.error(`Unknown shadcn token: ${used}`)
    process.exitCode = 1
  }
}

Example — a Figma sync (future)

const ds = await fetch('/design-system.json').then(r => r.json())
await figma.applyTokens(ds.tokens.primitive.map(t => ({ name: t.name, value: t.value })))

We don't ship a Figma sync today — but design-system.json is the shape it would consume.

Versioning

The shape evolves with Tostada. Two rules:

  1. Existing fields don't change meaning. A field that meant "the resolved hex color" yesterday still means that today.
  2. New fields are additive. If your reader doesn't know about a new field, it should ignore it.

There's no version field yet. The roadmap will introduce one before the shape changes in a breaking way.

Stability

The JSON is deterministic — same library state produces the same bytes. Diff two exports across time and you see real changes, not whitespace.