Quase toda vez que eu vi dar errado com agente de código, o problema não era o modelo. Era eu ter pulado direto pro código sem escrever a spec antes. O agente preenche cada lacuna com um chute, os chutes vão se acumulando, e no terceiro arquivo você está revisando uma coisa que nunca pediu. Este site, os apps desktop e os motores de conteúdo que eu publico foram todos feitos do mesmo jeito, então eu vou te mostrar o loop exatamente como ele roda aqui hoje.
Por que spec primeiro
A spec é o lugar mais barato de errar. Antes de escrever qualquer código, eu escrevo um documento curto dizendo o que vai existir quando o trabalho terminar: as rotas, os componentes, as chaves de texto, os testes que precisam passar e o que fica de fora. Normalmente cabe numa tela só. Não é burocracia, é economia: o agente lê esse documento no começo de toda sessão e já começa no nível de quem conhece o projeto, em vez de tentar descobrir tudo de novo pela árvore de arquivos.
A spec também resolve discussão antes dela acontecer. Se o design é preto e branco, a spec diz isso, e nenhum agente vem propor uma cor de destaque às duas da manhã.
Quebrando o plano em tarefas com teste
A spec vira um plano, e o plano vira tarefas numeradas. Eu deixo cada tarefa pequena o suficiente para terminar numa sessão, e cada uma carrega três coisas: os arquivos que ela pode tocar, os critérios de aceite e o teste que prova esses critérios. Se a tarefa não tem teste, é porque eu vou ter que conferir na mão depois, então ela nem entra na fila.
A checagem é sempre o mesmo comando, e ele é a única definição de pronto:
npm run check && npm run build
Lint, tipos, testes e depois o build de produção. Se essa linha está verde, a tarefa está pronta. Se está vermelha, não está pronta, por mais bonito que o diff pareça.
Agentes em paralelo, cada um na sua worktree
Tarefa que não divide arquivo com outra pode rodar ao mesmo tempo. Eu dou para cada agente a própria worktree do git e a própria branch, nascida da main atual, então ninguém edita o mesmo arquivo e ninguém fica esperando. Um cuida do hero, outro cuida do texto, um terceiro cuida do rodapé. Todos recebem a mesma spec, os mesmos comandos e a mesma regra: só toca nos arquivos que a tarefa nomeia.
Quando uma tarefa termina, a branch faz rebase na main e entra. Os merges são um por vez e pequenos. Só essa disciplina acabou com quase todo conflito que eu tinha antes.
Gates de revisão
Todo merge passa pelos mesmos gates. O comando lá de cima precisa estar verde com a saída colada, não prometida. Um screenshot prova o que o navegador mostra, porque teste passando não quer dizer que a página está certa. E o revisor, seja eu ou um agente, lê o diff contra a tarefa, não contra o repositório inteiro. Se o diff encostou num arquivo que a tarefa não nomeou, volta.
O que quebra
Três coisas que quebraram comigo neste site, e eu prefiro te contar do que deixar você descobrir sozinho.
Hidratação e reduced motion. Um hook que lê prefers-reduced-motion no primeiro render gera um HTML no servidor e outro no cliente, e o React reclama. Eu corrigi renderizando a versão estática primeiro e só trocando depois do mount.
node_modules por symlink com Turbopack. Compartilhar dependência entre worktrees por symlink parecia esperto e quebrou o servidor de dev de um jeito que as mensagens de erro nunca explicaram. Hoje cada worktree instala a sua.
Screenshot sem página aberta. Um agente pediu screenshot pro navegador antes de abrir qualquer página, recebeu uma imagem em branco e reportou o layout como ok. A regra virou: abre, espera, tira o screenshot, e depois olha o arquivo com o próprio olho.
Fechando
Nada disso é sobre confiar menos no modelo. É sobre dar pra ele o que qualquer bom colega de time ia querer também: uma spec clara, uma tarefa que dá para terminar, um teste que diz quando terminou e uma revisão que lê o que ele realmente fez. Faz isso e pode deixar rodar.