spec.md: anatomia e template pronto para agentes de código

Um spec.md bem estruturado define se o agente de código vai entregar exatamente o que você pediu ou se vai inventar requisitos pelo caminho. Neste artigo, você vai dissecar um modelo completo, seção por seção, e entender por que cada parte existe.
Ao final, você terá um template pronto para copiar, adaptar e usar com GitHub Copilot, Claude Code, Cursor ou qualquer outro agente.
Por que o spec.md funciona como contrato do agente
Agentes de código trabalham com o contexto que recebem. Por isso, quando a instrução chega vaga, o modelo preenche as lacunas com suposições plausíveis, mas nem sempre corretas.
O desenvolvimento orientado a especificação inverte essa lógica. Em vez de conversar com o agente até o código ficar aceitável, você escreve primeiro um documento estruturado e o trata como fonte da verdade.
Se você ainda não conhece a abordagem, vale ler antes o artigo sobre o que é spec driven development e como aplicar. Ele explica o fluxo completo, enquanto este texto foca em um único artefato.
No GitHub Spec Kit, o spec.md ocupa o centro do processo. Ele nasce no comando /speckit.specify e, em seguida, alimenta o plan.md e o tasks.md.
Além disso, a especificação descreve o quê e o porquê, nunca o como. Framework, banco de dados e bibliotecas ficam para o plano técnico, que vem depois.
Essa separação tem um motivo prático. Se a tecnologia mudar, o mesmo spec.md continua válido, porque ele fala de comportamento e não de implementação.
Em outras palavras, o documento funciona como um contrato. O agente lê, implementa e depois volta a ele para conferir se cumpriu cada cláusula.
A estrutura completa do spec.md
Antes de dissecar cada parte, vale olhar o modelo inteiro. O template a seguir parte do modelo oficial do Spec Kit no GitHub e acrescenta seções explícitas para regras de negócio, dependências e critérios de aceite.
Como exemplo, o modelo especifica um resgate de cupons de desconto no checkout de uma loja virtual. Assim, cada seção ganha um conteúdo concreto em vez de placeholders genéricos.
---
feature: coupon-redemption
id: "004"
title: Coupon redemption at checkout
status: draft
version: 0.3.0
owner: product-team
created: 2026-10-18
updated: 2026-10-18
branch: 004-coupon-redemption
related:
- specs/001-checkout/spec.md
---
# Feature Specification: Coupon redemption at checkout
## Context
### Problem
Customers receive promotional coupons by email, but the checkout has no way to apply them.
Support handles about 300 manual discount requests per week.
### Goal
Allow customers to apply a valid coupon during checkout and see the discount before paying.
### Out of scope
- Creating or editing coupons in the admin panel
- Stacking more than one coupon per order
## User Scenarios
### US-01: Apply a coupon (Priority: P1)
As a customer, I want to apply a coupon code at checkout so that I pay the discounted price.
### US-02: Remove a coupon (Priority: P2)
As a customer, I want to remove an applied coupon so that I can use it in a future order.
## Requirements
### Functional Requirements
- **FR-001**: System MUST allow the customer to enter a coupon code on the checkout page.
- **FR-002**: System MUST validate the coupon against the rules in the Business Rules table.
- **FR-003**: System MUST show the discounted total before payment confirmation.
- **FR-004**: System MUST allow the customer to remove an applied coupon.
- **FR-005**: System MUST notify the customer when a saved coupon is about to expire [NEEDS CLARIFICATION: email, push or both?]
### Non-Functional Requirements
- **NFR-001**: Coupon validation MUST respond in under 300 ms at p95.
- **NFR-002**: System MUST log every redemption attempt with order id and result.
- **NFR-003**: Error messages MUST NOT reveal whether a coupon code exists.
## Business Rules
| ID | Rule | Condition | Expected result |
|--------|------------------|----------------------------------------|----------------------------------------|
| BR-001 | Expiration | Current date after expires_at | Reject with COUPON_EXPIRED |
| BR-002 | Minimum amount | Cart subtotal below min_amount | Reject with MIN_AMOUNT_NOT_REACHED |
| BR-003 | Single use | Customer already redeemed this coupon | Reject with COUPON_ALREADY_USED |
| BR-004 | Maximum discount | Calculated discount above max_discount | Cap the discount at max_discount |
| BR-005 | One per order | Order already has a coupon | Replace the previous coupon |
## Key Entities
- **Coupon**: code, discount_type, value, min_amount, max_discount, expires_at
- **Redemption**: coupon, customer, order, redeemed_at
## Dependencies
- **DEP-001**: Pricing service exposes the cart subtotal (owner: checkout-team)
- **DEP-002**: Customer authentication already works (specs/001-checkout)
## Assumptions
- The marketing team creates coupons in an existing tool.
- All prices use a single currency.
## Acceptance Criteria
- **AC-001** (FR-002, BR-001): Given a coupon that expired yesterday, When the customer applies it, Then the system rejects it with COUPON_EXPIRED and the total stays the same.
- **AC-002** (FR-003, BR-004): Given a 50% coupon with max_discount of 100, When the subtotal is 400, Then the total shows 300.
- **AC-003** (FR-004): Given an order with an applied coupon, When the customer removes it, Then the total returns to the original subtotal.
- **AC-004** (NFR-001): Given 500 concurrent validations, When the load test runs, Then p95 stays under 300 ms.
## Success Criteria
- **SC-001**: Manual discount requests to support drop by 80% within 30 days.
## Review Checklist
- [ ] No implementation details (frameworks, databases, APIs)
- [ ] Every requirement is testable
- [ ] Every business rule has at least one acceptance criterion
- [ ] No [NEEDS CLARIFICATION] markers remain
Repare que cada item tem um identificador único, como FR-001 ou BR-002. Esses códigos parecem burocracia, mas permitem rastrear qualquer tarefa até o requisito que a originou.
A seguir, cada bloco do spec.md ganha uma análise própria, com o papel que cumpre na conversa com o agente.
Metadados: a identidade do documento
O bloco de metadados fica no topo, em formato YAML. Ele responde a perguntas simples: qual funcionalidade é essa, em que estado está e quem responde por ela.
Para um humano, essas informações parecem óbvias. Para o agente, no entanto, elas evitam um problema comum: trabalhar sobre uma versão desatualizada ou sobre a especificação errada.
No spec.md, o campo status merece atenção especial. Um documento em draft sinaliza que o agente ainda não deve implementar nada, enquanto approved libera a geração do plano.
Da mesma forma, version e updated ajudam a detectar divergência entre especificação e código. Se o código mudou depois da última atualização, alguém precisa revisar o contrato.
Já o campo branch segue a convenção do Spec Kit, que numera cada funcionalidade e cria uma branch com o mesmo nome. Assim, especificação e implementação viajam juntas no mesmo pull request.
Por fim, related aponta para outras especificações. Esse campo dá ao agente um mapa de contexto sem obrigá-lo a ler o repositório inteiro.
Contexto: o problema antes da solução
A seção de contexto do spec.md explica por que a funcionalidade existe. Ela costuma ter três partes: problema, objetivo e fora de escopo.
O problema descreve a dor atual com dados concretos. No exemplo, o suporte recebe cerca de 300 pedidos manuais de desconto por semana, e esse número dá peso à decisão.
O objetivo, por sua vez, define o resultado esperado em uma frase. Ele funciona como bússola: quando o agente precisar escolher entre duas interpretações, vai preferir a que serve melhor a esse objetivo.
Contudo, a parte mais subestimada é o fora de escopo. Agentes tendem a ser prestativos demais e completam funcionalidades vizinhas que ninguém pediu.
Quando você declara que criar cupons no painel administrativo não faz parte da entrega, o agente para de gerar telas extras. Com isso, o diff fica menor e a revisão fica mais rápida.
Logo depois do contexto, o template traz as histórias de usuário com prioridade. O Spec Kit usa níveis como P1, P2 e P3 para indicar o que entrega valor primeiro e o que pode esperar.
Cada história deve ser testável de forma independente. Na prática, isso permite que o agente entregue a P1 completa antes de tocar na P2, em vez de abrir várias frentes ao mesmo tempo.
Por isso, ordene as histórias do spec.md pelo valor que entregam, e não pela ordem em que surgiram na reunião.
Requisitos funcionais e não funcionais
Os requisitos formam o núcleo do spec.md. Eles dizem ao agente o que o sistema deve fazer e, também, sob quais condições deve operar.
Requisitos funcionais com identificadores estáveis
Cada requisito funcional começa com um identificador e usa o verbo MUST. Essa escolha vem da convenção da RFC 2119, que diferencia obrigação de recomendação.
Além disso, cada linha descreve uma única capacidade. Requisitos compostos, com vários verbos na mesma frase, geram tarefas confusas e testes que verificam coisas demais.
O identificador estável também importa. Quando o tasks.md cita FR-003, qualquer pessoa consegue voltar à especificação e entender a origem daquela tarefa.
Repare ainda no marcador [NEEDS CLARIFICATION] no FR-005. O template oficial do Spec Kit adota essa marcação para deixar explícita uma dúvida, em vez de deixar o agente adivinhar a resposta.
Em seguida, o comando /speckit.clarify procura esses marcadores e transforma cada um em pergunta. Dessa forma, a ambiguidade aparece na especificação, que custa pouco para mudar, e não no código.
Requisitos não funcionais mensuráveis
Requisitos não funcionais tratam de desempenho, segurança, observabilidade e acessibilidade. Eles raramente aparecem no pedido original, então o agente quase nunca os implementa sem que o spec.md peça.
A regra de ouro aqui é medir. Frases como "o sistema deve ser rápido" não guiam ninguém, enquanto "responder em menos de 300 ms no p95" vira um teste de carga.
O NFR-003 mostra outro tipo de cuidado. Ele impede que a mensagem de erro revele se um código de cupom existe, o que bloquearia tentativas de adivinhação.
Sem esse requisito, o agente provavelmente escreveria mensagens detalhadas e amigáveis. Embora pareça boa experiência, essa escolha abriria uma brecha de segurança.
Regras de negócio em formato tabular no spec.md
O template oficial do Spec Kit não traz uma seção própria para regras de negócio. Por isso, este modelo acrescenta uma tabela dedicada a elas no spec.md.
A diferença entre requisito e regra é sutil, mas importante. O requisito diz que o sistema valida o cupom, enquanto a regra diz exatamente o que torna um cupom válido.
O formato tabular resolve três problemas de uma vez. Primeiro, ele força cada regra a ter condição e resultado explícitos, sem espaço para frases vagas.
Segundo, a tabela facilita a leitura em diagonal. O revisor percorre as linhas e percebe rápido se falta algum caso.
Terceiro, o agente transforma cada linha em código e teste com muito mais precisão. Uma tabela de condição e resultado se aproxima bastante de uma tabela de decisão, que modelos interpretam bem.
Observe também a coluna de resultado esperado. Ela traz códigos de erro como COUPON_EXPIRED, que o agente pode reaproveitar diretamente no contrato da API.
Caso duas regras entrem em conflito, a tabela deixa o choque visível. Por exemplo, a BR-005 define que um novo cupom substitui o anterior, o que conversa com o item de fora de escopo sobre cupons acumulados.
Na prática, uma boa tabela de regras no spec.md reduz bastante as idas e vindas no chat. O agente para de perguntar o que acontece em cada cenário porque a resposta já está escrita.
Dependências e premissas
Nenhuma funcionalidade vive isolada. A seção de dependências lista o que precisa existir para a entrega funcionar, como serviços, outras funcionalidades e decisões de outros times.
No exemplo, o DEP-001 informa que o serviço de preços expõe o subtotal do carrinho. Com essa informação, o agente reutiliza o serviço existente em vez de recalcular o subtotal por conta própria.
Também vale registrar o responsável por cada dependência. Assim, quando algo travar, o time sabe exatamente com quem falar.
As premissas, por outro lado, registram o que o time assume como verdade sem confirmar. O template do Spec Kit trata essa seção como parte do documento, e ela tem um papel defensivo.
Quando uma premissa se mostra falsa, você sabe exatamente qual trecho revisar. Além disso, o agente evita criar soluções para problemas que a premissa já descarta, como conversão entre moedas.
Critérios de aceite no spec.md
Os critérios de aceite fecham o contrato. Eles descrevem como saber, de forma objetiva, que a funcionalidade está pronta.
O formato Given, When, Then vem do BDD e funciona muito bem com agentes. Cada critério define um estado inicial, uma ação e um resultado observável.
Mais importante ainda, cada critério do spec.md aponta para os requisitos e regras que valida. O AC-002, por exemplo, cobre ao mesmo tempo o FR-003 e a BR-004.
Essa rastreabilidade permite uma verificação simples. Se alguma regra da tabela não aparece em nenhum critério, a especificação ainda tem um buraco.
Os números também importam aqui. Um cupom de 50% sobre 400 geraria 200 de desconto, mas o teto de 100 reduz o total para 300, e esse cálculo vira um teste unitário direto.
Vale distinguir ainda critérios de aceite e critérios de sucesso. Os primeiros verificam o comportamento do software, enquanto os critérios de sucesso medem o impacto no negócio depois da entrega.
Como validar o spec.md antes do plano
O checklist de revisão no fim do template não serve de enfeite. Ele funciona como portão de qualidade antes de o agente gerar o plan.md.
O Spec Kit gera um checklist semelhante em checklists/requirements.md quando você roda o comando de especificação. Entre os itens, estão a ausência de detalhes de implementação e a ausência de marcadores de dúvida pendentes.
Você também pode pedir ao próprio agente que revise o spec.md contra esse checklist. Nesse caso, ele aponta requisitos sem teste, regras sem critério e termos ambíguos.
Contudo, a aprovação final precisa ser humana. O agente acelera a revisão, mas só quem conhece o negócio consegue dizer se as regras refletem a realidade.
Depois de aprovado, o documento muda o status para approved. Só então o fluxo segue para o plano técnico e, em seguida, para as tarefas.
Erros comuns ao escrever um spec.md
O erro mais frequente é misturar o como com o quê. Quando a especificação cita Entity Framework, Redis ou uma rota específica, ela deixa de descrever comportamento e passa a amarrar a solução.
Outro erro comum envolve requisitos impossíveis de testar. Palavras como "intuitivo", "rápido" e "seguro" precisam virar números, condições ou regras verificáveis.
Também é arriscado escrever um spec.md gigante para várias funcionalidades ao mesmo tempo. Documentos longos demais estouram o contexto do agente e diluem a atenção sobre o que realmente importa.
Além disso, muitos times escrevem a especificação uma vez e nunca mais a atualizam. Quando o código evolui e o documento fica para trás, o agente passa a trabalhar sobre informações falsas.
Por fim, alguns times removem os marcadores de dúvida sem resolvê-los. Apagar a pergunta não responde a pergunta, e o agente vai preencher a lacuna do jeito dele.
Conclusão
Um spec.md perfeito não depende de texto bonito, mas de estrutura. Metadados dão identidade, contexto dá direção, requisitos dão escopo, regras dão precisão, dependências dão limites e critérios de aceite dão o ponto de chegada.
Cada seção existe para responder uma pergunta que o agente faria se pudesse. Quando o documento responde antes, o agente para de adivinhar e passa a executar.
Portanto, copie o template, adapte os identificadores à realidade do seu time e trate a especificação como código. Versione, revise em pull request e atualize sempre que o comportamento mudar.
FAQ
O spec.md precisa seguir exatamente o template do Spec Kit?
Não. O template oficial serve como base, e você pode acrescentar seções como regras de negócio ou dependências, desde que mantenha o foco no quê e no porquê.
Qual a diferença entre spec.md e plan.md?
O spec.md descreve comportamento e regras sem citar tecnologia. Já o plan.md traduz essa especificação em decisões técnicas, como arquitetura, stack e modelo de dados.
Posso usar esse template sem o Spec Kit?
Sim. Qualquer agente de código consegue ler um arquivo markdown bem estruturado, então basta referenciar o arquivo no prompt ou nas instruções do repositório.
Quem deve escrever a especificação?
Normalmente, produto e engenharia escrevem juntos. O agente pode gerar o primeiro rascunho, mas a validação das regras de negócio continua humana.
Com que frequência devo atualizar o documento?
Sempre que o comportamento esperado mudar. A especificação deve acompanhar o código no mesmo pull request para evitar divergência.