DESIGN.md vs tailwind.config.js — Por que AI agents precisam do wrapper semântico

Comparação entre DESIGN.md e configurar tokens direto no tailwind.config.js. Por que LLMs não parsam configs JavaScript bem e como DESIGN.md resolve isso.

DESIGN.mdtailwind.config.js

Veredito Rápido

Se você usa Tailwind e AI coding agents (que é basicamente todo mundo em 2026), use os dois. O tailwind.config.js é o runtime — onde o framework lê os tokens. O DESIGN.md é o manual semântico — onde o agente entende por quê aqueles tokens existem e como usá-los. Colocar tudo só no tailwind.config e esperar que o Cursor entenda a intenção é como dar um dicionário pra alguém e esperar que escreva poesia.


Tabela Comparativa

DimensãoDESIGN.mdtailwind.config.js
FormatoYAML tokens + Markdown rationaleJavaScript/TypeScript object
Propósito primárioDocumentação semântica para humanos e AIConfiguração de runtime do Tailwind
Consumo por LLMsExcelente — formato nativo de LLMsProblemático — JS nested, spread operators, imports dinâmicos
Decisões de designEmbutidas no documentoInexistentes — só valores crus
PortabilidadeFramework-agnosticSó Tailwind (e derivados como UnoCSS com adapter)
ExecutávelNão — é documentaçãoSim — Tailwind lê e gera CSS
ConflitosRaro — arquivo pequeno e focadoComum — merge conflicts em objetos JS grandes
ManutençãoAtualiza quando design system mudaAtualiza quando design system muda (duplicação)

O Problema Real: LLMs e JavaScript Config

Aqui está o elefante na sala que ninguém discutia até AI agents virarem mainstream: LLMs são péssimos em parsear configuração JavaScript complexa.

Um tailwind.config.js típico de projeto real parece isso:

import { fontFamily } from 'tailwindcss/defaultTheme'
import colors from './tokens/colors.mjs'
import typography from './tokens/typography.mjs'

/** @type {import('tailwindcss').Config} */
export default {
  content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'],
  theme: {
    extend: {
      colors: {
        ...colors,
        primary: {
          DEFAULT: 'hsl(var(--primary))',
          foreground: 'hsl(var(--primary-foreground))',
        },
        surface: {
          DEFAULT: 'hsl(var(--surface))',
          elevated: 'hsl(var(--surface-elevated))',
        }
      },
      fontFamily: {
        display: ['Cal Sans', ...fontFamily.sans],
        body: ['Inter', ...fontFamily.sans],
      },
      spacing: generateSpacingScale(4),
      borderRadius: {
        ...defaultRadius,
        card: 'var(--radius-card)',
      }
    }
  },
  plugins: [require('@tailwindcss/typography'), require('@tailwindcss/forms')],
}

O que o LLM vê aqui:

  1. Imports dinâmicos — não sabe o que colors.mjs contém sem ler outro arquivo
  2. Spread operators...colors é uma caixa preta
  3. CSS variableshsl(var(--primary)) não é um valor, é uma referência
  4. FunçõesgenerateSpacingScale(4) requer execução mental
  5. Zero contexto — por que Cal Sans? Por que ratio de 4px? Silêncio.

Quando o agente recebe um prompt “crie um card de pricing seguindo nosso design system”, ele lê esse config e… chuta. Usa cores que parecem certas. Aplica espaçamento “mais ou menos”. O resultado compila, mas não respeita a intenção.


DESIGN.md em Detalhe

O wrapper semântico

DESIGN.md não substitui o tailwind.config. Ele envelopa os mesmos tokens com significado:

colors:
  primary:
    value: "hsl(222 47% 11%)"
    tailwind: "primary"
    usage: "CTAs, links primários, headers de seção"
    contrast: "Usar sempre com text-white ou primary-foreground"
  surface:
    default:
      value: "hsl(0 0% 100%)"
      tailwind: "surface"
      usage: "Background padrão de cards e containers"
    elevated:
      value: "hsl(210 20% 98%)"
      tailwind: "surface-elevated"
      usage: "Cards com elevação, modals, popovers"

typography:
  philosophy: |
    Escala modular com ratio 1.25 (Major Third).
    Display usa Cal Sans para personalidade.
    Body usa Inter para legibilidade em telas.
    Nunca misturar display em corpo de texto.
  scale:
    - name: "hero"
      class: "text-5xl font-display font-bold"
      usage: "Apenas hero sections — um por página"
    - name: "section-title"
      class: "text-3xl font-display font-semibold"
      usage: "Títulos de seção — h2 na hierarquia"
    - name: "body"
      class: "text-base font-body"
      usage: "Texto corrido — parágrafos, descrições"

spacing:
  base: "4px"
  philosophy: |
    Múltiplos de 4px. Componentes internos usam 2-4 (8-16px).
    Entre componentes usa 6-8 (24-32px).
    Entre seções usa 16-24 (64-96px).
    Nunca usar valores arbitrários como p-[13px].

O que muda na prática

Com esse DESIGN.md no contexto, o mesmo prompt “crie um card de pricing” gera:

  • Cores corretas com contraste adequado
  • Tipografia hierárquica respeitando a escala
  • Espaçamento consistente com o sistema
  • Classes Tailwind corretas (não inventa bg-slate-50 quando deveria ser bg-surface-elevated)

Vantagens específicas sobre config puro

  1. Self-contained — tudo num arquivo, sem imports pra resolver
  2. Intenção explícita — “nunca usar display em corpo de texto” evita erros
  3. Classes mapeadas — o agente sabe exatamente qual classe Tailwind aplicar
  4. Exemplos de uso — cenários concretos, não só valores abstratos
  5. Restrições documentadas — o que NÃO fazer é tão importante quanto o que fazer

tailwind.config.js em Detalhe

O que faz bem

O tailwind.config.js é execução. É o que o framework realmente lê pra gerar CSS. Sem ele, não existe Tailwind customizado. Ponto.

Quando basta sozinho

Em projetos onde:

  • Não usa AI agents pra gerar código
  • Time pequeno (1-2 devs) que conhece o config de cor
  • Design system simples (poucas cores, tipografia padrão)
  • Não precisa onboardar gente nova com frequência

Problemas reais sem DESIGN.md

Cenário 1: Novo dev no time

“Qual a diferença entre bg-surface e bg-surface-elevated? Quando uso cada um?”

Resposta do tailwind.config: silêncio. Resposta do DESIGN.md: “Surface para cards padrão, surface-elevated para cards com elevação visual — modals, popovers, tooltips.”

Cenário 2: AI agent gerando página

Prompt: “Crie uma landing page com hero, features grid e pricing cards.”

Sem DESIGN.md: O agente usa text-4xl porque parece certo, mistura font-bold com font-semibold aleatoriamente, usa gap-4 e gap-6 sem critério.

Com DESIGN.md: Hero usa text-5xl font-display font-bold (um por página). Features usa text-3xl font-display font-semibold. Spacing entre seções é py-24. Consistência automática.

Cenário 3: Design system evolui

Mudou a primary de azul pra roxo. No tailwind.config, o valor muda e pronto. Mas e a regra de contraste? E os pairings que funcionavam? E as combinações que agora quebram?

DESIGN.md documenta essas relações. O agente sabe que mudar a primary afeta CTAs, links e headers — e pode ajustar tudo de forma coordenada.


A Relação Correta: Camadas

┌─────────────────────────────────────┐
│         DESIGN.md                    │  ← Semântica, intenção, restrições
│  (consumido por AI + humanos)        │
├─────────────────────────────────────┤
│      tailwind.config.js              │  ← Runtime, valores executáveis
│  (consumido pelo Tailwind CLI)       │
├─────────────────────────────────────┤
│      CSS gerado                      │  ← Output final
│  (consumido pelo browser)            │
└─────────────────────────────────────┘

DESIGN.md não compete com tailwind.config. Ele é a camada acima — a que traduz tokens em intenção. O tailwind.config continua existindo, continua sendo o que o Tailwind lê. Mas o agente lê o DESIGN.md primeiro e depois sabe quais classes do Tailwind usar.


Quando Usar Qual

Use só tailwind.config quando:

  • Projeto pessoal pequeno, sem AI agents
  • Você é o único dev e conhece cada token de memória
  • Design system mínimo (cores da marca + tipografia padrão)
  • Não vai onboardar ninguém no projeto

Use DESIGN.md + tailwind.config quando:

  • Qualquer projeto que usa AI coding agents — que é 90% dos projetos em 2026
  • Time com mais de 1 dev
  • Design system com mais de 10 tokens customizados
  • Precisa de consistência visual entre páginas/componentes
  • Open-source onde contribuidores precisam entender o design

Use DESIGN.md sem Tailwind quando:

  • Projeto usa outro framework CSS (vanilla, CSS Modules, styled-components)
  • Design tokens precisam ser framework-agnostic
  • Migrando de Tailwind pra outra solução

FAQ

DESIGN.md precisa estar sincronizado manualmente com tailwind.config?

Na maioria dos casos, sim — mas não é tão ruim quanto parece. DESIGN.md muda raramente (design system é estável por definição). Quando muda, você atualiza ambos. Existem scripts na comunidade que geram tailwind.config a partir do DESIGN.md, invertendo a direção: o DESIGN.md vira a fonte canônica e o config é derivado.

Se já tenho tailwind.config bem organizado, preciso mesmo de DESIGN.md?

Depende: seu AI agent gera código consistente? Se você pede “crie um card” e o resultado usa tokens errados ou mistura estilos, o config sozinho não está funcionando como documentação. DESIGN.md resolve exatamente esse gap.

Posso gerar DESIGN.md a partir do meu tailwind.config existente?

Sim. O designmd.app oferece geração automática de DESIGN.md a partir de configs existentes. Mas o valor real está em adicionar o rationale — as explicações de por quê — que nenhum script extrai automaticamente do config.

E se uso Tailwind v4 com CSS-first config?

Tailwind v4 move tokens pra @theme no CSS, o que melhora um pouco a legibilidade vs o JS config antigo. Mas o problema fundamental permanece: CSS não carrega semântica de uso, restrições, ou filosofia de design. DESIGN.md continua sendo a camada semântica necessária.

Quantos tokens justificam criar um DESIGN.md?

Se seu tailwind.config tem mais de 5 cores customizadas, tipografia não-padrão, ou espaçamento customizado — já justifica. Na prática, qualquer projeto que personalizou o Tailwind além do default beneficia de DESIGN.md. O custo de criar é baixo (30 minutos), o benefício de consistência é permanente.


Conclusão

tailwind.config.js é infraestrutura. DESIGN.md é comunicação.

Um fala pro Tailwind “gere essas classes CSS com esses valores”. O outro fala pro agente (e pro humano) “use essas classes nesses contextos por essas razões”.

A confusão acontece quando times tratam o config como documentação. Não é. Nunca foi. É um objeto JavaScript que configura um build tool. Tentar extrair intenção de design de um extend.colors.primary.DEFAULT: 'hsl(var(--primary))' é como tentar entender uma receita lendo só a lista de ingredientes sem as instruções.

DESIGN.md é as instruções. E em 2026, com AI agents cozinhando a maioria do frontend, as instruções importam mais que nunca.

Os 461 design systems no designmd.app incluem a maioria dos projetos Tailwind relevantes — e cada um mostra como o wrapper semântico transforma configuração em compreensão.