Pular para o conteúdo

Builder OS

Builder · OS
L08 · Onde cada coisa mora
~11 MIN DE LEITURA

Lição 8 de 10: Onde cada coisa mora: CLAUDE.md, rule, skill, hook

lição 8/10 do Módulo 1
AO FIM, VOCÊ VAI TER
  • 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:

saída esperada
---
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?".

DestinoO que éO gatilhoCusto de contextoExemplo BR
CLAUDE.mdFato sempre-verdadeiro sobre o projeto.Alto — carrega inteiro no início de toda sessão."Stack: Python + Polars + DuckDB."
path-scoped ruleFato 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."
skillProcedimento 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."
hookGarantia 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."
subagenteUm 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."
comandoAtalho 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.

prompt · text
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.

prompt · text
## 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:

prompt · text
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.

prompt · text
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.