Lição 8 de 10: Onde cada coisa mora: CLAUDE.md, rule, skill, hook
- Uma regra de roteamento de quatro vias que você aplica sem hesitar: fato → CLAUDE.md, fato-para-alguns-arquivos → path-scoped rule, procedimento-com-um-quando → skill, garantia → hook
- O custo de contexto de cada destino, e por que jogar tudo no CLAUDE.md "por garantia" pesa em toda sessão
- Sua escolha de stack estável fixada no CLAUDE.md uma vez, em vez de repetida a cada sessão
A L07 te deu o que é cada destino. Esta lição é o : a decisão de para qual deles cada coisa vai, e o que essa escolha custa na janela de contexto, o total de texto que o Claude carrega por sessão, o orçamento que você viu encher na L06.
A pergunta que toda decisão de setup responde
Toda vez que você quer que o Claude saiba de um fato, respeite uma constraint, execute um procedimento ou nunca deixe algo passar, existe uma pergunta antes do código: onde isso mora? São quatro destinos, e a doc da Anthropic dá o critério de corte direto.
A árvore de roteamento
Pegue a decisão na mão e faça três perguntas, nesta ordem.
Isso precisa acontecer toda vez, sem exceção, mesmo que o Claude resolva o contrário? Se sim, é um hook, o destino determinístico. Ex: rodar lint depois de cada edição, bloquear leitura de .env. Os outros três destinos são consultivos: o Claude lê e tenta seguir, mas pode julgar diferente. A doc de memória aponta o hook como o destino quando você precisa de garantia, verbatim: "If the instruction is something that must run at a specific point, such as before every commit or after each file edit, write it as a hook instead. Hooks execute as shell commands at fixed lifecycle events and apply regardless of what Claude decides to do." O preço dessa garantia é que o hook roda em toda ocorrência do gatilho: um hook de lint a cada edição também roda nas edições triviais. Hooks entram em detalhe no Módulo 5. Por enquanto, vale reconhecer que essa coluna existe e que ela é o destino de uma garantia. Fonte: How Claude remembers your project, Anthropic.
É um procedimento com etapas e um "quando"? Se a decisão é "quando o cenário X aparece, faça os passos A, B, C", é uma skill. O description: do frontmatter é o trigger que diz ao Claude quando carregar. Ex: "quando o usuário pedir mudança não-trivial, escreva um plano antes": um procedimento com um gatilho claro, que carrega só quando esse pedido aparece.
É um fato ou constraint que só vale numa parte do código? Se sim ("todo handler de API valida a entrada"; ou, num projeto de dados, "todo módulo em src/scraper/ registra a data e a URL da fonte do dado"), é uma : um arquivo em .claude/rules/ que, no frontmatter, traz um paths: listando os caminhos onde ela vale, e só carrega quando o Claude mexe num arquivo que casa com esse padrão. Se o fato vale para o projeto inteiro e em toda sessão, ele fica no CLAUDE.md (ou numa rule sem paths, que carrega sempre).
A path-scoped rule é a peça que a L07 só mencionou de passagem, e é fácil de pular. O reflexo é jogar no CLAUDE.md global o que devia ser uma rule por caminho. O formato vem direto da doc:
---
paths:
- "src/api/**/*.ts"
---
# Regras de desenvolvimento da API
- Todo endpoint valida a entrada antes de persistir.
- Use o formato padrão de resposta de erro.O paths: usa um padrão de caminho chamado glob. O * casa com qualquer trecho dentro de uma pasta; o ** casa com qualquer profundidade de subpastas. Então "src/api/**/*.ts" quer dizer "qualquer arquivo .ts, em src/api/ ou em qualquer pasta abaixo dela". Você pode copiar o bloco como está e só trocar o caminho pelo da sua área.
A tabela abaixo é a árvore de roteamento deitada: os destinos lado a lado, com o que é cada um, o gatilho que manda a decisão pra lá, o que ele custa de contexto e um exemplo. Clique no gatilho de uma linha pra destacar aquele destino e ler a tabela como a decisão "qual destino?".
| Destino | O que é | O gatilho | Custo de contexto | Exemplo BR |
|---|---|---|---|---|
CLAUDE.md | Fato sempre-verdadeiro sobre o projeto. | Alto — carrega inteiro no início de toda sessão. | "Stack: Python + Polars + DuckDB." | |
path-scoped rule | Fato ou constraint que só vale numa parte do código. | Baixo fora da área — só carrega quando casa o `paths:`. | "Todo módulo em src/scraper/ registra data e URL da fonte." | |
skill | Procedimento de vários passos com um "quando". | Quase zero até ser usada — progressive disclosure. | "Ao abrir um PR, gere descrição + checklist + nota da fonte." | |
hook | Garantia determinística, roda independente do que o Claude decide. | Pouco da janela — entra como comando, não como texto. | "Bloquear leitura de .env; rodar lint após cada edição." | |
subagente | Um agente auxiliar com contexto próprio, separado do principal. | Isolado — gasta a própria janela, devolve só o resumo. | "Revisor de segurança que lê o diff e reporta achados." | |
comando | Atalho que injeta um prompt pronto sob um nome (/slug). | Baixo — só entra quando você invoca o comando. | "/recibo: gera tela + cálculo em centavos + teste." |
O roteamento é um orçamento de contexto
Aqui o fio fecha com a L06. Roteamento errado tem um custo concreto, e ele aparece na janela de contexto.
O CLAUDE.md carrega inteiro no começo de toda sessão. A doc é explícita sobre o que isso custa:
"CLAUDE.md files are loaded into the context window at the start of every session, consuming tokens alongside your conversation."
Então cada procedimento de 40 linhas que você empurra para o CLAUDE.md "por garantia" é 40 linhas competindo por atenção em toda sessão, inclusive nas centenas em que aquele procedimento não tem nada a ver com o que você está fazendo. É o mesmo context rot da L06 (a degradação da resposta conforme a janela enche de coisa irrelevante), só que provocado pelo próprio setup.
A skill resolve isso por um mecanismo com nome: . O corpo da skill não fica no contexto o tempo todo; ele entra só quando a skill é usada.
A regra prática que sai daí: o CLAUDE.md é caro, porque carrega sempre; a path-scoped rule é barata fora da sua área, porque carrega só quando casa; a skill é quase de graça até ser invocada, por progressive disclosure; e o hook ocupa pouco da janela de início, porque entra como um comando de shell, não como o texto inteiro de um procedimento (o output que ele devolve ao Claude é curto; o custo maior dele é tempo de execução). Na hora de rotear, pergunte qual é a natureza da decisão antes de pensar no arquivo: é isso que segura o orçamento de contexto, em vez de ver o CLAUDE.md inchar sessão após sessão.
Stack estável como decisão de roteamento
A escolha de stack (que linguagem, que bibliotecas, que versões) é fato sempre-verdadeiro sobre o projeto, então vai no CLAUDE.md. Vale fixá-la explicitamente, e a razão é técnica: o agente erra menos quando o ecossistema muda pouco. Armin Ronacher, autor do Flask e nome conhecido na área, defende padronizar nas tecnologias mais estáveis, e o argumento serve para qualquer stack, não só a dele.
Onde essa decisão mora? É fato sobre o projeto, vale em toda sessão, descreve a stack, então vai para o CLAUDE.md. Uma linha como "stack: Python 3.12 + Polars + DuckDB; prefira gerar código a adicionar dependência nova sem pedir" rotea direito: é fato sempre-verdadeiro, sem ser procedimento nem constraint de um caminho só. Fixar a escolha de stack uma vez, no CLAUDE.md, em vez de repetir "use tal versão" a cada sessão, é em si uma decisão de roteamento.
Lab: roteie cinco decisões e mova uma de lugar
Rotear as cinco decisões é rápido; o passo 3 (mover uma seção e ler o diff) leva o tempo de uma ida e volta com o Claude. Dá para parar depois do passo 1 e voltar aos passos 2 e 3 em outra sessão.
Roteie cinco decisões no papel (ou no chat). Para cada uma, diga o destino e a razão de uma frase. Use a árvore: garantia → hook; procedimento com quando → skill; fato-de-uma-área → path-scoped rule; fato-de-sempre → CLAUDE.md. A lista mistura áreas diferentes de propósito: o roteamento é o mesmo seja o produto um SaaS, um scraper de dados públicos ou um painel cívico.
Roteie cada uma destas decisões para um destino (CLAUDE.md, path-scoped rule, skill ou hook) e justifique em uma frase:
1. "Valores monetários são sempre inteiros em centavos, no projeto inteiro."
2. "Todo arquivo em src/scraper/ registra a data e a URL da fonte do dado coletado."
3. "Quando eu pedir uma nova página de relatório, gere a página + a consulta ao banco + uma nota de rodapé com a fonte, nessa ordem."
4. "Nunca commitar arquivos .env*, sob nenhuma circunstância."
5. "A stack deste produto é Python + Polars + DuckDB."Gabarito: 1 → CLAUDE.md (ou rule sem paths): fato de sempre. 2 → path-scoped rule com paths: ["src/scraper/**"]: fato de uma área. 3 → skill: procedimento com um "quando". 4 → hook: garantia que não pode falhar. 5 → CLAUDE.md: fato/descrição de stack.
Ache uma seção do seu CLAUDE.md que virou procedimento, ou comece um do zero. Se você já tem um projeto com CLAUDE.md povoado, abra-o e procure um trecho com etapas ("primeiro faça X, depois Y, então Z"), algo que é mais receita do que fato. Esse é o candidato a sair.
Se você ainda está no começo e seu CLAUDE.md está vazio (ou nem existe), não tem problema: cole o trecho abaixo como uma seção de procedimento dentro de um CLAUDE.md de teste, e use-o como o candidato dos próximos passos. O exercício funciona igual.
## Como publicar um relatório
Primeiro rode a coleta com o scraper. Depois confira se a data da fonte está
preenchida em toda linha. Então gere a página em src/relatorios/ com a nota de
rodapé citando a fonte. Por fim, rode os testes e só então faça o commit.Com um CLAUDE.md em mãos (seu ou o de teste), peça ao Claude que aponte o procedimento:
Leia o CLAUDE.md deste projeto e me aponte qualquer seção que seja um procedimento de vários passos (uma receita com etapas), em vez de um fato sempre-verdadeiro. Para cada uma, diga se ela carregaria melhor como skill, e por quê.Mova uma para uma skill (ou rule) e meça o que você devolveu. Escolha um candidato (o do seu projeto, ou a seção "Como publicar um relatório" do CLAUDE.md de teste do passo 2) e peça a migração. Você está tirando peso do contexto de toda sessão e colocando atrás de um trigger.
Mova essa seção do CLAUDE.md para uma skill em .claude/skills/<nome>/SKILL.md, com um description: que sirva de trigger claro. Remova a seção do CLAUDE.md. Me diga quantas linhas saíram do CLAUDE.md — esse é o contexto que volta a ficar livre em toda sessão onde a skill não é chamada. Antes de gravar, me mostre o diff (a lista de linhas que entram e saem de cada arquivo) e espere eu confirmar.Peça o diff antes de aplicar e leia-o: o diff é a lista do que muda em cada arquivo (linhas que entram, linhas que saem), e é o ponto onde você confere se o Claude moveu o trecho certo e montou o paths: ou o description: do jeito que você quis, antes de qualquer arquivo mudar. Se o trecho for fato de uma área (e não procedimento), o destino certo é uma path-scoped rule com paths:, em vez de uma skill. É o mesmo movimento, só muda o arquivo.
Você terminou quando
Você consegue pegar qualquer decisão de setup (um fato, uma constraint, um procedimento, uma garantia) e rotear sem hesitar para CLAUDE.md, path-scoped rule, skill ou hook, dizendo em uma frase por que aquele destino e não outro, e nomeando o custo de contexto da escolha errada.