Claude Code em monorepo: como apontar o agente para o pacote certo sem carregar o repositório inteiro

Claude Code em monorepo apontando o agente para o pacote certo
Resposta rápida

Trabalhar com Claude Code em monorepo trava por um motivo simples: os defaults pensados para projeto pequeno enchem a janela de contexto com instrução e leitura que não têm relação com a tarefa, gastando token e degradando o desempenho. A saída é delimitar escopo: iniciar a sessão dentro do pacote (que carrega o CLAUDE.md local mais o da raiz), escrever cada regra no nível certo da hierarquia, conferir no /context o que realmente entrou em Memory files e barrar leitura do que não interessa com .gitignore e regras Read em permissions.deny. Quando a tarefa atravessa pacotes, entram --add-dir e subagentes 🙂

Você pede um ajuste no pacote de API e o agente abre a pasta do front

Quem trabalha em repositório grande já viveu essa cena, e ela não é bug: é o comportamento padrão batendo de frente com a realidade do repo

A própria documentação do Claude Code descreve o problema em um guia dedicado a monorepos e bases de código grandes

Conforme a base cresce, os defaults (que foram pensados para projeto pequeno) podem preencher a janela de contexto com instruções e leituras de arquivo sem relação nenhuma com a tarefa

Resultado: token queimado e desempenho pior

A boa notícia é que dá pra delimitar isso com coisas concretas: onde a sessão começa, o que o CLAUDE.md daquele nível diz e o que as permissões deixam ler

Bora ver na prática?

Domine o Claude Code do básico ao avançado
Pré-inscrição Formação Claude Code

Domine o Claude Code do básico ao avançado

Você vai aprender a criar sistemas completos com Claude Code, sem precisar ser programador. Inscreva-se para ter acesso a um desconto de lançamento e bônus especiais!

O que você precisa antes de começar:

Nada de PC da Nasa aqui, o cenário mínimo é bem simples:

  • um repositório com mais de um pacote (aquele clássico apps/ e packages/ convivendo)
  • Claude Code instalado e rodando no repo
  • acesso pra editar os arquivos de configuração do projeto: o .claude/settings.json (versionado, vale pro time) e o .claude/settings.local.json (pessoal, só seu)
  • um .gitignore já cobrindo node_modules/, dist/ e build/

Sobre os dois settings: as listas se somam entre os escopos

Ou seja, o arquivo local ADICIONA caminho, ele não remove o que veio do compartilhado

Se quiser a referência oficial aberta em outra aba enquanto lê, é a página Set up Claude Code in a monorepo or large codebase, em code.claude.com/docs/en/large-codebases

Passo a passo para apontar o Claude Code ao pacote certo:

  1. Inicie a sessão dentro do pacote alvo

Esse é o passo que resolve metade da dor, e é só um cd

cd packages/api
claude

Ao iniciar em packages/api/, o Claude carrega o packages/api/CLAUDE.md e o CLAUDE.md da raiz

Nenhuma instrução de packages/web/ entra no contexto

O erro comum deste passo: abrir na raiz por costume, porque "é onde o projeto está", e depois reclamar que o agente confundiu os pacotes

  1. Escreva o CLAUDE.md do pacote no nível certo da hierarquia

O Claude lê o CLAUDE.md de cada nível, e as regras de uma subpasta valem SÓ para arquivos abaixo daquele caminho

Então a divisão é natural: o que é comum a todo mundo fica na raiz, o que é específico (padrão de teste, convenção de rota, jeito de nomear migration) desce pro pacote

CLAUDE.md                    <- o que vale pro repo inteiro
packages/api/CLAUDE.md       <- regra que só faz sentido na API
packages/web/CLAUDE.md       <- regra que só faz sentido no front

Aqui vale uma pausa pra explicar o carregamento, porque muita gente se ferra nisso

O Claude Code carrega o CLAUDE.md do diretório de trabalho e de todos os diretórios pais no início da sessão

Os de subpastas ele carrega sob demanda, quando lê arquivos dali

O erro comum deste passo: empurrar detalhe de um pacote pro arquivo da raiz "pra garantir", que é exatamente o jeito de fazer o contexto engordar em toda sessão

  1. Rode /context e olhe a lista de Memory files

Chega de achismo, dá pra conferir o que entrou de verdade

/context

A tela mostra a ocupação da janela de contexto por categoria: system prompt, system tools, MCP tools, subagentes customizados (com a origem de cada um), memory files, skills e mensagens da conversa

O erro comum deste passo: achar que quebrar o CLAUDE.md gigante em imports @path aliviou o contexto

Não aliviou! Os arquivos importados via @path são carregados no launch, então o custo de contexto continua ali

Organiza a leitura pra humano, e só

Como impedir que o agente leia o que não interessa:

Delimitar onde a sessão começa é metade do trabalho

A outra metade é blindar a leitura, pra ele não sair varrendo pasta que ninguém pediu

  1. O básico já vem de graça

As buscas de conteúdo do Claude respeitam o .gitignore por padrão

Então caminhos já listados ali, tipo node_modules/, dist/ e build/, ficam fora dos resultados de busca sem você configurar absolutamente nada 😀

  1. Para arquivo versionado que você não quer que ele abra, use deny de leitura

É o caso do build commitado, daquele bundle que vive no repo por motivo histórico, e por aí vai

A regra vai nas permissões, em permissions.deny:

{
  "permissions": {
    "deny": [
      "Read(./**/dist/**)",
      "Read(./**/build/**)"
    ]
  }
}

Tome cuidado com a ordem de avaliação: primeiro deny, depois ask, depois allow

O primeiro match decide, independente de quão específica é a regra

E tem um detalhe que pega gente desprevenida: caminho barrado por um deny de Read é recusado inclusive pra CRIAR arquivo novo ali

  1. Em worktree, escreva em disco só o que precisa

Existe o setting worktree.sparsePaths, que usa o git sparse-checkout pra gravar apenas os diretórios listados mais os arquivos de raiz

O ganho é direto: worktrees iniciam mais rápido e ocupam menos espaço

E onde commitar cada coisa dessas?

Se todo mundo que trabalha no diretório precisa dos mesmos paths, vai em .claude/settings.json e entra no versionamento

Se é caminho só pra você, .claude/settings.local.json resolve, lembrando que ele adiciona à lista, não remove

Quando a tarefa atravessa mais de um pacote:

Nem tudo é "mexer só na API", né? Às vezes o tipo mora na lib compartilhada e o consumo está em outro canto

Aqui vão as saídas mais comuns

Precisa enxergar um diretório fora do working directory:

A flag --add-dir dá acesso a diretórios extras, e ela valida que cada caminho passado existe mesmo como diretório

Porém tem uma pegadinha: por padrão, os CLAUDE.md e arquivos de rules desses diretórios adicionados NÃO são carregados

Ou seja, ele enxerga o código, mas não as instruções daquele pacote

Se você quer a memória junto, existe variável de ambiente pra isso:

CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 claude --add-dir ../shared

Com ela, o diretório adicional passa a carregar CLAUDE.md, .claude/CLAUDE.md, .claude/rules/*.md e CLAUDE.local.md

Varredura ampla sem sujar a sessão:

Quando a pergunta é do tipo "onde esse helper é usado em todos os pacotes", jogar isso na conversa principal é pedir pra encher o contexto de arquivo lido

É aí que entram os subagentes: cada um roda em uma conversa própria, as chamadas e resultados intermediários ficam nele e só a mensagem final volta pro pai

O principal recebe um resumo em vez de todo arquivo aberto no caminho, sacou?

E eles rodam em paralelo, então subtarefas independentes terminam no tempo da mais lenta, não na soma de todas

Se quiser ir mais fundo nesse ponto, eu já falei sobre usar subagents no Claude Code por aqui

Cada pacote com seu procedimento:

Skills carregam de diretórios .claude/skills/ aninhados abaixo do diretório de trabalho

Quando o Claude lê ou edita um arquivo em uma subpasta, as skills daquele .claude/skills/ ficam disponíveis

Na prática isso é massa: um pacote do monorepo pode fornecer skills próprias mesmo com a sessão iniciada na raiz

A ressalva honesta: skills aninhadas não carregam no startup

Elas carregam na primeira vez que o Claude lê ou edita um arquivo naquela subpasta, e ficam disponíveis pelo resto da sessão

Até lá, não aparecem no autocomplete nem podem ser chamadas pelo nome

Se a dúvida for qual formato usar pra cada coisa, tem um post sobre skills, comandos e subagentes que separa isso direitinho

Feedback de tipos no pacote certo com a ferramenta LSP:

Tem um recurso que encaixa perfeito no cenário de monorepo

A ferramenta LSP dá inteligência de código a partir de um language server em execução

Depois de cada edição de arquivo, ela reporta automaticamente erros de tipo e warnings, sem passo separado de build

É justamente o tipo de rede de segurança que você quer quando a edição escapa pro pacote vizinho e quebra tipo em outro lugar

A ressalva: ela fica inativa até você instalar um plugin de code intelligence para a linguagem

O plugin traz a configuração do language server, e o binário se instala à parte

Pra valer no repositório inteiro, o caminho é adicionar o plugin ao setting de projeto enabledPlugins

O que fazer agora:

A régua do escopo em monorepo é basicamente isso:

  • onde a sessão começa (é o que define quais CLAUDE.md entram no launch)
  • o que o CLAUDE.md daquele nível diz (regra de subpasta vale só abaixo dela)
  • o que as permissões deixam ler (.gitignore de graça, permissions.deny pro resto)

E tem um detalhe de sessão longa que vale guardar

Depois do /compact, o Claude relê o CLAUDE.md da raiz direto do disco e reinjeta na sessão

Já os CLAUDE.md aninhados de subpasta não voltam sozinhos: eles recarregam quando ele lê um arquivo naquela subpasta de novo

Próximo passo, e é bem simples: na próxima sessão, comece dentro do pacote, rode /context e compare a lista de memory files com o que a tarefa realmente precisava

Se tiver instrução de pacote que não tem nada a ver ali no meio, você achou exatamente o que mover de lugar 🙂

Até o próximo post!

Perguntas frequentes

Como o Claude Code decide quais CLAUDE.md carregar em um monorepo?

No início da sessão ele carrega o CLAUDE.md do diretório de trabalho e o de cada diretório pai. Os CLAUDE.md de subpastas só entram sob demanda, quando o Claude lê algum arquivo dentro daquele caminho.

Iniciar o Claude Code na raiz do monorepo carrega as instruções de todos os pacotes?

Não. Se a sessão começa em packages/api/, o Claude carrega packages/api/CLAUDE.md e o CLAUDE.md da raiz, mas nenhuma instrução de packages/web/ entra no contexto. É por isso que iniciar dentro do pacote certo resolve boa parte da confusão.

Dividir o CLAUDE.md gigante em vários arquivos com @path reduz o consumo de contexto?

Não reduz. Os arquivos importados via @path são carregados no launch da mesma forma, então o custo de contexto continua o mesmo. O ganho de organizar em imports é só para facilitar a leitura humana.

A flag –add-dir do Claude Code também carrega o CLAUDE.md do diretório adicionado?

Por padrão não. –add-dir dá acesso ao código do diretório extra, mas os arquivos de memória (CLAUDE.md e rules) daquele diretório ficam de fora. Para trazer a memória junto, é preciso rodar com CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1.

Como conferir quais arquivos de memória realmente entraram no contexto da sessão?

Rodando /context. O comando mostra a ocupação da janela por categoria, incluindo a lista de Memory files, e assim dá pra confirmar se algum CLAUDE.md indesejado foi carregado.

Bloquear um diretório com deny de leitura impede o Claude Code de criar arquivo novo ali?

Impede sim. Um caminho barrado por um deny de Read é recusado inclusive para criar arquivo novo naquele local, então vale lembrar disso antes de aplicar a regra em pasta onde o agente ainda precisa escrever.



Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação Vibe Coding

Formação Vibe Coding

Do Prompt ao Produto: Crie Software Real com IA

  • 474 aulas
  • 20 projetos
  • 39h 27min

Blog | Mais populares