Back to blog
13 min read

Construi um design system open source em dois dias com Claude Code. E não foi vibe coding.

Como transformei intenção de produto em um DS brutalista funcional usando skills, memoria persistente e subagentes. O metodo, os ganhos e por que o julgamento de product designer continua sendo o trabalho.

Como transformei intenção de produto em um DS brutalista funcional usando skills, memoria persistente e subagentes. O metodo, os ganhos e por que o julgamento de product designer continua sendo o trabalho.

O que existe hoje no github.com/thiagoxikota/touch-grass

Dois dias atrás esse repositório não existia. Hoje ele tem:

Um pacote de tokens construido em cima do Style Dictionary 4 que emite CSS variables, um @theme block de Tailwind v4, JSON no formato W3C Design Tokens pro Figma e constantes Swift pro iOS consumir via SPM. Um pacote de componentes React 19 com dez primitives (Button, Input, Badge, Card, Tag, Divider, Stat, Timer, Checkbox, Switch) e oito patterns (LeaderboardRow, FocusTimerDisplay, BeRealStamp, PatternInterruptModal, SessionSummaryCard, Sparkline, Toast, Field), todos com forwardRef, todos com token-only colors, todos cobertos por Vitest + React Testing Library + Playwright Component Testing - 17 suites verdes. Um docs site em Vite + React 19 com oito páginas de foundations (color, typography, spacing, borders, grid, motion, states, brand), dez de primitives e oito de patterns, todas rodando os componentes reais ao vivo. Um Package.swift na raiz pra expor os tokens como pacote SPM. Licenca MIT, CHANGELOG, CONTRIBUTING escrito com as regras brutalistas na cara do colaborador, CI rodando no GitHub Actions. Primeiro release tagueado v0.1.0, segundo v0.1.1 com suporte a subpath, terceiro v0.1.2 com o docs refresh completo.

Esse DS serve de base pra Timeouts, o app iOS de academia social pra tempo fora do celular que eu estou construindo. Mas a história interessante não é o que tem no repo. É como ele apareceu la.

Por que um DS, e por que brutalista

Eu poderia ter usado shadcn/ui e ter um app de pé na mesma tarde. Não seria errado. Seria generico. E Timeouts não é um produto generico - é uma proposta contra o modelo dominante de app de "foco" (bloquear, envergonhar, fazer arvorezinha morrer). Um DS brutalista com zero cantos arredondados, zero texto cinza, zero motion, Geist Mono em todo lugar que conta, era a forma de transformar a tese do produto em forca visual. Restricao como decisão.

O brutalismo aqui não é estética. É forcing function. Quando o DS proibe border-radius, proibe text-gray-500, proibe transition-all, o designer para de simular comodidade que não está la. O produto fica mais honesto porque o sistema não deixa ele mentir.

Essa é a primeira coisa que AI-driven workflows não sabem fazer sozinhos: escolher o que o produto deveria ser. O Claude não decide que você vai fazer um DS brutalista. Você decide. O Claude ajuda a executar.

O metodo: não é autocomplete, é sistema operacional

Existe uma diferença entre tratar IA como autocomplete inteligente e tratar IA como sistema operacional pro trabalho de design. Autocomplete te deixa digitar mais rápido. Sistema operacional muda o que você pode fazer no tempo que tem.

O Claude Code, que é o terminal que eu uso, tem três conceitos que juntos viram esse sistema operacional:

  1. Skills. Workflows nomeados que encodam como fazer algo específico. Eu tenho skills como touch-grass-component (que sabe o lockstep de 6 arquivos pra adicionar um primitive), touch-grass-figma-bridge (que sabe as limitacoes do Plugin API do Figma que já mordi antes), touch-grass-brand-asset (que sabe o pipeline de SVG → token compliance). Cada skill é conhecimento procedural destilado. Não é prompt esperto - é metodo.

  2. Memoria persistente. Um diretório onde eu gravo o contexto do usuário (quem é, como prefere trabalhar), do projeto (decisões, por que), e do feedback (o que não deve se repetir). Cada conversa nova comeca com esse contexto já carregado. Eu não preciso re-explicar, a cada sessão, que o Timeouts não é focus timer - é sim Strava pra tempo fora do celular. Uma vez que eu disse, ficou.

  3. Subagentes. Sub-processos do Claude que fazem tarefas paralelas sem poluir o contexto principal. Quando eu preciso de uma busca larga em codebase, uma revisão de código, uma exploração de docs - eu delego. O contexto principal fica limpo pra decisão, não pra busca.

Junte os três e você tem uma forma de trabalhar onde você mantem o julgamento, o design intent, o criterio de qualidade, e delega a parte mecânica. Product designer continua fazendo product design. A IA vira o assistant técnico que nunca se cansa.

O loop, em quatro passos

Eu não escrevi nenhuma linha de código do touch-grass na bala. Cada feature passou por um loop de quatro etapas. Esse loop é o que separa trabalho assistido por IA de vibe coding:

1. Brainstorming. Antes de qualquer código, uma conversa. O que estou tentando fazer, quais são as restricoes, quais abordagens existem, qual eu escolho e por que. Essa etapa não gera código, gera um documento de spec curto (três a dez parágrafos). O spec fica versionado em docs/superpowers/specs/. Se o spec está errado, o código vai estar errado - melhor descobrir antes de escrever.

2. Planning. Pega o spec e transforma em uma lista de tarefas com dependencias explicitas. Essa etapa revela o que eu não tinha pensado - "pra adicionar o Button eu preciso antes do cn() helper, do base.css, do token pipeline funcionando". O plano fica em docs/superpowers/plans/. Claude o usa pra se auto-dirigir depois.

3. Test-driven execution. Cada componente comeca pelo teste. O Vitest test do Button foi escrito antes do JSX do Button. Isso parece dogma, mas tem razao prática: quando IA escreve código, a única prova de que fez certo é o teste passar. Sem teste, todo código assistido por IA é uma promessa sem garantia.

4. Code review. Depois da execução, um agent específico (superpowers:requesting-code-review) le o diff, compara com o spec, aponta tudo que não bate. Não sou eu, não é o mesmo contexto, é uma terceira voz cetica. Se passa nessa revisão, commit. Se não, volta.

Os quatro passos são ritual. Todo componente, toda feature, todo fix grande. O loop não é burocracia - é o que garante que cada commit adiciona algo verificavel ao repo, não uma aproximacao.

Um exemplo concreto: o Button

O Button foi a primeira primitive. A conversa com Claude comecou assim:

Eu: "adicionar um Button brutalista, três variants (primary, ghost, danger), cinco states (default, hover, focus, disabled, loading), 48px tap target mínimo, uppercase mono, loading state usa block characters não spinner."

Claude: disparou o skill touch-grass-component, que injetou no contexto o lockstep de seis arquivos que eu tinha escrito antes. Depois abriu brainstorming: "confirma que ghost não tem hover background, so border color flip?". Eu confirmei. "Danger deve ter hover? Parece contraditorio com a semântica." Bom ponto. "Não, fica estático." OK.

Saiu o spec. Saiu o plano. O plano virou uma lista de TODOs. O primeiro TODO foi o teste:

describe('Button', () => {
  it('renders with primary variant by default', () => {
    render(<Button>START</Button>);
    expect(screen.getByRole('button')).toHaveClass('bg-earned', 'text-bg');
  });
  // ...mais 7 cases
});

Teste antes do componente, vermelho. Depois o componente, verde. Depois a demo page, a barrel export, a rota no docs site. Depois o code-reviewer agent rodou e apontou que eu tinha esquecido de definir o type="button" default (clicks dentro de form submetiam). Fix, teste novo, verde de novo. Commit.

Tempo total: 20 minutos. Isso inclui a conversa, o teste, o componente, a demo, o review, o commit. Um Button que faz sentido, coberto por 8 testes, documentado numa página ao vivo, que segue as mesmas regras brutalistas que todos os outros vao seguir. Não é vibe coding. E engenharia de produto com IA fazendo o trabalho manual.

O que a memoria salva

No segundo dia, enquanto eu estava construindo a landing do timeouts.app, Claude comecou a escrever copy tipo "focus timer that rewards stepping away" e "earn your screen time". Eu parei: "Timeouts não é focus timer. E academia social pra tempo fora do celular. Comprovantes por foto, leaderboard com seus amigos, IA coach olhando seus padrões. Por favor não esquece isso nunca mais."

Claude salvou uma memoria marcada como project no diretório de memoria:

Timeouts core concept. Strava/gym-rats for time OFF the phone. Social proof, photo proofs, group competition, AI coach. NOT a focus timer. NEVER frame as "earn screen time" or "block apps".

Essa memoria entra no contexto toda vez que eu abro uma nova conversa nesse projeto. Uma licao aprendida. Ao contrario de um PDF de brand book que ninguém le, essa memoria é consultada por quem vai escrever cada linha seguinte. O erro de posicionamento não se repete porque o sistema impede a repeticao.

Esse é um ganho que eu não tinha antes de usar memoria persistente: o contexto do produto fica com você como equipe, não na sua cabeca como indivíduo. Cada sessão nova comeca informada, não em branco.

Subagents em paralelo: como economizar o contexto principal

Quando eu estava escrevendo o README matador pro launch público, eu precisava de três coisas ao mesmo tempo: screenshots do docs site rodando local, revisão de linguagem do README, e um inventario do que já existia no repo pra eu não prometer o que não tem. Em vez de rodar tudo sequencial poluindo o contexto, eu despachei três subagents em paralelo:

  • Um agent com Playwright pra rodar pnpm dev, tirar screenshots de três páginas e salvar.
  • Um agent de code review pra ler o rascunho do README e apontar trechos genericos.
  • Um agent de exploração pra mapear o que tem em packages/ds/src/ e packages/docs-site/src/pages/.

Os três rodaram juntos. Cada um voltou com um relatorio conciso. Eu consolidei. Isso não é um detalhe - é o que torna o contexto principal focado em decisão e não em busca. Se eu tivesse feito os três sequenciais, o ruido de saida teria empurrado decisões importantes pra fora da janela de contexto.

Design é 80% decidir e 20% executar. Subagents te devolvem o 20%.

O que o product designer continua fazendo

Nada disso funciona sem julgamento de produto. Olha cada passo e me diz quem decide:

  • Fazer um DS em vez de usar shadcn → produto. Eu.
  • Fazer brutalista em vez de soft → produto. Eu.
  • Button tem cinco states ou três → produto. Eu.
  • Ghost variant tem hover fundo ou so border → produto. Eu.
  • Timeouts é academia social e não focus timer → produto. Eu.
  • Landing do timeouts.app não pode usar "earn screen time" → produto. Eu.
  • Tokens são fg/bg/earned e não ink/primary → produto. Eu.

O Claude escreveu praticamente todo o código. Não escreveu nenhuma das decisões. Eu mantive o julgamento em cada ponto de decisão e deleguei a execução. Esse é o truque. Product designers que vao sobreviver a IA não são os que digitam mais rápido. São os que tem gosto forte e direcao clara o suficiente pra guiar maquinas de execução sem perder identidade no meio do caminho.

O que eu não faco

Pra ser justo com o metodo, preciso dizer o que ele evita:

Não faco spec-less sprints. Nunca peco código sem antes ter uma conversa de brainstorming, por mais simples que seja a tarefa. Simples é exatamente onde premissas erradas fazem estrago.

Não deixo IA rodar sem teste. Código sem teste é promessa. Promessa não merece commit.

Não aceito sugestão por autoridade. Quando o code reviewer aponta algo que parece errado, eu investigo e respondo com evidencia, não concordo so porque veio de outro agent. IA tem confiança estatistica, não tem razao.

Não acumulo tech debt por pressa. Cada decisão de arquitetura que eu tomo agora vira restricao do futuro. Se eu deixo um atalho sujo no Button, cada primitive depois herda a sujeira. Claude respeita a arquitetura que você estabelece - não cria arquitetura sozinho.

Não uso IA pra desenhar em vez de mim. Eu ainda faco wireframe. Eu ainda faco audit de acessibilidade. Eu ainda penso em hierarquia, densidade, ritmo. IA não substitui essas decisões - ela as documenta em código depois que eu as fiz.

Use cases reais que eu rodo como product designer

Deixando o touch-grass de lado, essas são as coisas que eu uso IA pra fazer no dia a dia do meu trabalho de produto:

Síntese de entrevistas de usuário. Jogo as transcricoes, peco categorias por frequencia e intensidade, Claude mapeia pain points recorrentes e cita as falas textuais. Depois eu valido a mao e descarto o que não bate com o que eu ouvi ao vivo. Economia de tempo: horas. Risco: baixo se você le as citacoes.

Leitura profunda de PDFs densos. Paper academico, regulacao do governo, spec de API de terceiros. Eu rodo pelo Gemini Pro primeiro (melhor em contexto longo), peco um sumario executivo e uma lista de decisões que preciso tomar. Depois leio so as partes relevantes. A alternativa é ler tudo ou não ler nada - ambas ruins.

Audit de copy. Cola todo o texto de uma tela, peco pra apontar: ambiguidade, jargao, passos cognitivos ocultos, termos que não batem com o glossario do produto. IA acha padrões que eu passo batido porque eu escrevi o texto e meu olho cega.

Geração de variantes pra teste A/B. A decisão de QUAL hipotese testar é minha. A geração das três redacoes da mesma hipotese com framings diferentes é mecânica - delego.

Conexao Figma ↔ código. Skill próprio que encoda o Plugin API do Figma. Quando eu mudo um token, rodo uma skill que atualiza variaveis no Figma, rebinda componentes, valida com screenshots. O que antes custava uma tarde de trabalho sujo vira um comando.

Revisão de acessibilidade. Audit WCAG automático via skill a11y-audit que roda o Playwright, checa contrast ratios reais, navega por teclado, testa com screen reader simulado. IA não substitui o teste com usuário real com deficiencia - mas cobre os 80% de erros basicos antes de chegar la.

Prompting pra outras IAs. A parte meta. Quando preciso gerar mockup em Lovable, Figma Make, Paper.design - uso um skill dedicado que transforma briefing de produto em um prompt longo e estruturado pro gerador. O output de outra IA é so tao bom quanto o prompt de entrada.

A licao que vale levar

O mito da IA substituindo designer é o de uma maquina que desenha sozinha. Não é o que acontece em alta performance. O que acontece em alta performance é um designer com gosto forte, direcao clara e um sistema de trabalho onde IA faz a execução mecânica enquanto ele mantem o julgamento. O caro ficou caro. O mecânico virou commodity.

Um DS brutalista pronto em dois dias não é milagre. É método. Skills que encodam processo, memoria que preserva contexto, subagents que protegem foco, testes que validam execução, revisão que garante qualidade. Nada disso substitui você decidir que Timeouts é academia social e não focus timer. Nada disso substitui você escolher brutalismo como tese visual. Nada disso substitui você saber que um Button precisa de 48px de tap target porque pessoas com tremor não acertam 40px.

Tudo isso substitui a parte do seu trabalho que você não devia estar fazendo de qualquer forma.


O código está em github.com/thiagoxikota/touch-grass. O landing do produto está em timeouts.app. Os docs vivos estão em timeouts.app/touch-grass. Se algum dos dois parece cru pra você agora, é porque é - o segundo dia é o comeco, não o fim. O metodo continua rodando.

Design SystemClaude CodeAI WorkflowsProduct DesignBrutalismTouch Grass

Made withbyThiago Xikota