Há alguns meses escrevi sobre vibe coding e como o que parece mágica na demo se transforma em dívida quando se trata de produção. Este artigo é a continuação natural dessa reflexão, pois desde então mudei bastante a minha forma de trabalhar com Claude Code, e a mudança tem nome: desenvolvimento orientado a especificações.

A ideia não é nova. Pensar antes de construir é a disciplina usual. O que mudou foi o contexto. Quando a programação era cara, o próprio atrito forçava você a pensar. Agora você pede ao Claude Code “faça-me um serviço de notificação” e em vinte minutos você tem duas mil linhas funcionando. Trabalhar pelo case feliz que o modelo imaginou, e não pelo que seu produto precisa. Já experimentei isso várias vezes: protótipos preciosos que tiveram que ser jogados fora porque a IA tomou vinte decisões arquitetônicas que ninguém pediu.

O ponto de viragem para mim foi parar de tratar Claude Code como um preenchimento automático gigante e começar a tratá-lo como ele é: um engenheiro muito rápido e literal que precisa de um briefing decente. Esse briefing é a especificação.

O que é uma especificação (e o que não é)

Uma especificação é um documento markdown que fica no repositório e define três coisas: o que é construído, com quais restrições e como saberemos se está certo. É o contrato entre você e o agente. Antes de solicitar o código, você redige o contrato. Posteriormente, o prompt é reduzido a algo tão simples como "implementar specs/notification-service.md, começar com o despachante".

É importante esclarecer o que não é, porque é aqui que tenho visto mais pessoas tropeçarem. Não é documentação escrita depois do fato para justificar o que já existe. Também não é um PRD de quarenta páginas: uma boa especificação para uma mídia especial ocupa entre 50 e 150 linhas. E não é um prompt longo. O prompt é efêmero, é perdido quando a sessão é encerrada. A especificação persiste, é versionada pelo PR e refinada entre as iterações, assim como o código.

Minha regra mental: se amanhã eu deletar toda a implementação, a especificação deverá me permitir regenerá-la sem perder nenhuma decisão importante. O código pode ser regenerado. O critério, não.

Definindo o contexto: regras e habilidades

Uma boa especificação não viaja sozinha. Para que o agente de IA entenda verdadeiramente o seu ecossistema de desenvolvimento, você precisa definir as regras (regras) globais do projeto e as habilidades ou scripts específicos que ele pode executar (habilidades). Isso é configurado no nível do repositório usando arquivos como AGENTS.md ou a pasta de customizações. Desta forma, Claude Code ou Antigravity conhece as restrições do seu projeto antes de processar o arquivo.

Se você quiser se aprofundar em como funciona esse sistema de regras, como carregá-las e como evitar que o agente aja por conta própria, recomendo a leitura do meu artigo anterior: Como aproveitar melhor o Google Antigravity (sem que o agente trabalhe contra você), onde detalho o uso de customizações, regras e fluxos de trabalho.

Os cinco blocos de uma especificação que funciona

Após meses de iteração no Venturest, minhas especificações convergiram para uma estrutura de cinco blocos.

  1. Contexto e objetivo: qual problema de negócio resolve, em no máximo dois parágrafos. O modelo precisa do porquê para resolver adequadamente as ambiguidades que inevitavelmente permanecerão.
  2. Escopo e não escopo: o não escopo é o bloco mais rentável de todo o documento. É onde você tira a liberdade do agente de “melhorar” coisas que ninguém pediu para ele fazer. Cada linha sem escopo contém centenas de linhas de código que você não precisará revisar ou excluir.
  3. Decisões técnicas fechadas: pilha, serviços, padrões, convenções de nomenclatura. Tudo o que já foi decidido vai para aqui, escrito como fato consumado. Se você escrever como uma sugestão, o modelo irá tratá-lo como negociável.
  4. Comportamento esperado: casos de uso, casos extremos e erros, em tabela ou formato Dado/Quando/Então. Esse bloco é o que Claude Code converte quase literalmente em testes, então o esforço é pago duas vezes.
  5. Critérios de Aceitação: a lista que permite responder sim ou não à pergunta "está terminado?" Se um critério não pode ser verificado, não é um critério, é uma intenção.
Claude Code executando uma especificação de desenvolvimento no terminal.

Exemplo real: serviço de notificação Venturest

Quando construímos nosso serviço de notificação multicanal, a primeira solicitação foi vaga e o resultado foi o esperado: um monólito acoplado ao backend. Na segunda vez que escrevi isto (versão resumida):

# SPEC: serviço de notificação

## Contexto
A Venturest precisa notificar eventos da plataforma (propostas, reuniões,
esclarecimentos, pagamentos) por email, push e in-app. Hoje os e-mails são enviados
inline do back-end, sem novas tentativas ou rastreabilidade. 

## Escopo
- Atendimento desacoplado do backend, orientado a eventos. 
- Canais: email (SES), push (SNS + FCM/APNs), in-app (GW WebSocket API). 

## Fora do escopo
- SEM SMS. NÃO há preferências do usuário nesta fase. SEM painel de administração. 

## Decisões técnicas (fechadas, não propõem alternativas)
- Fila: SQS FIFO como barramento de entrada. DLQ após 3 tentativas. 
- Processamento: Lambda Node.js 20, tamanho de lote 10, 256 MB, tempo limite de 15s. 
- Modelos: Guiadores no S3 (`templates/{type}/{channel}.html|txt`),
armazenado em cache na memória em partidas a quente. Atualize sem reimplantar. 
- História: DynamoDB com TTL de 90 dias. 
- Origens: back-end, EventBridge e webhooks externos são publicados no
mesma fila com um envelope comum. 

## Comportamento esperado
| Caso | Resultado | 
|---|---| 
| Evento válido, canal de e-mail | Template de renderização + envio de SES + cadastro no DynamoDB | 
| O modelo não existe no S3 | Log de erros + mensagem para DLQ, sem nova tentativa | 
| Falha transitória do SES | Tente novamente via SQS (máx. 3) e depois DLQ | 
| Evento duplicado (mesmo ID de desduplicação) | Descartado pelo FIFO, sem efeito | 

## Critérios de aceitação
- [ ] Um evento postado na fila gera notificação em < 30 anos (pág. 95)
- [] Os 3 canais compartilham o mesmo envelope de entrada
- [ ] Teste a cobertura no despachante > 80%
- [] Alterar um modelo no S3 não requer reimplantação

Com esta especificação, Claude Code produziu a infraestrutura, o despachante e os testes em uma única sessão. E o mais importante: sem inventar um canal de SMS ou um CRUD de preferências que ninguém pediu. O bloco sem alcance fez seu trabalho.

Segundo exemplo: Reuniões, quando há um terceiro na equação

O segundo caso me parece ilustrativo por outro motivo: o recurso depende de um provedor externo. Construímos o Venturest Meetings, as videochamadas integradas no contexto de cada projeto, em daily.co. Quando você integra terceiros, a tarefa mais importante da especificação é definir a fronteira entre o seu produto e o fornecedor, porque essa é exatamente a área onde a IA improvisa com mais alegria.

# SPEC: Reuniões de risco (daily.co)

## Contexto
Clientes e parceiros de crescimento realizam reuniões de projeto no Zoom ou Meet,
fora da plataforma. O contexto se perde: o que é falado não está vinculado
ao projeto nem alimenta os Resumos de IA. Reuniões traz a videochamada
dentro do projeto. 

## Escopo
- Crie e participe de videochamadas na visualização do projeto. 
- Gravação e transcrição da sessão. 
- Após a conclusão, resumo do pipeline: resumo, próximas etapas e alertas de escopo
vinculado ao projeto. 

## Fora do escopo
- NÃO são permitidos webinars ou salas com mais de 10 participantes. SEM SDK móvel nativo
nesta fase. NÃO há chat próprio dentro da chamada (Esclarecimentos utilizados). 

## Decisões técnicas (fechadas, não propõem alternativas)
- Provedor: daily.co com pré-construído incorporado (iframe). Não crie UI
própria chamada. 
- As salas são criadas a partir do back-end por meio da API REST do daily.co, sempre
privado, associado a um `project_id`. 
- Acesso somente com token de reunião assinado, gerado pelo nosso backend,
com vencimento. Nunca publique URLs de salas. 
- Webhook `recording.ready` de daily.co aciona o pipeline
transcrição e resumo. A gravação é copiada para nosso S3; 
Não dependemos da retenção de fornecedores. 
- Rastreamento: evento `Reunião agendada` com `account_id`, `project_id`,
`duração_min`, `fonte`. 

## Comportamento esperado
| Caso | Resultado | 
|---|---| 
| Usuário com acesso ao projeto | Token gerado, entre na sala | 
| Usuário sem acesso ao projeto | 403, sem token, sem URL de sala | 
| Token expirado | Acesso negado, opção de regeneração do projeto | 
| Gravação de webhook.pronto | Copiar para S3 + transcrição + resumo no projeto | 
| daily.co desativado ao criar espaço | Erro de usuário controlado, nova tentativa manual | 

## Critérios de aceitação
- [] Nenhuma sala é acessível sem um token assinado pelo nosso backend
- [ ] Sala criada e usuário dentro de < 3s (pág. 95)
- [ ] O resumo aparece vinculado ao projeto após a sessão
- [ ] Queda do webhook não perde gravações (reconciliação diária)

Veja a decisão de acesso. Sem especificações, o modelo provavelmente irá gerar salas com URLs públicas, porque é o caminho mais curto e é isso que mostram os exemplos na documentação de qualquer provedor. É o tipo de buraco que não aparece na demo e que aparece meses depois, quando alguém compartilha um link onde não deveria. A especificação torna essa decisão uma regra explícita antes que exista uma única linha de código.

Erros comuns ao escrever especificações

A primeira é escrever especificações muito abertas. “Use boas práticas” não é uma instrução, é uma oração. Cada decisão que você não toma, o modelo toma por você, e nem sempre na direção que mais lhe convém.

A segunda é não versionar as especificações. Quando o recurso evolui e as especificações ficam para trás, o agente trabalha contra um contrato obsoleto. A especificação fica no repositório e muda para PR, como qualquer outro arquivo.

A terceira é deixar indefinida a fronteira com terceiros. Quando o recurso integra um provedor externo, como acontece com daily.co em Meetings, tudo o que você não definir na especificação será resolvido pelo modelo copiando o quickstart da documentação do provedor. E o início rápido foi projetado para a demonstração, não para o seu modelo de permissões ou retenção de dados.

E a quarta, talvez a mais sutil, é confundir especificação com prompt. A dica é a conversa de hoje. A especificação é o documento que sobrevive à conversa. O prompt aponta, a especificação define.

reflexão de fundo

Há algo quase irônico em tudo isso. A IA devolveu-nos uma disciplina que a indústria vinha minando há anos. Escrever especificações era visto como uma burocracia de outra época, e agora acontece que é a alavanca que separa as equipes que geram código daquelas que entregam produtos.

Minha conclusão após esses meses é que o trabalho do engenheiro sênior não diminuiu, mas mudou. Menos tempo digitando implementação e mais tempo fazendo o trabalho que sempre foi a parte mais difícil: decidir o que construir, o que não construir e como saber se está certo. A IA não tira esse trabalho de você. Ele o coloca na sua frente, em markdown, antes da primeira linha do código.

E na sua equipe? Você escreve as especificações antes de abrir o Claude Code ou continua negociando com o modelo com base nas instruções? Estou interessado em saber como você está resolvendo isso.

NOVO EBOOK GRATUITO

Programar com Inteligência Artificial usando Spec Driven Development

90% dos desenvolvedores já programam com IA e esta é a forma correta de fazer. Baixe o guia completo em espanhol.

Baixar Ebook Grátis
Portada Ebook Programar con IA
Paulo Bischof
Paulo Bischof
CTO · Product Manager · Software Developer
Vamos conversar