Se você já pediu uma tela inteira a um agente de IA e ela veio funcionando, você fez vibe coding. A prática ficou popular porque a primeira hora impressiona: você descreve a intenção em linguagem natural, o agente escreve, você roda, funciona.
O que quase nenhum conteúdo sobre o assunto cobre é a terceira semana. É quando o agente propõe a quarta variação do mesmo bottom sheet, importa o cliente de banco dentro de um componente de UI, e reintroduz uma biblioteca que você tirou do projeto dois meses atrás por travar o scroll no Android. Nada disso é falha do modelo. É falha de contexto.
Este artigo é sobre a camada que separa a demo do projeto que sobrevive: como estruturar o conhecimento de um projeto para que o agente decida certo sem você reensinar as mesmas regras toda sessão. Os números vêm de um app real, o Gaveta, com cinco meses de produção, 726 commits, 38 versões publicadas nas lojas e um desenvolvedor.

O que é vibe coding, de fato
Vibe coding é escrever software descrevendo o resultado em linguagem natural e deixando o agente de IA produzir o código, revisando pelo comportamento em vez de pela leitura linha a linha. O termo se popularizou em 2025 e virou guarda-chuva para tudo que vai do protótipo descartável ao produto em produção.
A confusão útil de desfazer é essa: vibe coding não é um nível de habilidade, é um modo de trabalho. E ele tem duas versões com destinos diferentes.
Na versão descartável, você aceita o código sem contrato. O protótipo é jogado fora na semana seguinte e nada disso importa.
Na versão de produção, o código fica. E aí o custo se desloca: escrever deixa de ser o passo caro, porque o agente escreve rápido. O caro passa a ser que toda sessão começa do zero.

Por que o agente esquece, e por que você também
O agente não sabe por que aquele hook de tela tem um sub-view-model para o sheet. Não sabe que a lib de blur foi trocada porque recompunha a cada frame e travava a lista. Não sabe que a Apple já rejeitou um release por causa de uma palavra na nota da loja.
Você sabe. Mas você também esquece, e daqui a três meses você é uma pessoa diferente lendo o próprio código.
Sem um lugar que responda essas perguntas no momento da decisão, dois desfechos acontecem, e os dois custam caro:
- A arquitetura apodrece por acréscimo. Cada tela nova inventa a própria variante do padrão. No Gaveta, esse processo produziu 31 bottom sheets escritos à mão antes de alguém contar.
- Você vira o compilador humano do agente. Cada PR vira uma sessão de reensinar as mesmas cinco regras. O ganho de velocidade evapora na revisão.
A saída é tratar contexto como artefato de arquitetura, com a mesma disciplina que se aplica a código: fronteiras explícitas, uma fonte de verdade por assunto, e enforcement automático onde couber.

Um documento soberano por fronteira
O primeiro erro previsível é escrever um documento gigante que tenta cobrir tudo. Ele não é lido nem por humano nem por agente: estoura a janela de atenção e vira ruído.
A alternativa é aplicar arquitetura da informação ao próprio repositório. No Gaveta, o documento da raiz tem 212 linhas e abre declarando o que ele não é: ele descreve como os pacotes se conectam, e nunca como codar dentro de um deles. Isso fica com o documento do pacote, e a regra é declarada como inviolável.
A raiz vira uma tabela de roteamento:
| Área onde você vai mexer | Documento soberano |
|---|---|
mobile/** | mobile/CLAUDE.md (1.259 linhas) |
web/** | web/CLAUDE.md (1.853 linhas) |
supabase/** | docs/SUPABASE.md |
| Produto e design | PRODUCT.md e DESIGN.md |
O escopo do documento acompanha o escopo do problema. O menor deles tem 116 linhas e mora dentro da pasta do componente de blur, porque a decisão que ele guarda só importa para quem está escrevendo blur. A raiz não sabe nada sobre blur, e essa ignorância é proposital.
Fecha com a instrução que evita o pior tipo de dano: se a mudança não cabe em nenhum recipe do documento soberano, pare e pergunte, não improvise arquitetura.

Contrato e receituário respondem perguntas diferentes
Cada documento de pacote se divide em duas metades com naturezas distintas.
O contrato responde "o que eu não posso fazer". São princípios, uma tabela de camadas, convenção de nomes e a lista de regras de lint. Cabe em poucas seções porque regra que não cabe não é seguida. A tabela de camadas do Gaveta tem cinco linhas e responde noventa por cento das perguntas de "onde isso vai":
| Camada | Pode | Não pode |
|---|---|---|
| Serviço | async puro, banco, RPC, fetch | Hooks React, JSX |
| Hook de dados | Chave de cache via registro central, invalidações | JSX de página |
| Hook de tela | Agregar hooks, navegação, derivar view model | Importar o cliente de banco direto |
| View | Props tipadas, JSX | Query, mutation, acesso a dados |
| Rota | const vm = useXScreen() e renderizar a View | Lógica de negócio, query inline |
O receituário responde outra coisa: "como eu faço o que preciso agora". São passos numerados para criar feature do zero e um cookbook de padrões que já se repetiram, cada um com link para o exemplo real no código.
E o cookbook cresce por repetição, não por antecipação: um padrão só entra depois de aparecer em dois lugares. Cookbook antecipado vira enfeite.
O detalhe que mais economiza tempo é uma tabela de "olhe esta feature como referência", ligando cada tipo de trabalho a um arquivo existente. Documentação que aponta para o código real envelhece melhor que documentação que descreve o código real.

Regra sem lint é sugestão
Todo documento normativo tem um inimigo: o terceiro PR. Na primeira feature você segue a regra, na segunda também, na terceira você tem pressa e o documento não reclama.
O lint reclama. No Gaveta, quatro coisas quebram o build em nível de erro: cliente de banco e biblioteca de cache importados na camada de rota ou em qualquer View, chave de cache escrita como literal fora do registro central, e modal escrito à mão em vez do primitive compartilhado.
A parte que faz diferença está na mensagem de erro. Ela não só proíbe, ela ensina a saída: "bottom sheet não se escreve à mão, use o primitive, que já traz arrastar-para-fechar, safe area, teclado e tokens".
Vale a mesma lógica para o design system. Tokens documentados em prosa são sugestão. Tokens documentados com uma regra que proíbe hex literal em JSX são contrato. A diferença aparece no terceiro mês, quando existem quarenta telas em vez de quatro.

O documento que admite não ser verdade ainda
A parte mais útil dessa estrutura é a mais desconfortável de escrever.
O documento da web do Gaveta abre dizendo que é a arquitetura-alvo, não o estado atual: parte do dashboard ainda tem acesso a dados dentro da página, strings hardcoded e cache artesanal. E publica o plano de fases em vez de fingir que as regras já valem, com fase 0 sendo o que está de fato ativo no lint hoje.
Isso muda o comportamento de quem lê, humano ou agente. Um documento que afirma cem por cento de conformidade faz o agente copiar o legado achando que é o padrão. Um documento que nomeia a dívida faz o agente perguntar antes de copiar.

Toda regra carrega a cicatriz que a gerou
Rastreando o histórico do Gaveta, cada mudança normativa aparece logo depois de um incidente:
- 28 de julho. A Apple rejeitou a versão 1.5.2 por metadados imprecisos. A causa foi uma linha da nota de novidades que começava com "Android:", porque o mesmo arquivo alimenta as duas lojas. A regra que entrou não é conselho, é comando verificável: antes de commitar, um
grepprocurando por nomes de plataforma tem que voltar vazio. E carrega o motivo: custou um ciclo de review inteiro por causa de uma palavra. - 31 de agosto. Um link de teste no splash subiu visível em produção. Virou item de checklist de release, com a condição explícita de confirmar que ele está dentro do bloco de desenvolvimento antes de buildar.
- 22 de julho. Os 31 bottom sheets viraram um primitive só, num commit de 41 arquivos. A regra de lint que proíbe modal à mão nasceu no mesmo dia. Sem ela, o sheet número 32 apareceria em duas semanas.
O padrão é o mesmo nos três casos: a regra é escrita depois da dor, e o texto carrega a dor junto. É isso que a faz sobreviver. Regra sem história vira burocracia que a próxima pessoa com pressa remove. Regra que diz "isso custou um ciclo de review da Apple" ninguém remove.

O insight da Otther: contexto é entregável, não subproduto
Quando a Otther entra num produto que já roda com time e agente, a primeira coisa que medimos não é cobertura de teste nem dívida de código. É quanto tempo alguém leva para tomar a decisão certa sem perguntar a outra pessoa. Esse número prevê velocidade melhor que qualquer métrica de output.
O que aplicamos, em ordem:
- Mapear as fronteiras antes dos padrões. Quem decide o quê, e onde essa decisão mora. Sem isso, todo documento vira depósito.
- Escrever o contrato curto e o receituário longo. O contrato precisa caber na cabeça. O receituário pode ser extenso, porque é consultado, não memorizado.
- Amarrar cada regra normativa a uma linha de lint. As que não têm, marcar como aspiracional e publicar o plano de fases. Regra sem enforcement é sugestão.
- Amarrar manutenção ao fluxo, não à boa vontade. "Evento novo entra neste documento no mesmo PR que instrumenta" funciona. "Manter o documento atualizado" não funciona.
O mesmo raciocínio vale para o handoff entre design e engenharia, e explica por que tanto handoff falha: quando o documento de spec repete os valores do design system em vez de citá-lo, ele nasce desatualizado. Handoff que aponta para a fonte sobrevive ao primeiro ajuste de token.

A conta honesta
Esse método tem preço, e ele aparece no histórico. Dos 726 commits do Gaveta, 146 tocam algum arquivo markdown, e 31 deles não tocam em mais nada. Um em cada cinco commits mexe em texto que ninguém compila.
Os documentos também acumulam dívida. Um diagrama na raiz ainda diz "33 migrations" quando a pasta tem 105, porque o número entrou em maio dentro de um bloco que ninguém revisita. E as frases sobre "CI bloqueia merge" descrevem intenção, porque o lint roda na máquina do desenvolvedor, não num runner. O sistema envelhece exatamente onde não tem enforcement, como ele mesmo prevê.
O que a conta compra: abrir o repositório depois de duas semanas fora, num pacote que você não tocou, e entregar uma feature sem reconstruir o modelo mental. O agente também. Cinco meses, 38 releases, e a camada de arquitetura continua com cache centralizado, rotas de seis linhas e View sem acesso a dados, porque o lint não deixa passar.

Conclusão
Vibe coding não falha por causa do modelo. Falha porque o conhecimento que justifica cada decisão do projeto mora na cabeça de alguém, e nem essa pessoa nem o agente têm acesso a ele na hora em que a decisão acontece.
A pergunta que resolve isso não é qual ferramenta usar. É onde cada tipo de conhecimento mora, quem é dono dele, e o que acontece quando alguém viola a regra. Responder isso com markdown, ADRs, design system ou handbook é detalhe de formato. O que não muda é o teste: quando a próxima sessão precisar decidir, ela vai encontrar a resposta no lugar onde vai procurar?
Se o seu time está ganhando velocidade com IA e perdendo consistência de produto na mesma proporção, é esse o problema. Fale com a Otther sobre como estruturar a camada de contexto do seu produto.

