Quase todo time que trabalha com agentes já passou por isso: você escreve uma spec que parece razoável, o agente executa, e o que volta não é bem o que você pediu. Não é código quebrado, é código sutilmente errado. Um campo a mais, um fluxo que ninguém autorizou, uma decisão arquitetural tomada no meio do caminho. Aí começa o retrabalho: revisar, apontar, pedir ajuste, e esperar que agora vá.
O reflexo é culpar o modelo. Na maior parte das vezes, não foi ele. Uma spec para agente não é descrição, é restrição. É o menor conjunto de limites que permite executar sem reinterpretação. A maior parte das falhas do tipo “o agente fez coisa estranha” é falha de spec, não de modelo. Este post é sobre o que uma spec precisa ter, o que ela precisa deixar de fora, e como saber que ela está pronta antes de rodar o agente.
Por que a spec narrativa falha#
A spec narrativa é o formato mais comum, e o mais perigoso. Ela descreve a feature em parágrafos, conta a história do usuário, explica o contexto de negócio, e em algum lugar no meio disso diz o que precisa ser feito. Em contexto humano, funciona. Um sênior lê, preenche as lacunas com bom senso e segue. Um agente lê tudo como sinal e tenta honrar tudo igualmente.
O problema é que prosa e restrição competem pelo mesmo espaço. Quando você escreve “seria bom ter um feedback visual”, o agente trata como requisito. Quando você escreve “idealmente sem adicionar dependências”, ele trata como preferência opcional. Não há um jeito confiável de dizer “isso é obrigatório, isso é decoração” sem marcar explicitamente.
O outro problema é que narrativa esconde a decisão real. Muitas specs parecem completas até você tentar responder a pergunta: qual decisão concreta essa spec está pedindo?. Se a resposta exige reler três parágrafos e inferir, já está ambígua para um agente.
O que uma spec mínima precisa conter#
Vou listar o núcleo, sem cerimônia. Se um item está faltando, a spec vai gerar retrabalho com probabilidade alta.
Decisão concreta. Uma frase, no imperativo, dizendo o que o agente vai entregar ao fim da execução. Não “melhorar o fluxo de login”, mas “adicionar verificação por e-mail no cadastro de novos usuários usando o provedor já configurado”. A diferença é que a segunda versão não admite duas interpretações razoáveis.
Acceptance criteria verificáveis. Cada AC precisa ter um jeito mecânico de checar se foi atendido. Given/When/Then funciona bem, SHALL/DEVE funciona bem, texto solto verificável manualmente também resolve. O que não funciona é AC do tipo “o fluxo deve ficar intuitivo”. Intuitivo para quem, medido como, verificado por qual teste?
Non-goals explícitos. Aqui está a parte que mais gente esquece. Non-goal é o que a spec está conscientemente deixando de fora. “Não adicionar novos endpoints”, “não mexer no schema de users”, “não alterar o fluxo de logout” são non-goals. Sem essa camada, o agente decide o escopo sozinho, e quase sempre decide a mais.
Target files. Os arquivos que vão ser tocados, nomeados. src/auth/email-verification.ts, src/auth/routes.ts, tests/auth/email-verification.test.ts. Não “o módulo de auth”, não “onde fizer sentido”. Quando a lista de arquivos não é óbvia, isso é sinal de que a spec ainda está abstrata demais e precisa voltar um passo.
Restrições técnicas críticas. Tudo que vai levar a revisão se for ignorado: versão de dependência, padrão de erro que o projeto segue, contrato de tipo, limites de performance, requisito de compatibilidade. Não é o lugar para listar o style guide inteiro, que já mora na constituição do projeto. É o lugar para restrições específicas daquela tarefa.
O que deixar de fora#
Tão importante quanto o que entra é o que não entra. Uma spec enxuta evita:
- Histórico de discussão. Debate sobre alternativas vira ruído. Se uma alternativa foi descartada e a razão importa, vira um ADR (architecture decision record) curto. Se não importa, some.
- Justificativa de produto longa. O agente não precisa da motivação de negócio para executar. Precisa da decisão. Motivação longa dilui o sinal.
- Exemplos de código tentativos. Snippet “para dar uma ideia” quase sempre vira snippet que o agente copia literalmente, inclusive os erros.
- Instruções genéricas do projeto. Convenção de nomes, estilo de commit, regra de teste já estão na constituição. Repetir polui o prompt e aumenta chance de contradição silenciosa com o documento canônico.
- Preferências decorativas. “Seria legal se”, “idealmente”, “se possível”. Ou é requisito, ou não está na spec.
A regra operacional é: cada linha da spec deveria mudar o que o agente faz. Se não muda, não entra. É a mesma lógica de orçamento de contexto do post anterior, aplicada ao artefato da spec em vez do prompt como um todo.
O teste operacional: two agents, same output#
Existe um teste mental que vale mais que checklist comprido. Antes de rodar, pergunte:
Dois agentes diferentes, com a mesma spec e o mesmo contexto, produziriam saídas funcionalmente equivalentes?
Se a resposta é não, a spec está subespecificada. Alguma decisão ainda mora na cabeça de quem escreveu. Em vez de mandar o agente executar, vale gastar cinco minutos deixando essa decisão explícita.
Esse teste captura o que checklist tradicional não captura. Uma spec pode ter todos os campos preenchidos e ainda falhar no teste, porque os campos estão vagos. Pode ter muito menos que o formato completo e passar, porque cada campo é preciso.
“Funcionalmente equivalente” aqui quer dizer que o comportamento observável é o mesmo. Nomes internos diferentes, estrutura de diretório diferente, ordem de parâmetros diferente, tudo isso é aceitável. O que não é aceitável é um agente tratar um campo como obrigatório e outro como opcional.
Falhas comuns de spec#
Quatro padrões aparecem com frequência suficiente para valer nome próprio. Todos são editáveis em minutos quando você reconhece o padrão.
Spec narrativa em vez de restritiva. A spec conta uma história em vez de definir limites. Correção: extrair a decisão em uma frase imperativa no topo, mover o resto para contexto opcional ou descartar.
AC sem verificabilidade. “Experiência fluida”, “comportamento esperado”, “funciona bem”. Correção: para cada AC, escrever a checagem concreta. Se a checagem não existe, o AC não existe.
Non-goals implícitos. O autor sabe o que está fora de escopo, mas não escreveu. Correção: listar três a cinco non-goals antes de enviar. Quase sempre o primeiro que aparece na cabeça é o mais importante.
Decisão escondida em prosa. A spec parece completa, mas a decisão real está diluída em dois parágrafos. Correção: se você não consegue apontar a frase que contém a decisão, a decisão não está na spec.
Um exemplo antes e depois#
Imagine que a tarefa é adicionar verificação de e-mail no cadastro. Uma spec comum ficaria parecida com isso:
Precisamos melhorar a segurança do cadastro. Hoje o usuário consegue
criar uma conta com qualquer e-mail, inclusive de domínios temporários
ou digitado errado, o que tem gerado problemas de suporte. Seria bom
ter uma verificação por e-mail, idealmente usando algo que a gente já
tenha configurado. O fluxo deve ser intuitivo e não atrapalhar a
conversão. Se possível, considerar também o caso do OAuth. Vale
avaliar se faz sentido bloquear funcionalidades antes da verificação.
Parece razoável. É péssima para um agente. A decisão está escondida em “seria bom ter”, tem três coisas opcionais sem marca clara, dois gatilhos para o agente expandir escopo (“considerar OAuth”, “avaliar bloqueio”), nenhum AC verificável, e nenhum arquivo-alvo.
A mesma tarefa reescrita como restrição:
decisao: >
Adicionar verificação por e-mail ao cadastro de novos usuários
usando o provedor de e-mail já configurado em src/email/provider.ts.
acceptance_criteria:
- Dado um cadastro com e-mail válido, quando a conta é criada,
então um e-mail de verificação com token é enviado.
- Dado um token de verificação válido, quando o endpoint de
confirmação é chamado, então o usuário é marcado como verificado.
- Dado um token expirado ou inválido, quando o endpoint de
confirmação é chamado, então a resposta é 400 com erro genérico.
- Usuários existentes na base continuam funcionando sem verificação.
non_goals:
- Não alterar fluxo de OAuth.
- Não bloquear acesso a funcionalidades de usuários não verificados.
- Não adicionar reenvio de verificação nesta story.
- Não mexer no fluxo de logout ou recuperação de senha.
target_files:
- src/auth/email-verification.ts (novo)
- src/auth/routes.ts (adicionar rota de confirmação)
- src/users/user.model.ts (adicionar campo verified_at)
- tests/auth/email-verification.test.ts (novo)
restricoes:
- Token precisa expirar em 24h.
- Mensagens de erro seguem o padrão de src/errors/http-errors.ts.
- Sem adicionar dependências novas.
A segunda versão é mais curta, mais chata de ler, e muito menos ambígua. Dois agentes diferentes entregariam resultado equivalente. A primeira versão entregaria duas features diferentes dependendo do humor do modelo.
Repare que esse formato não depende de DSL de nenhum produto específico. É texto estruturado. Pode virar YAML, markdown, campo em uma ferramenta de story, o que funcionar no seu fluxo.
Spec é habilidade de edição, não de escrita#
Escrever spec longa é fácil. Escrever spec enxuta é difícil pela mesma razão que um parecer curto é difícil: cada palavra precisa ter função. Na prática, uma boa spec quase sempre passa por duas ou três versões, e cada versão remove coisa.
A primeira versão tende a misturar tudo. A segunda versão separa decisão de contexto e marca os non-goals. A terceira versão corta metade do que não muda o comportamento. Quando você começa a remover e o teste dos dois agentes continua passando, a spec está pronta.
Cinco minutos editando uma spec evitam horas revisando uma PR. O investimento é desproporcionalmente bom.
Fechando#
Contexto e spec são duas dimensões diferentes do mesmo problema. Contexto responde “o que o agente vê”. Spec responde “o que o agente precisa decidir”. As duas juntas são a base do trabalho com agentes. Prompt inflado com spec ambígua é a combinação que mais gera retrabalho. Contexto mínimo com spec restritiva é a combinação que mais se paga.
Se der para levar uma coisa deste post: da próxima vez que você for rodar um agente, antes de apertar enter, leia a spec e pergunte em voz alta “dois agentes produziriam a mesma saída?”. Se a resposta não é um sim direto, edite a spec primeiro. É o movimento com melhor retorno por minuto investido que existe no fluxo com agentes.
Referências#
Addy Osmani — How to Write a Good Spec for AI Agents.
BMAD Method — referência prática de handoffs guiados por spec.

Comentários
Os comentários usam Disqus e só são carregados se você clicar no botão abaixo.