Os agentes estavam fazendo exatamente o que eu disse a eles. Esse era o problema.
Eu havia construído um pipeline onde agentes de IA podiam pegar um arquivo de spec, implementar uma funcionalidade, rodar os testes, revisar o resultado e fazer o commit — sem eu escrever uma linha de código. Funcionava na maior parte. Dezenas de funcionalidades entregues. Mas eu ficava revisando o output e sentindo que algo estava errado. Não quebrado. Apenas sutilmente errado de um jeito difícil de nomear.
Passei um tempo culpando os modelos. Depois os prompts. Depois os passos de validação. Por fim tive que encarar o óbvio: os agentes estavam implementando exatamente o que eu havia escrito. Minhas specs estavam subespecificadas. O gargalo era sempre eu, na etapa de planejamento.
A coisa que a maioria das pessoas descarta
Há algo que parece certo no vibe coding. Você opera no nível da intenção — descrevendo o que quer e deixando o modelo lidar com a mecânica. Essa parte é genuinamente útil.
Mas observe o que a maioria das pessoas faz com o output:
Você triturou o fonte e versionou cuidadosamente o binário.
O prompt — sua descrição estruturada do que você queria, por que, e o que "correto" significava — é o artefato valioso. O código gerado é o que compila a partir dele. Quando você descarta o prompt e faz commit só do output, perdeu a coisa que realmente importava.
A consequência prática aparece seis meses depois: você está olhando para um código que escreveu e gastando vinte minutos fazendo engenharia reversa da própria intenção. A spec teria sido uma leitura de trinta segundos.
O que é um pipeline orientado por specs
Construí o que chamo de um harness SDLC (Software Development Lifecycle) — um sistema onde, em vez de escrever código diretamente, você escreve uma spec descrevendo o que precisa ser construído, e agentes de IA cuidam da implementação, testes, revisão e documentação.
A spec é o fonte. O código é o que é compilado a partir dela.
Ideia simples. A parte interessante é descobrir como rodar esse pipeline com eficiência. Cometi alguns erros caros no caminho.
A primeira versão: cara
Meu design original rodava cada tarefa pelo pipeline completo — implement, test, review, document, wrap-up — de forma independente, em ambiente isolado, em paralelo:
No papel: rigoroso. Na prática: cerca de 200.000 tokens por tarefa. Uma spec de cinco tarefas queimava um milhão de tokens antes de eu ver qualquer output integrado.
O desperdício era estrutural. Fases de setup que não variavam entre tarefas rodavam N vezes. Revisões por tarefa só enxergavam as mudanças de uma tarefa — perdiam problemas de integração de qualquer jeito. A documentação rodava em isolamento antes de qualquer coisa ser montada.
E a revisão por tarefa me dava uma falsa confiança: ela capturava problemas dentro de uma tarefa, mas não conseguia verificar se o resultado integrado realmente funcionava. Eu estava pagando por isolamento em tarefas que eram majoritariamente sequenciais.
O que reconstruí
O redesign vem de uma pergunta mais simples: o que realmente precisa de isolamento, e o que pode ser compartilhado?
O passo de implement se beneficia de um contexto novo por tarefa — sem contaminação entre mudanças não relacionadas. Todo o resto — setup, testes, revisão, documentação — pode rodar uma vez sobre o resultado integrado.
Isso produz uma escada limpa de ferramentas:
Escolha o degrau que corresponde ao escopo. Um hotfix trivial não precisa de uma fase de revisão. Uma spec de funcionalidade completa precisa. Múltiplos blocos de funcionalidades independentes rodando em paralelo precisam do orquestrador.
A maior mudança está no orquestrador. A versão original orquestrava tarefas individuais. A versão reconstruída opera no nível de bloco — cada bloco é uma unidade de trabalho do tamanho de uma funcionalidade completa que roda seu próprio pipeline completo em seu próprio branch:
E dentro de cada sdlc-flow, o design enxuto roda um agente de implement novo por tarefa, depois um back-half consolidado sobre o resultado integrado:
Isolamento de agente por tarefa, com o custo aproximado de rodar uma única vez.
Mas o redesign do pipeline não melhorou meus outputs
Mais rápido e mais barato, sim. Resultados melhores, não.
O que melhorou os resultados foi consertar as specs.
Eu estava otimizando a execução enquanto o planejamento ainda era o gargalo. Os agentes liam tarefas subespecificadas, faziam suposições razoáveis e produziam resultados tecnicamente corretos que perdiam a intenção real. Nenhuma quantidade de ajuste no pipeline muda isso.
Você não conserta uma spec ruim com um pipeline melhor.
Como um artefato de planejamento realmente parece
A coisa mais interessante que fiz com este pipeline: usei ele para redesenhar o próprio pipeline.
Aqui está uma versão condensada do master plan que escrevi antes de tocar em uma linha de código. O objetivo era redesenhar todos os quatro engines SDLC — e o pipeline orientado por spec foi a ferramenta que usei para fazer isso:
Algumas coisas valem destacar sobre como essa spec funciona.
A seção de objetivo captura por que isso está acontecendo antes de descrever o que construir. "Dados de uso: quase ninguém usa mais" é contexto essencial — sem isso, um agente poderia preservar compatibilidade retroativa com um comportamento que ninguém usa de fato.
O campo Files é um compromisso, não uma descrição. O agente sabe exatamente quais arquivos tocar e quais deixar em paz. Qualquer coisa não listada está fora do escopo por padrão.
O campo Interfaces / shared surface diz ao agente o que este bloco expõe para os blocos que vêm depois. Esse é o contrato do qual outros blocos dependem — alterá-lo no meio da implementação quebra o trabalho downstream.
O campo Out of scope faz algo que a maioria das specs simplesmente ignora: nomeia as coisas que você não está construindo. Isso importa porque um agente tentando ser útil frequentemente implementa coisas adjacentes que parecem obviamente relacionadas. Entradas explícitas de fora do escopo evitam esse desvio.
E os critérios de aceitação são verificáveis contra o diff. Não "o engine funciona melhor" — "esses símbolos específicos sumiram, este arquivo está commitado, node --check passa." Esses se tornam o checklist exato que a fase de revisão executa.
O teste prático: Você consegue passar esta spec para um engenheiro competente sem contexto prévio e ele construir a coisa certa? Se não, a spec não está pronta — e um agente de IA vai falhar da mesma forma.
Planejar antes de gerar
O fluxo que funciona para mim agora:
A etapa de planejamento é onde as perguntas difíceis acontecem: o que "pronto" realmente significa, quais são as restrições reais, onde estão os casos extremos. É mais barato responder essas perguntas antes de começar a implementação do que depois.
Quando apresso o planejamento, pago com ciclos de revisão. A causa raiz é quase sempre uma tarefa subespecificada — e a correção é sempre "escreva uma spec mais clara", não "use um modelo melhor".
Quando desacelero no planejamento, as implementações geralmente entregam limpas na primeira tentativa.
A habilidade escassa
A habilidade escassa não é escrever código. Não é fazer prompts. É escrever especificações que capturam completamente a intenção — claras o suficiente para que um agente sem estado tome a decisão certa sem fazer perguntas de acompanhamento.
Isso é difícil. Requer pensar nas próprias suposições antes de começar. Requer distinguir entre "tenho uma vaga noção do que quero" e "consigo articular o que quero com precisão suficiente para outra pessoa agir".
Mas transfere. A mesma disciplina que faz uma boa spec de agente faz um registro de decisão de arquitetura melhor, uma descrição de PR mais clara, um documento de design mais útil. Torna você um colaborador melhor, independentemente de a pessoa do outro lado ser humana ou IA.
As ferramentas estão mudando rápido. A habilidade subjacente não.
Comece com a spec.