Specs no Claude Code: como evitar alucinações

Specs no Claude Code: como evitar alucinações

Estruturar specs no Claude Code é a forma mais confiável de impedir que o agente invente APIs, tabelas ou regras de negócio que ninguém pediu. Neste artigo, você verá como combinar o CLAUDE.md, arquivos de plano dedicados e subagentes com restrições explícitas para transformar o contexto volátil da conversa em um contrato rígido.

Por que o Claude Code alucina sem uma spec

Cada sessão do Claude Code começa com uma janela de contexto vazia. Portanto, tudo o que você explicou ontem no chat simplesmente não existe na sessão de hoje.

Além disso, conversas longas passam por compactação. Quando isso acontece, instruções que você deu apenas no chat podem desaparecer do contexto, enquanto o CLAUDE.md da raiz volta a ser lido do disco.

Quando falta informação, o modelo preenche as lacunas com o padrão mais provável. Na prática, é nesse ponto que surgem endpoints inventados, colunas que não existem e validações que ninguém especificou.

Em outras palavras, alucinação em agentes de código raramente é falta de capacidade. Quase sempre, o problema é a falta de um contrato claro.

Por isso, specs no Claude Code funcionam como a fonte da verdade que o agente consulta antes de agir. Elas não servem como documentação decorativa, mas como o limite do que pode ou não entrar no código.

O que é uma spec no Claude Code

Uma spec no Claude Code é um documento versionado que descreve o que construir, por que construir e como verificar que a entrega ficou pronta. Ela vive no repositório, ao lado do código, e muda por meio de commits, assim como qualquer outro artefato.

Esse conceito vem do Spec Driven Development, popularizado por ferramentas como o GitHub Spec Kit. Contudo, você não precisa de nenhuma ferramenta extra, porque os recursos nativos do Claude Code já bastam para trabalhar com specs.

A diferença entre uma spec e um prompt está na durabilidade. O prompt some com a sessão, enquanto a spec continua no disco para a próxima sessão, para o próximo subagente e para a próxima pessoa do time.

Também existe uma diferença de autoridade. Um prompt é um pedido, já uma spec aprovada é um acordo que o time revisou e que o agente precisa respeitar.

Estrutura de pastas para specs no Claude Code

O primeiro passo é separar o que é regra permanente do que é decisão de uma feature. Por exemplo, a estrutura abaixo funciona bem em projetos .NET, Node ou Python:

.
├── CLAUDE.md
├── .claude/
│   ├── settings.json
│   ├── active-spec
│   ├── rules/
│   │   └── api.md
│   ├── agents/
│   │   ├── spec-reviewer.md
│   │   └── implementer.md
│   └── hooks/
│       ├── require-approved-spec.sh
│       └── inject-active-spec.sh
└── specs/
    ├── constitution.md
    └── 001-order-checkout/
        ├── spec.md
        ├── plan.md
        ├── tasks.md
        └── deviations.md

A pasta specs guarda os contratos de cada feature, numerados em ordem. Já a pasta .claude guarda as peças que obrigam o agente a respeitar esses contratos.

O arquivo constitution.md reúne os princípios que valem para todas as specs do projeto no Claude Code. Por exemplo, ele pode definir a versão do runtime, o padrão de arquitetura e as bibliotecas proibidas.

CLAUDE.md como porta de entrada das specs no Claude Code

O CLAUDE.md é o arquivo que o agente lê no início de toda sessão. Ele pode ficar em ./CLAUDE.md ou em ./.claude/CLAUDE.md, e o time compartilha o arquivo pelo controle de versão.

No entanto, a documentação oficial do Claude Code deixa claro um ponto importante: o CLAUDE.md é contexto, não configuração imposta. Por isso, ele deve apontar para as specs no Claude Code e definir o protocolo de leitura, enquanto o bloqueio real fica com hooks e permissões.

A mesma documentação recomenda manter cada arquivo com menos de 200 linhas. Arquivos longos consomem contexto e reduzem a aderência às instruções.

O exemplo a seguir define o protocolo de leitura das specs no Claude Code:

<!-- Contrato do projeto, lido no início de toda sessão -->
# Project contract

## Source of truth
- Specs live in `specs/`. They win when they disagree with the code.
- Global principles: @specs/constitution.md

## Spec protocol (mandatory)
1. Before writing any code, read `specs/<feature>/spec.md`, `plan.md` and `tasks.md`.
2. If no spec exists for the request, stop and propose one. Do not write code.
3. Implement only tasks listed in `tasks.md`. One task per change.
4. If the spec is ambiguous, ask. Never invent endpoints, tables or fields.
5. Log any deviation in `specs/<feature>/deviations.md` before changing code.

## Commands
- Build: `dotnet build`
- Test: `dotnet test`

Repare no uso de @specs/constitution.md fora das crases. Essa sintaxe importa o arquivo para o contexto na inicialização, com até quatro níveis de importação aninhada.

Por outro lado, o CLI ignora caminhos entre crases na hora de importar. Dessa forma, você referencia a pasta de cada feature sem carregar todas as specs de uma vez.

Outro detalhe útil: comentários HTML em bloco somem antes de o conteúdo chegar ao modelo. Assim, você deixa notas para humanos sem gastar tokens de contexto.

Regras por caminho com a pasta rules

Para regras que valem apenas para parte do código, use arquivos em .claude/rules com o campo paths no frontmatter. Assim, a regra entra no contexto só quando o agente lê arquivos que combinam com o padrão.

---
paths:
  - "src/Api/**/*.cs"
---

# API rules
- Every endpoint must match a route declared in the active spec.
- Use ProblemDetails for every error response.
- Never add a route that is not listed in `plan.md`.

Com isso, o CLAUDE.md fica enxuto e cada camada do projeto ganha regras próprias. Além disso, você evita contradições, porque duas regras conflitantes fazem o modelo escolher uma delas de forma arbitrária.

Arquivos de plano dedicados

O segundo pilar é dividir cada feature em três arquivos com responsabilidades distintas. Essa divisão segue o fluxo especificar, planejar e quebrar em tarefas, o mesmo que o Spec Kit adota.

  • spec.md: o que construir e por que construir.
  • plan.md: como construir, com arquivos, padrões e dependências.
  • tasks.md: os passos pequenos e verificáveis da implementação.

Essa separação reduz o espaço para interpretação. Afinal, o agente encontra cada tipo de decisão em um lugar previsível, em vez de procurar respostas em um texto corrido.

O contrato de comportamento no spec.md

O spec.md descreve o comportamento esperado em critérios de aceite que você consegue testar. Veja um exemplo para uma feature de checkout:

# Spec 001: Order checkout

Status: Approved

## Goal
Allow a customer to convert a cart into an order.

## Acceptance criteria
- AC1: POST /api/orders returns 201 with the order id.
- AC2: An empty cart returns 422 with a ProblemDetails body.
- AC3: Total amount equals the sum of item price times quantity.

## Out of scope
- Payments, coupons and shipping.

## Data contract
- Table `orders`: `id` (uuid), `customer_id` (uuid), `total_amount` (numeric), `created_at` (timestamptz).

A seção Out of scope é a mais subestimada. Ela diz explicitamente o que o agente não deve fazer, e é justamente nesse vazio que a maioria das alucinações acontece.

Também vale observar o campo Status. Ele permite que um hook do Claude Code verifique, de forma automática, se a spec já passou por revisão humana.

O como e o passo a passo no plan.md e no tasks.md

O plan.md registra as decisões técnicas: arquivos afetados, padrões e dependências permitidas. Já o tasks.md transforma o plano em uma lista curta, em que cada item traz um critério de verificação.

# Tasks 001

- [ ] T1: Create `Order` entity and `orders` migration. Verify: `dotnet ef migrations list`.
- [ ] T2: Add `POST /api/orders` endpoint. Verify: AC1 and AC2 tests pass.
- [ ] T3: Add total calculation in `OrderService`. Verify: AC3 test passes.

Dessa forma, o agente nunca precisa adivinhar o próximo passo. Ele escolhe uma tarefa, roda a verificação e só então avança.

Plan mode: o Claude Code lê a spec antes de codar

O plan mode é o recurso nativo que força o agente a analisar antes de editar. Nesse modo, ele lê arquivos e pesquisa o código, mas não altera nada até você aprovar o plano.

Você ativa o modo com Shift+Tab durante a sessão ou já inicia o CLI nele:

# Inicia a sessão em modo somente leitura
claude --permission-mode plan

Para tornar esse comportamento o padrão do projeto, defina o modo em .claude/settings.json:

{
  "permissions": {
    "defaultMode": "plan"
  }
}

Em seguida, use um prompt que amarra a leitura da spec ao início do trabalho:

Read specs/001-order-checkout/spec.md, plan.md and tasks.md.
List every acceptance criterion and every file you intend to touch.
Do not propose anything outside tasks.md. Then present the plan for T1 only.

Esse prompt cria um ponto de controle para as specs no Claude Code. Primeiro o agente prova que leu a spec, depois apresenta o plano e, por fim, você aprova ou corrige antes que exista qualquer linha de código.

Pedir a lista de critérios de aceite tem um motivo prático. Se o agente cita um critério que não está no arquivo, você detecta a alucinação ainda no plano, quando corrigir custa quase nada.

Subagentes com restrições para specs no Claude Code

Subagentes são assistentes especializados que rodam em uma janela de contexto própria, com prompt de sistema e ferramentas que você define. Eles ficam em .claude/agents como arquivos markdown com frontmatter YAML.

Para specs no Claude Code, o grande valor dos subagentes está no isolamento. Um subagente não recebe o histórico da conversa principal, então julga o código apenas contra a spec, sem os vieses acumulados durante a implementação.

Um revisor de specs somente leitura

O primeiro subagente compara as mudanças com a spec e nunca edita arquivos:

---
name: spec-reviewer
description: Verifies that changes match the active spec. Use proactively after any code change.
tools: Read, Grep, Glob
model: sonnet
permissionMode: plan
---

You are a spec compliance reviewer.

1. Read the spec, plan and tasks of the feature named in the task.
2. Compare the changed files against each acceptance criterion.
3. Flag any route, table, field or dependency not declared in the spec.
4. Report PASS or FAIL per criterion, with file and line as evidence.

You never edit files. If the spec is silent on something, report it as a gap.

O campo tools funciona como lista de permissões. Como Edit, Write e Bash ficaram de fora, o revisor não consegue alterar código nem executar comandos, por mais que o modelo tente.

Além disso, o campo permissionMode mantém o subagente em modo de planejamento. Com isso, você tem duas barreiras independentes contra edições acidentais.

Um implementador com ferramentas negadas

O segundo subagente implementa uma única tarefa por vez:

---
name: implementer
description: Implements exactly one task from tasks.md of an approved spec.
disallowedTools: WebFetch, WebSearch, Agent
maxTurns: 30
---

You implement one task at a time from `specs/<feature>/tasks.md`.

- Read spec.md and plan.md before touching any file.
- Change only the files listed in plan.md for this task.
- If something is missing from the spec, stop and report it. Do not guess.
- Run the verification command of the task before finishing.

Aqui o campo disallowedTools remove a busca na web e a criação de outros subagentes. Assim, o implementador trabalha apenas com o repositório e com as specs no Claude Code, sem trazer soluções de fora.

Já o campo maxTurns limita quantas rodadas o subagente executa. Quando ele atinge o limite, o CLI devolve o resultado marcado como parcial, o que evita implementações que se estendem sem controle.

Hooks: da instrução ao contrato

Até aqui, quase tudo depende de o modelo seguir instruções. No entanto, a documentação recomenda um hook PreToolUse sempre que você precisar bloquear uma ação, independentemente da decisão do agente.

O script abaixo impede edições em src enquanto a spec ativa não estiver com status aprovado:

#!/bin/bash
# .claude/hooks/require-approved-spec.sh
INPUT=$(cat)
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

# Protege apenas o código de produção
[[ "$FILE" != *"/src/"* ]] && exit 0

cd "$CLAUDE_PROJECT_DIR" || exit 0
ACTIVE=$(cat .claude/active-spec 2>/dev/null)
SPEC="specs/$ACTIVE/spec.md"

if [ -z "$ACTIVE" ] || ! grep -q "^Status: Approved" "$SPEC" 2>/dev/null; then
  echo "Blocked: no approved spec. Set .claude/active-spec and approve $SPEC first." >&2
  exit 2
fi

exit 0

Depois, registre o hook em .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/require-approved-spec.sh" }
        ]
      }
    ]
  }
}

O código de saída 2 bloqueia a ferramenta e devolve a mensagem de erro ao modelo. Com isso, o Claude Code entende o motivo do bloqueio e volta para a spec, em vez de insistir na edição.

Além disso, um hook UserPromptSubmit pode injetar a spec ativa como contexto a cada prompt. Dessa forma, mesmo depois de uma compactação, o contrato volta a aparecer na conversa:

#!/bin/bash
# .claude/hooks/inject-active-spec.sh
cd "$CLAUDE_PROJECT_DIR" || exit 0
ACTIVE=$(cat .claude/active-spec 2>/dev/null) || exit 0
echo "Active spec: specs/$ACTIVE/spec.md. Read it before writing any code."

Essa combinação muda a natureza das specs no Claude Code. Elas deixam de ser um pedido educado e passam a funcionar como uma regra que o próprio cliente aplica.

O fluxo completo de specs no Claude Code

Com todas as peças no lugar, o ciclo de cada feature segue sempre a mesma ordem:

  1. Escreva a spec.md com a ajuda do agente em plan mode e revise o texto manualmente.
  2. Marque Status: Approved e grave o nome da feature em .claude/active-spec.
  3. Peça o plano de uma única tarefa em plan mode e aprove.
  4. Delegue a implementação ao subagente implementer.
  5. Acione o spec-reviewer para validar cada critério de aceite.
  6. Registre desvios em deviations.md e atualize a spec antes do próximo ciclo.

Repare que a spec muda antes do código, nunca depois. Essa ordem é o que transforma specs no Claude Code em contrato, e não em documentação que envelhece em silêncio.

Se você está começando com IA generativa, vale revisar os conceitos de base no artigo Generative AI: Fundamentos da IA. Afinal, entender como o modelo gera texto ajuda a perceber por que ele preenche lacunas quando falta contexto.

Erros comuns ao escrever specs no Claude Code

O erro mais frequente é escrever uma spec gigante para o Claude Code. Uma especificação longa demais consome contexto e esconde os critérios importantes no meio de parágrafos irrelevantes.

O segundo erro é usar critérios que ninguém consegue verificar. "A API deve ser rápida" não ajuda o agente, enquanto "o p95 fica abaixo de 200 ms" vira um teste concreto.

Outro problema comum é deixar instruções conflitantes entre o CLAUDE.md, as regras por caminho e a spec. Nesse caso, o modelo escolhe uma das versões, e você perde a previsibilidade.

Também é arriscado confiar apenas no CLAUDE.md para proibir ações. Como ele é contexto, o bloqueio de verdade precisa de hooks ou de regras de permissão nas configurações.

Por fim, muitos times deixam a spec envelhecer. Quando o código muda sem atualizar a especificação, o agente passa a ler um contrato falso e volta a alucinar com confiança.

Conclusão

Alucinação em agentes de código é, na maior parte das vezes, um sintoma de contexto frágil. Por isso, a solução não é escrever prompts mais longos, mas mover as decisões para specs no Claude Code, versionadas e lidas antes de qualquer ação.

O CLAUDE.md define o protocolo e aponta para as specs. Os arquivos spec.md, plan.md e tasks.md dão estrutura ao que construir, enquanto o plan mode garante a leitura antes da escrita.

Já os subagentes isolam revisão e implementação com ferramentas restritas. Por fim, os hooks fecham o ciclo e transformam specs no Claude Code em um contrato que o próprio CLI faz cumprir.

Comece pequeno, com uma única feature e um único hook. Em seguida, evolua o processo conforme o time ganha confiança no fluxo.

No começo, escrever specs no Claude Code parece um custo extra. Contudo, esse tempo volta rapidamente em menos retrabalho, revisões mais curtas e código que faz exatamente o que o time combinou.

FAQ

Preciso do Spec Kit para usar specs no Claude Code?

Não. O CLAUDE.md, a pasta de regras, os subagentes e os hooks já permitem aplicar o mesmo fluxo sem ferramentas externas.

O CLAUDE.md garante que o agente siga a spec?

Não garante. Ele funciona como contexto, então ações que precisam de bloqueio real devem usar hooks ou regras de permissão.

Qual o tamanho ideal do CLAUDE.md?

A documentação recomenda menos de 200 linhas por arquivo. Detalhes específicos devem ir para regras por caminho, skills ou para as próprias specs.

Subagentes leem o CLAUDE.md?

Sim, subagentes personalizados carregam os arquivos CLAUDE.md, mas não recebem o histórico da conversa principal. Os subagentes nativos Explore e Plan, por outro lado, iniciam sem o CLAUDE.md.

Onde registrar mudanças de escopo durante a implementação?

Registre em um arquivo de desvios dentro da pasta da feature e atualize a spec antes de alterar o código. Assim, o contrato continua refletindo a realidade.

Glossário

Termo Significado
Spec Documento versionado que define o que construir, por que e como verificar a entrega
CLAUDE.md Arquivo de instruções que o Claude Code carrega no início de toda sessão
Alucinação Resposta plausível, porém inventada, que o modelo produz quando falta informação
Plan mode Modo somente leitura em que o agente analisa e propõe um plano antes de editar
Subagente Assistente especializado com contexto, prompt e ferramentas próprias
Hook Comando que roda em eventos do ciclo de vida do agente e pode bloquear ações
Compactação Resumo automático da conversa quando a janela de contexto se aproxima do limite
Critério de aceite Condição verificável que define quando uma funcionalidade está pronta

Fontes