SSD Nodes Learn Hosting plans →
Guias Matt ConnorPor Matt Connor · Atualizado 2026-08-24

AGENTS.md aninhado para monorepo: estrutura ideal

Veja como dividir o AGENTS.md por serviço, evitar regras obsoletas e reduzir o contexto lido pelo agente sem instalar nada no monorepo.

O que significa um AGENTS.md aninhado num monorepo

Um AGENTS.md aninhado num monorepo significa ter um ficheiro pequeno na raiz do repositório e outro ficheiro dentro de cada diretório de serviço. O ficheiro da raiz contém as poucas regras que são válidas em todo o repositório, além de um mapa que indica onde estão os outros ficheiros. Cada ficheiro de serviço contém os comandos e as convenções aplicáveis apenas a esse diretório. Um agente que edite services/worker/queue.py lê primeiro o ficheiro da raiz e o ficheiro do worker, sem gastar contexto algum com o front end que nunca irá alterar.

Não há nada para instalar. AGENTS.md é uma convenção, e o projeto upstream afirma isso claramente:

AGENTS.md é apenas Markdown padrão. Use os títulos que quiser; o agente simplesmente analisa o texto fornecido.

É por isso que vale a pena aprender esta técnica corretamente. O formato não vai mudar sem aviso. O que causa problemas é a localização e a manutenção dos ficheiros, e ambas são da sua responsabilidade.

Por que um único AGENTS.md grande na raiz deixa de funcionar?

Um único AGENTS.md com 600 linhas na raiz de um repositório que contém uma aplicação web, um worker em segundo plano e um diretório Terraform falha de quatro formas diferentes.

Fica desatualizado porque ninguém é responsável por ele. O engenheiro que renomeia um script de testes em apps/web está a editar ficheiros em apps/web. O AGENTS.md da raiz não está nesse diff, por isso nenhum revisor vê a inconsistência. Seis semanas depois, o ficheiro descreve uma etapa de build que já não existe, e a pessoa que causou o problema já se esqueceu da alteração.

Consome contexto em todas as tarefas. Estes ficheiros são carregados no início da sessão, antes de o agente saber o que lhe vai ser pedido. A documentação do Claude Code apresenta um valor concreto: "mantenha menos de 200 linhas por ficheiro CLAUDE.md. Ficheiros mais longos consomem mais contexto e reduzem a adesão." O Codex deixa de combinar ficheiros de instruções quando o tamanho total atinge 32 KiB, o valor predefinido de project_doc_max_bytes. Um ficheiro na raiz que documenta quatro serviços consome esse orçamento com três deles em todas as tarefas.

As instruções começam a contradizer-se. O diretório da aplicação web exige pnpm test. O worker exige pytest -q. Quando são escritas num único ficheiro, cada regra só está correta em parte das situações, por isso o agente tem de adivinhar qual se aplica. A documentação do Claude Code descreve o resultado: "se duas regras se contradisserem, o Claude pode escolher uma arbitrariamente." Um ficheiro por diretório elimina a dúvida, porque apenas uma das duas regras está no contexto. Quando uma regra que tem a certeza de ter escrito claramente é ignorada mesmo assim, analisar as razões pelas quais uma instrução nunca é aplicada é melhor do que reescrever o texto pela quarta vez.

Fica cheio de informações que o agente poderia obter do código. Uma árvore de diretórios, uma lista de dependências, um resumo da função de cada pacote. A verificação /doctor do Claude Code existe precisamente para remover este conteúdo. Ela "remove conteúdo que o Claude pode obter da base de código, como estruturas de diretórios, listas de dependências e descrições gerais da arquitetura" e mantém "problemas conhecidos, fundamentação e convenções que diferem das predefinições das ferramentas." Esta frase é o melhor teste que conheço para determinar se uma linha pertence realmente ao ficheiro.

O agente lê o ficheiro da raiz ou apenas o mais próximo?

É aqui que a maioria das pessoas interpreta mal o modelo, por isso vale a pena citar a convenção upstream em vez de a parafrasear:

Coloque outro AGENTS.md dentro de cada pacote. Os agentes leem automaticamente o ficheiro mais próximo na árvore de diretórios, por isso o ficheiro mais próximo tem precedência e cada subprojeto pode incluir instruções adaptadas.

E, em caso de conflitos:

O AGENTS.md mais próximo do ficheiro editado ganha; os pedidos explícitos do utilizador no chat substituem tudo o resto.

Para muitas pessoas, "tem precedência" significa que "o ficheiro da raiz é ignorado". Não é esse o caso. Nas ferramentas que implementam esta convenção, todos os ficheiros no caminho desde a raiz do repositório até ao diretório de trabalho são lidos e concatenados. O ficheiro mais próximo só ganha quando dois ficheiros definem regras diferentes sobre o mesmo assunto.

O Codex é explícito sobre o mecanismo: "O Codex concatena os ficheiros desde a raiz, separando-os com linhas em branco. Os ficheiros mais próximos do diretório atual substituem as orientações anteriores." O Claude Code percorre o mesmo caminho para o seu próprio nome de ficheiro. Os ficheiros na hierarquia de diretórios acima do diretório de trabalho "são carregados integralmente no arranque", e "Todos os ficheiros descobertos são concatenados no contexto, em vez de se substituírem uns aos outros." Os diretórios abaixo do diretório de trabalho comportam-se de forma diferente: o Claude Code carrega esses ficheiros a pedido, "quando o Claude lê ficheiros nesses diretórios."

Daqui resultam duas consequências práticas. O ficheiro da raiz é um prefixo de todas as sessões no repositório, por isso trate cada linha aí colocada como uma linha cujo custo é pago cem vezes por semana. Um ficheiro por diretório não tem qualquer custo quando o agente está a trabalhar noutro local, o que significa que os detalhes são baratos e devem ficar aí.

Este comportamento foi verificado na documentação do Codex e do Claude Code em agosto de 2026. As ferramentas implementam a convenção de formas ligeiramente diferentes e podem alterar esse comportamento, por isso confirme as regras de carregamento do agente utilizado pela sua equipa.

Um layout funcional para um repositório com três serviços

repo/
  AGENTS.md                   rules true everywhere, plus the map
  apps/web/AGENTS.md          TypeScript client, Vite, Vitest
  services/worker/AGENTS.md   Python queue consumer, pytest
  infra/AGENTS.md             Terraform and the deploy scripts

O ficheiro raiz é curto de propósito. Indica onde procurar e contém apenas as regras que se aplicam a todos os diretórios.

# AGENTS.md

This is a monorepo. Each top-level directory ships its own AGENTS.md.
Read this file and the AGENTS.md nearest the code you are editing
before you change anything.

- `apps/web` browser client
- `services/worker` queue consumer
- `infra` Terraform and deploy scripts

## Rules for the whole repository

- The package manager is `pnpm`. `npm install` writes a second lockfile
  that CI ignores, so the install you tested is not the install that ships.
- Any `generated/` directory is build output. Edit the schema in
  `schemas/` and run `pnpm codegen` instead.
- `.env.local` holds real credentials. Do not read it and do not print it.
- If you change code in a directory, update that directory's AGENTS.md
  in the same commit.

O ficheiro específico do diretório é onde ficam os detalhes e pode ter o tamanho que o diretório exigir.

# apps/web

Browser client. Vite and React, TypeScript with `strict` on.

## Commands

- `pnpm dev` serves on port 5173.
- `pnpm test` runs Vitest once and exits.
- `pnpm typecheck` runs `tsc --noEmit`.

## Conventions

- One component per file under `src/components/`.
- All HTTP goes through `src/api/client.ts`. Do not call `fetch` directly,
  because the client attaches the auth header and retries on 429.

## Traps

- `pnpm build` does not type check. Vite strips the types instead of
  checking them, so a broken type still produces a green build.
  Run `pnpm typecheck` as a separate step.

O ficheiro do worker tem a mesma estrutura, mas conteúdo diferente: o comando de instalação, pytest -q, o motivo pelo qual o consumer tem de permanecer idempotente e a migração que tem de ser executada antes de os testes passarem. O ficheiro de infra é onde define as regras que impedem um agent de causar danos. Nunca execute terraform apply. Execute terraform plan e pare aí. Indique também o state backend que já está configurado, para que o agent não tente inicializar outro.

Repare no que não aparece em nenhum destes ficheiros: uma descrição da finalidade de cada serviço. Isso é responsabilidade das pessoas. O projeto upstream estabelece a mesma separação ao afirmar que "os ficheiros README.md são para pessoas: inícios rápidos, descrições de projetos e orientações para contribuir", enquanto o AGENTS.md contém "o contexto adicional, por vezes detalhado, de que os coding agents precisam: passos de build, testes e convenções." A separação entre AGENTS.md e um README destinado às pessoas explica essa fronteira frase a frase. Já um DESIGN.md que regista o motivo pelo qual o código tem esta estrutura aborda o terceiro ficheiro, que explica decisões em vez de comandos.

Quem atualiza o ficheiro quando o código muda?

Existe uma regra, definida no ficheiro raiz: quem altera código num diretório atualiza o AGENTS.md desse diretório no mesmo commit.

Isto funciona por uma razão mecânica, não cultural. O ficheiro específico do diretório fica no mesmo diff que o código, por isso o revisor do pull request vê ambos ao mesmo tempo. Um ficheiro raiz pertence a todos, o que significa que não pertence a ninguém, e nunca aparece no diff que alguém já está a rever.

Associe a regra a uma verificação no pull request. Ela encontra o AGENTS.md mais próximo acima de cada ficheiro alterado e indica quando esse ficheiro não foi alterado.

#!/usr/bin/env bash
# Warn when code changed but the nearest AGENTS.md above it did not.
changed=$(git diff --name-only origin/main...HEAD)

nearest_doc() {
  d=$(dirname "$1")
  while [ "$d" != "." ]; do
    if [ -f "$d/AGENTS.md" ]; then echo "$d/AGENTS.md"; return; fi
    d=$(dirname "$d")
  done
  echo "AGENTS.md"
}

printf '%s\n' "$changed" | while read -r f; do
  [ -n "$f" ] || continue
  case "$f" in AGENTS.md|*/AGENTS.md) continue ;; esac
  doc=$(nearest_doc "$f")
  printf '%s\n' "$changed" | grep -Fqx "$doc" && continue
  echo "note: $f changed but $doc was not updated"
done

Numa branch que reestruturou o cliente da API sem alterar a documentação, a saída é semelhante a esta:

note: apps/web/src/api/client.ts changed but apps/web/AGENTS.md was not updated

Mantenha isto como um aviso, não como uma falha. Uma regra obrigatória leva as pessoas a adicionar uma linha em branco ao ficheiro para que o CI fique verde, e um ficheiro editado apenas para satisfazer um robô vale menos do que nenhum ficheiro. O aviso dá ao revisor uma pergunta para fazer. É essa parte que funciona.

Como identificar um AGENTS.md desatualizado?

Há duas verificações que pode executar hoje e um sintoma que verá durante uma sessão.

Compare a data de cada ficheiro com a data do código que ele descreve. %cs mostra a data do commit como YYYY-MM-DD.

for f in $(git ls-files '*AGENTS.md'); do
  d=$(dirname "$f")
  printf '%s  doc:%s  code:%s\n' "$f" \
    "$(git log -1 --format=%cs -- "$f")" \
    "$(git log -1 --format=%cs -- "$d")"
done
apps/web/AGENTS.md          doc:2026-02-11  code:2026-08-07
services/worker/AGENTS.md   doc:2026-07-29  code:2026-08-09
infra/AGENTS.md             doc:2026-08-01  code:2026-08-01

Uma documentação com data seis meses anterior à do código não prova que o ficheiro está errado. Indica qual ficheiro deve ler primeiro, e isso é tudo o que precisa de uma verificação que demora um segundo.

Procure caminhos que já não existem. A documentação deteriora-se de uma forma muito específica: continua a descrever código que foi eliminado. Todos os caminhos destes ficheiros estão escritos entre crases, por isso é fácil extraí-los e testá-los.

grep -o '`[^`]*`' apps/web/AGENTS.md | tr -d '`' | grep '/' | while read -r p; do
  [ -e "$p" ] || [ -e "apps/web/$p" ] || echo "missing: $p"
done

Leia o resultado em vez de integrar esta verificação no CI. Ela também assinala globs como src/**/*.ts e qualquer URL que tenha colocado entre aspas, porque ambos contêm uma barra e nenhum deles é um ficheiro no disco.

O sintoma numa sessão. O agente lê o ficheiro, tenta abrir src/api/client.ts porque o ficheiro lhe indicou esse caminho, e a ferramenta devolve:

No such file or directory

Por isso, faz o que é razoável e escreve o seu próprio wrapper fetch. Esse é o custo real de um ficheiro desatualizado. O agente não ignora a sua documentação. Segue a documentação, chega a um caminho que foi eliminado há três meses e recria código que já existe. Uma skill como Ponytail, que obriga o agente a fazer a menor alteração que funcione, torna esse impulso de recriação menos frequente, mas não consegue encontrar um helper para o qual o ficheiro apontou o caminho errado.

O Claude Code lê ficheiros AGENTS.md?

Não, e é importante deixar isso claro porque a estrutura aninhada depende desse comportamento. Em agosto de 2026, a documentação afirma: "O Claude Code lê CLAUDE.md, não AGENTS.md." O padrão continua a funcionar; basta criar um CLAUDE.md junto de cada AGENTS.md.

A forma de importação é adequada quando pretende adicionar linhas específicas da ferramenta às linhas partilhadas. Coloque isto em services/worker/CLAUDE.md:

@AGENTS.md

## Claude Code

Use plan mode for changes under `services/worker/migrations/`.

A forma com symlink é adequada quando não há configurações específicas da ferramenta a adicionar.

git ls-files '*AGENTS.md' | while read -r f; do
  ln -s AGENTS.md "$(dirname "$f")/CLAUDE.md"
done
ls -l apps/web/CLAUDE.md

ln não produz saída quando é executado com sucesso, por isso confirme a listagem com apps/web/CLAUDE.md -> AGENTS.md. Em seguida, inicie uma sessão e execute /context; os ficheiros carregados aparecem em Memory files. No Windows, um symlink requer privilégios de Administrator ou Developer Mode, por isso use a importação @AGENTS.md nesse sistema.

Há uma armadilha relacionada com isto. Depois de /compact, o ficheiro raiz é lido novamente a partir do disco, mas os ficheiros aninhados nos subdiretórios não são injetados novamente. Eles voltam a ser carregados na próxima vez que o agente ler um ficheiro nesse diretório. Se uma regra específica de um diretório parecer deixar de ser aplicada a meio de uma sessão longa, normalmente essa é a causa. Alterar qualquer ficheiro do diretório faz com que a regra seja carregada novamente.

Definições que apontam outros agentes para AGENTS.md

O Codex lê AGENTS.md nativamente. Em cada nível, verifica primeiro AGENTS.override.md, permitindo aplicar uma substituição local a um diretório sem editar o ficheiro partilhado. Para de combinar ficheiros quando o tamanho total atinge 32 KiB, o valor predefinido de project_doc_max_bytes. Esse é mais um motivo para manter o ficheiro raiz pequeno.

O Aider obtém essa configuração através de .aider.conf.yml, com a linha read: AGENTS.md.

O Gemini CLI obtém essa configuração através de .gemini/settings.json, com { "context": { "fileName": "AGENTS.md" } }.

A documentação upstream descreve uma renomeação compatível com versões anteriores para repositórios que ainda usam o nome singular antigo: mv AGENT.md AGENTS.md && ln -s AGENTS.md AGENT.md.

Num monorepo muito grande, a definição claudeMdExcludes do Claude Code ignora ficheiros ancestrais por caminho ou glob. Isto é útil quando o diretório de outra equipa está acima do seu.

Como isto é diferente da memória do agente ou de uma skill?

Estes mecanismos parecem semelhantes, mas falham de formas completamente diferentes. Por isso, é importante identificar com precisão qual deles pretende usar.

AGENTS.md é escrito por si, enviado para o git, revisto num pull request e igual para todas as pessoas que clonarem o repositório. A memória do agente é escrita pelo agente, armazenada fora do repositório e local a uma máquina. A documentação do Claude Code estabelece a mesma distinção: CLAUDE.md contém "Instruções e regras" que escreve, a memória automática contém "Aprendizagens e padrões" que o Claude escreve, e o diretório de memória não é partilhado entre máquinas. O teste é simples. Se um facto tiver de ser válido para um colega que faça um clone novo, não pode ficar na memória. Como a memória do agente persiste entre sessões aborda essa parte.

Uma skill é a terceira opção. AGENTS.md é contexto carregado em todas as sessões; uma skill é um procedimento carregado quando é necessário. A documentação do Claude Code apresenta uma regra útil: "Se uma entrada for um procedimento com várias etapas ou só for relevante para uma parte da base de código, mova-a para uma skill ou para uma regra limitada a um caminho." A segunda parte dessa frase corresponde exatamente ao que um AGENTS.md aninhado resolve. A primeira parte corresponde ao objetivo de skills de agente e, quando o mesmo procedimento for necessário em mais do que um repositório, deve partilhar a skill entre repositórios em vez de colar os mesmos parágrafos em dez ficheiros AGENTS.md diferentes.

O projeto upstream indica que "no momento da redação, o repositório principal da OpenAI tem 88 ficheiros AGENTS.md". Esse número resume todo o argumento. Um repositório grande não precisa de um ficheiro maior. Precisa de mais ficheiros pequenos, cada um junto do código que descreve e sob responsabilidade de quem alterou esse código pela última vez.

FAQ

Um ficheiro AGENTS.md aninhado substitui o ficheiro raiz ou é adicionado a ele?

É adicionado a ele. A documentação upstream diz que "o ficheiro mais próximo tem precedência", o que descreve o que acontece num conflito, não o que é carregado. O Codex "concatena os ficheiros da raiz para baixo, juntando-os com linhas em branco", e o Claude Code concatena todos os ficheiros encontrados ao subir a partir do diretório de trabalho, em vez de os substituir. O ficheiro mais próximo só prevalece quando dois ficheiros dão instruções diferentes sobre o mesmo assunto. Escreva as regras partilhadas uma vez no ficheiro raiz e não as repita em todos os diretórios.

Qual deve ser o tamanho do AGENTS.md raiz?

Deve ser suficientemente pequeno para não se importar que seja incluído no início de todos os pedidos que fizer nesse repositório, porque é isso que acontece. A documentação do Claude Code sugere manter cada ficheiro abaixo de 200 linhas e avisa que ficheiros mais longos "reduzem a adesão". Por predefinição, o Codex deixa de combinar ficheiros de instruções quando o total ultrapassa 32 KiB. Se o ficheiro raiz documentar quatro serviços, a maior parte do conteúdo será desnecessária para qualquer tarefa individual. Mova os detalhes para ficheiros específicos de cada diretório e deixe um mapa no ficheiro raiz.

Como impeço que estes ficheiros fiquem desatualizados?

Adicione uma regra ao ficheiro raiz: quem alterar código num diretório atualiza o AGENTS.md desse diretório no mesmo commit. Colocar o ficheiro junto ao código faz com que a regra seja cumprida, porque a alteração fica no mesmo diff do pull request que uma pessoa já está a analisar. Adicione um aviso de CI que associe cada caminho alterado ao AGENTS.md mais próximo acima dele e, periodicamente, compare git log -1 --format=%cs em cada ficheiro com o mesmo comando executado no diretório que esse ficheiro documenta.

O Claude Code lê ficheiros AGENTS.md?

Não. Em agosto de 2026, a documentação afirma que "o Claude Code lê CLAUDE.md, não AGENTS.md." Crie um CLAUDE.md no mesmo diretório, com @AGENTS.md na primeira linha. Isto carrega o ficheiro partilhado e permite adicionar instruções específicas do Claude abaixo dele. Um link simbólico criado com ln -s AGENTS.md CLAUDE.md funciona quando não há mais nada a adicionar, mas no Windows requer direitos de Administrador ou o Modo de Programador. Execute /context numa sessão e confirme que o ficheiro aparece em Memory files.

Onde coloco uma regra que só é relevante algumas vezes?

Não no AGENTS.md. Esse ficheiro é carregado em todas as sessões, por isso cada linha compete pela atenção com o pedido que escreveu. Um procedimento com vários passos, necessário apenas ocasionalmente, deve ficar numa skill, que é carregada quando necessário. Uma regra aplicável a um único diretório deve ficar no AGENTS.md desse diretório. Um facto que o agente consegue ler diretamente no código, como a árvore de diretórios ou a lista de dependências, não deve ficar em nenhum dos dois.