Agentes de codificação são rápidos, confiantes e inicialmente alheios à arquitetura da sua base de código. Se você entregar ao Claude Code, Codex ou Cursor um ticket vago, ele pode gerar código que compila, passa em testes simples e ainda assim viola limites importantes entre domínio, aplicação, infraestrutura e HTTP. Um DESIGN.md reduz esse risco ao registrar a intenção arquitetônica no lugar onde o agente realmente pode ler: o próprio repositório.
TL;DR
DESIGN.md é um arquivo Markdown no repositório que documenta decisões arquitetônicas, invariantes e restrições de design para humanos e agentes de codificação. Ele responde a:
Por que este sistema é estruturado dessa forma?
Enquanto isso:
-
README.mdexplica o que o projeto é e como começar. -
AGENTS.mdexplica como agentes devem construir, testar e trabalhar no projeto. -
CLAUDE.mdcontém instruções específicas para Claude Code. -
DESIGN.mdregistra o raciocínio arquitetônico que não é óbvio lendo apenas o código.
Introdução
O problema aparece rápido em equipes que adotam agentes de codificação.
Você pede a um agente para adicionar um endpoint de reembolso em um serviço de pagamentos. Ele cria um handler funcional, chama o banco diretamente no controller, ignora um erro do gateway e inventa um novo tipo de moeda porque não percebeu que já existia um no domínio.
O diff parece limpo. Os testes passam. Mas o código está errado em pontos que só alguém com contexto arquitetônico percebe.
O agente não é necessariamente ruim em programar. Ele só não conhece decisões que vivem:
- na cabeça de engenheiros seniores;
- em páginas antigas do Notion;
- em threads do Slack;
- em ADRs esquecidos;
- ou em padrões implícitos espalhados pelo código.
DESIGN.md resolve isso tornando explícitas as regras que o agente não consegue inferir com segurança.
O que DESIGN.md realmente é
DESIGN.md é um registro em texto puro do porquê seu código é organizado de determinada forma.
Ele não substitui o README, não é um tutorial de setup e não deve virar uma wiki genérica. Ele deve capturar decisões como:
- “A camada de domínio nunca importa o framework web.”
- “Dinheiro é sempre representado como inteiro em unidades menores, nunca
float.” - “Chamadas ao gateway de pagamento passam pelo padrão outbox.”
- “O agregado
Accounté o único caminho de escrita no livro-razão.” - “A especificação OpenAPI é a fonte de verdade para contratos de API.”
Essas regras são difíceis de inferir lendo arquivos isolados. O código mostra o resultado da decisão, mas não explica a decisão.
Um agente pode ver que Account.debit() existe. Mas, sem contexto, ele pode criar outro caminho de escrita para saldo porque não sabe que aquele método é deliberadamente o único ponto permitido.
A ideia tem relação com práticas conhecidas como ARCHITECTURE.md e ADRs. A diferença é o público: DESIGN.md é escrito para humanos e agentes de codificação. Por isso, deve ser:
- direto;
- declarativo;
- fácil de escanear;
- focado em invariantes;
- mantido dentro do repositório.
DESIGN.md vs AGENTS.md vs CLAUDE.md vs README.md
Esses arquivos se complementam. Não coloque tudo em um só.
| Arquivo | Público | Responde a | Frequência de mudança | Tamanho recomendado |
|---|---|---|---|---|
README.md |
Humanos | O que é o projeto e como começar | Muda com funcionalidades | Médio |
AGENTS.md |
Agentes de codificação | Como buildar, testar, lintar e contribuir | Muda com ferramentas | Curto |
CLAUDE.md |
Claude Code | Instruções específicas para Claude | Muda com ferramentas | Curto |
DESIGN.md |
Agentes, engenheiros e revisores | Por que a arquitetura é assim e o que não pode quebrar | Muda raramente | Médio e denso |
O projeto agents.md descreve AGENTS.md como um formato aberto para orientar agentes de codificação. Ele é operacional: comandos, testes, estilo, convenções de commit.
A documentação de memória do Claude Code descreve CLAUDE.md como um arquivo de instruções para o Claude. Ela também recomenda manter esse arquivo curto. Se você já usa AGENTS.md, uma configuração comum é fazer o CLAUDE.md importar esse conteúdo.
Exemplo:
@AGENTS.md
O que não cabe bem em AGENTS.md ou CLAUDE.md é justificativa arquitetônica profunda. Para isso, use DESIGN.md.
Uma estrutura prática:
repo/
README.md
AGENTS.md
CLAUDE.md
DESIGN.md
api/openapi.yaml
src/
No AGENTS.md, adicione uma referência curta:
## Arquitetura
Antes de alterar camadas, contratos de API, persistência, transações ou integrações externas, leia `DESIGN.md`.
No CLAUDE.md, se necessário:
@AGENTS.md
@DESIGN.md
Se você quer estruturar melhor o contexto do Claude nesses arquivos, veja Fluxos de trabalho do Claude Code.
O que colocar em DESIGN.md
Inclua regras que um agente não consegue inferir com segurança do código.
Um bom DESIGN.md deve cobrir:
-
Forma do sistema
- camadas;
- módulos;
- direção das dependências.
-
Invariantes
- regras que devem ser sempre verdadeiras.
-
Decisões-chave e justificativa
- o que foi escolhido;
- por que foi escolhido.
-
Alternativas rejeitadas
- o que a equipe decidiu não fazer;
- por que não deve ser reintroduzido.
-
Regras de domínio e dados
- moeda;
- datas;
- IDs;
- soft delete;
- multi-tenancy.
-
Fonte de verdade do contrato da API
- onde está o OpenAPI;
- o que é gerado;
- o que não deve ser editado manualmente.
-
Onde colocar novo código
- mapa prático para endpoints, casos de uso, integrações e middlewares.
-
O que não tocar
- código gerado;
- módulos legados;
- migrações aplicadas.
Modelo de DESIGN.md para uma API de pagamentos
Use este modelo como ponto de partida:
# DESIGN.md: Serviço de API de Pagamentos
Este arquivo registra a intenção arquitetônica e as decisões por trás dela.
Leia antes de gerar ou modificar código. Se uma alteração entrar em conflito
com uma regra abaixo, sinalize o conflito em vez de contorná-lo.
## Forma do sistema
Arquitetura em camadas. Dependências apontam apenas para dentro:
http -> app -> domain <- infra
- `domain/` não importa `http/`, `app/` nem frameworks.
- `infra/` implementa interfaces declaradas em `domain/` ou `app/`.
- `http/` nunca acessa banco de dados ou gateway de pagamento diretamente.
- `http/` chama casos de uso em `app/`.
## Invariantes
- Uma entrada de livro-razão é imutável após escrita.
- Correções financeiras são novas entradas compensatórias.
- Saldo é derivado das entradas do livro-razão.
- Dinheiro é inteiro em unidades menores, mais código ISO-4217.
- Nunca use `float` para dinheiro.
- Toda chamada externa a gateway de pagamento é idempotente por `idempotency_key`.
- Saldos não ficam negativos sem uma `OverdraftPolicy` explícita.
## Decisões-chave
### Padrão Outbox para chamadas de gateway
Handlers escrevem uma intenção na mesma transação de banco da alteração de negócio.
Um worker processa essa intenção e chama o gateway.
Justificativa: o gateway pode expirar sob carga. Chamadas inline tornam latência,
retries e tratamento de falhas difíceis de controlar.
Regra: não chame o gateway diretamente de um handler HTTP.
### Único caminho de escrita por agregado
Apenas `Account.post_entry()` escreve no livro-razão.
Justificativa: múltiplos caminhos de escrita já causaram desvio de saldo.
Regra: adicione comportamento ao agregado, não queries paralelas de escrita.
## Alternativas rejeitadas
- Lazy-loading de ORM entre agregados.
- Saldo persistido como coluna mutável.
- Uso de `float` para valores monetários.
- Webhooks síncronos executados na thread da requisição.
- Edição manual de tipos gerados a partir do OpenAPI.
## Regras de dados e domínio
- Todos os timestamps são UTC.
- Timestamps são formatados como RFC 3339 na borda HTTP.
- IDs são ULIDs gerados na camada de aplicação.
- Soft delete não é usado.
- Toda query multi-tenant deve ter escopo por `tenant_id`.
- Um método de repositório sem escopo de tenant é bug.
## Contrato da API
- `api/openapi.yaml` é a fonte de verdade.
- Tipos de request/response são gerados a partir do OpenAPI.
- Não edite manualmente arquivos em `http/generated/`.
- Para endpoints novos ou alterados:
1. atualize `api/openapi.yaml`;
2. regenere os tipos;
3. implemente o handler;
4. adicione testes de contrato.
- Respostas de erro seguem RFC 9457 (`problem+json`).
- Use o helper `problem()`.
- Não crie envelopes de erro ad-hoc.
## Onde o novo código vai
- Novo endpoint:
- rota em `http/routes/`;
- DTO em `http/dto/`;
- caso de uso em `app/usecases/`;
- regra de negócio em `domain/`.
- Nova integração externa:
- interface em `app/ports/`;
- implementação em `infra/clients/`.
- Cross-cutting concerns:
- autenticação, logging e idempotência ficam em middleware;
- não implemente inline em handlers.
## Fora do escopo
- `http/generated/`: código gerado. Não editar manualmente.
- `legacy/billing_v1/`: congelado. Não estender.
- `migrations/`: nunca edite migração já aplicada. Crie uma nova.
## Em caso de dúvida
Se uma solicitação exigir quebrar uma regra deste arquivo, sinalize o conflito
e proponha a menor alternativa compatível com o design.
A seção “Em caso de dúvida” é importante. Ela diz ao agente como agir quando a tarefa conflita com a arquitetura. Sem isso, o agente tende a contornar a regra para completar o ticket.
Como agentes realmente consomem DESIGN.md
Agentes não têm um parser especial para DESIGN.md. Eles leem o arquivo como contexto.
Por isso, você precisa tornar o arquivo fácil de encontrar.
Para Claude Code
No CLAUDE.md:
@DESIGN.md
Ou, se você centraliza instruções em AGENTS.md:
@AGENTS.md
@DESIGN.md
Para agentes que usam AGENTS.md
No AGENTS.md:
## Design e arquitetura
Leia `DESIGN.md` antes de alterar:
- camadas;
- contratos de API;
- modelos de domínio;
- transações;
- integrações externas;
- persistência;
- autenticação;
- multi-tenancy.
Escreva para recuperação, não para leitura linear
Prefira:
- `http/` nunca acessa o banco diretamente.
Em vez de:
Idealmente, tentamos manter uma separação razoável entre a camada HTTP e as
partes internas do sistema, embora em alguns casos seja aceitável...
Agentes seguem melhor regras curtas, absolutas e testáveis.
Equipes que constroem fluxos autônomos com agentes dependem desse ciclo de contexto e correção. Veja também construa seu próprio Claude Code.
Antipadrões
1. Repetir o código
Evite frases como:
UserService gerencia usuários.
Isso o agente já vê no código.
Prefira registrar intenção:
`UserService` não aplica regras de autorização. Autorização fica em `app/policies/`.
2. Transformar DESIGN.md em tutorial
Comandos de setup, instruções de build e scripts pertencem a README.md, CONTRIBUTING.md ou AGENTS.md.
Não coloque isso em DESIGN.md:
npm install
npm run dev
npm test
3. Documentar aspiração como realidade
Errado:
O sistema usa CQRS.
Se apenas parte do sistema usa CQRS, escreva:
Meta: novas escritas passam por casos de uso em `app/usecases/`.
Atual: `legacy/` ainda possui handlers que acessam repositórios diretamente.
Não estenda esse padrão.
4. Não definir dono
Sem dono, o arquivo vira ficção.
Adicione ao template de PR:
- [ ] Esta mudança altera uma decisão em `DESIGN.md`?
- [ ] Se sim, atualizei `DESIGN.md` na mesma PR.
5. Sincronizar linha a linha com o código
Não tente documentar cada classe, função ou pacote. Isso apodrece rápido.
Documente decisões que mudam pouco:
- limites de camada;
- invariantes;
- formatos de erro;
- política de transação;
- fonte de verdade do contrato;
- regras de domínio.
6. Contradizer AGENTS.md
Evite duplicar regras operacionais em vários arquivos.
Bom:
AGENTS.md -> comandos, testes, lint, fluxo de contribuição
DESIGN.md -> arquitetura, invariantes, decisões
Ruim:
AGENTS.md diz para usar problem+json.
DESIGN.md diz para usar outro envelope de erro.
DESIGN.md para APIs e backend
Em APIs e serviços backend, DESIGN.md costuma ter alto impacto porque muitos erros de agentes acontecem em áreas invisíveis:
- contratos HTTP;
- idempotência;
- transações;
- consistência;
- autenticação;
- multi-tenancy;
- paginação;
- erros;
- integrações externas.
Declare a fonte de verdade do contrato
Se sua API usa OpenAPI, seja explícito:
`api/openapi.yaml` é a fonte de verdade do contrato HTTP.
Handlers, DTOs, testes e documentação devem estar em conformidade com esse arquivo.
Também declare o que não fazer:
Não edite manualmente tipos gerados em `http/generated/`.
Atualize o OpenAPI, regenere os tipos e depois implemente.
Se você projeta o contrato primeiro no Apidog e exporta o OpenAPI para o repositório, o agente passa a ter um alvo claro. O raciocínio por trás de design-first para agentes é abordado em projetando APIs para agentes de IA.
Defina limites de transação
Exemplo:
Chamadas externas nunca acontecem dentro de uma transação de banco.
Use outbox para efeitos colaterais externos.
Sem essa regra, o agente tende a implementar a versão ingênua:
await db.transaction(async () => {
await paymentGateway.charge(...)
await orderRepository.markPaid(...)
})
A versão alinhada ao design seria:
await db.transaction(async () => {
await orderRepository.markPaymentPending(orderId)
await outboxRepository.enqueue({
type: "payment.charge.requested",
payload: {
orderId,
idempotencyKey,
},
})
})
Defina idempotência como invariante
Para pagamentos, pedidos e provisionamento, escreva:
Endpoints que criam efeitos externos devem exigir `Idempotency-Key`.
Retries com a mesma chave não podem duplicar cobrança, pedido ou provisionamento.
Padronize erros
Exemplo:
Todas as respostas de erro seguem RFC 9457 (`application/problem+json`).
Use o helper `problem()`.
Não crie formatos de erro específicos por endpoint.
Isso evita respostas inconsistentes como:
{ "error": "Invalid request" }
em um endpoint e:
{ "message": "Invalid request", "code": 400 }
em outro.
Proteja multi-tenancy
Exemplo:
Toda query deve ter escopo por `tenant_id`.
Um método de repositório sem `tenant_id` é bug de segurança.
Essa regra é crítica porque uma query isolada pode parecer correta, mas ainda assim vazar dados entre tenants.
Defina regras de versionamento
Exemplo:
Remover campo, renomear campo ou alterar semântica de resposta é breaking change.
Breaking changes exigem nova versão da API.
Campos novos opcionais são permitidos em versões menores.
Sem isso, agentes podem “limpar” respostas e quebrar clientes.
Exemplo de fluxo prático
Para adicionar um endpoint novo com agente:
- Atualize o contrato OpenAPI.
- Gere os tipos.
- Peça ao agente para ler
DESIGN.md. - Peça para implementar apenas nos locais definidos.
- Rode testes.
- Revise o diff contra os invariantes.
Prompt útil:
Leia `DESIGN.md` antes de implementar.
Adicione o endpoint POST /refunds conforme `api/openapi.yaml`.
Restrições:
- não edite arquivos gerados;
- não chame gateway diretamente do handler;
- use o padrão outbox;
- preserve idempotência por Idempotency-Key;
- use problem+json para erros.
Se alguma solicitação conflitar com `DESIGN.md`, pare e explique.
Esse tipo de prompt funciona melhor quando DESIGN.md já contém as regras como absolutos.
Para validar a API gerada contra o contrato, Baixe o Apidog e use o fluxo design-first com exportação OpenAPI, depuração e testes de endpoint.
Conclusão
DESIGN.md é um guardrail simples para agentes de codificação.
Use-o para registrar:
- por que a arquitetura existe;
- quais invariantes não podem ser quebrados;
- quais alternativas já foram rejeitadas;
- onde novos códigos devem ser colocados;
- qual arquivo é a fonte de verdade do contrato da API.
Ele não substitui AGENTS.md, CLAUDE.md ou README.md. Ele complementa esses arquivos com o contexto que agentes normalmente não têm.
Para backend e APIs, o maior ganho é declarar a especificação OpenAPI como autoritativa. Assim, agentes deixam de inventar schemas e passam a implementar contra um contrato explícito.
Projete esse contrato primeiro. Baixe o Apidog para criar APIs com abordagem design-first, exportar OpenAPI e validar se endpoints gerados por agentes realmente seguem o contrato.
Perguntas Frequentes
DESIGN.md é um padrão oficial como AGENTS.md?
Não. AGENTS.md é um formato definido e amplamente adotado. DESIGN.md é uma convenção de comunidade, semelhante a ARCHITECTURE.md e ADRs.
Use como um padrão prático, não como uma especificação formal.
Preciso de DESIGN.md se já tenho AGENTS.md ou CLAUDE.md?
Sim, se sua arquitetura possui restrições não óbvias.
AGENTS.md e CLAUDE.md devem continuar curtos e operacionais. Coloque decisões arquitetônicas em DESIGN.md e apenas referencie esse arquivo.
Para o arquivo operacional, veja como escrever arquivos AGENTS.md.
Como DESIGN.md difere de ARCHITECTURE.md?
A diferença principal está no público e no estilo.
ARCHITECTURE.md costuma ser escrito para humanos. DESIGN.md é escrito para humanos e agentes, então tende a ser mais declarativo, mais focado em invariantes e mais fácil de usar como contexto em ferramentas de codificação.
Qual deve ser o tamanho de DESIGN.md?
O suficiente para cobrir decisões importantes. Curto o suficiente para cada linha importar.
Como regra prática:
- 2 a 4 páginas focadas funcionam bem;
- listas são melhores que longos parágrafos;
- invariantes são melhores que explicações genéricas;
- corte qualquer coisa que apenas repita o código.
Como faço o agente realmente ler DESIGN.md?
Referencie-o no arquivo que o agente já carrega.
Para Claude Code:
@DESIGN.md
Para AGENTS.md:
Leia `DESIGN.md` antes de mudanças estruturais, contratos de API, persistência ou integrações externas.
O agente sempre seguirá DESIGN.md?
Não. Arquivos de instrução são contexto, não enforcement rígido.
Mas regras claras aumentam muito a chance de adesão. Além disso, revisores podem apontar violações diretamente:
Isso quebra a regra de caminho único de escrita em `DESIGN.md`.
Corrija mantendo o design.
Esse feedback costuma produzir correções melhores e mais rápidas.
DESIGN.md ajuda com contratos de API?
Sim. Um dos usos mais valiosos é declarar que a especificação OpenAPI é autoritativa.
Exemplo:
`api/openapi.yaml` é a fonte de verdade.
Não invente schemas no handler.
Não edite tipos gerados manualmente.
Projetar esse contrato primeiro em uma ferramenta como Apidog dá ao agente um alvo explícito.
Onde DESIGN.md deve ficar?
Na raiz do repositório:
repo/
README.md
AGENTS.md
CLAUDE.md
DESIGN.md
Em monorepos, use:
repo/
DESIGN.md # regras globais
services/payments/DESIGN.md
services/billing/DESIGN.md
O arquivo global define regras do sistema. Arquivos locais definem decisões específicas de cada serviço.
Top comments (0)