AGENTS.md annidati per un monorepo
Un unico AGENTS.md nella root diventa obsoleto e consuma contesto inutile. Scopri come distribuire regole e comandi nelle directory dei servizi.
Cosa significa AGENTS.md annidato in un monorepo
AGENTS.md annidati in un monorepo significa avere un file di piccole dimensioni nella radice del repository e un altro file all’interno della directory di ciascun servizio. Il file nella radice contiene le poche regole valide ovunque e una mappa che indica dove si trovano gli altri file. Ogni file del servizio contiene i comandi e le convenzioni applicabili esclusivamente a quella directory. Un agente che modifica services/worker/queue.py legge quindi il file nella radice e quello del worker, senza utilizzare contesto per il front end che non dovrà mai modificare.
Non c’è nulla da installare. AGENTS.md è una convenzione, come dichiara chiaramente il progetto upstream:
AGENTS.md è semplice Markdown standard. Usa le intestazioni che preferisci; l’agente analizza semplicemente il testo fornito.
Per questo vale la pena imparare correttamente questa tecnica. Il formato non cambierà senza preavviso. I problemi derivano dal posizionamento e dalla manutenzione, e la responsabilità per entrambi è tua.
Perché un unico AGENTS.md nella root smette di funzionare?
Un singolo AGENTS.md di 600 righe nella root di un repository che contiene una web app, un background worker e una directory Terraform presenta quattro problemi distinti.
Diventa obsoleto perché nessuno ne è responsabile. L’ingegnere che rinomina uno script di test in apps/web sta modificando file sotto apps/web. Il file AGENTS.md nella root non compare in quel diff, quindi nessun reviewer vede la discrepanza. Sei settimane dopo, il file descrive ancora una fase di build che non esiste più e la persona che ha introdotto la modifica ha dimenticato il cambiamento.
Consuma contesto per ogni attività. Questi file vengono caricati all’inizio della sessione, prima che l’agente sappia cosa gli verrà chiesto. La documentazione di Claude Code indica un valore preciso: "target under 200 lines per CLAUDE.md file. Longer files consume more context and reduce adherence." Codex smette di unire i file di istruzioni quando la loro dimensione complessiva raggiunge 32 KiB, il valore predefinito di project_doc_max_bytes. Un file nella root che documenta quattro servizi consuma quel budget per tre di essi durante ogni attività.
Le istruzioni iniziano a contraddirsi. La directory web richiede pnpm test. Il worker richiede pytest -q. Inserite nello stesso file, entrambe le regole sono corrette solo in alcuni casi, quindi l’agente deve indovinare quale si applica. La documentazione di Claude Code descrive il risultato in questo modo: "if two rules contradict each other, Claude may pick one arbitrarily." Un file per directory elimina l’ambiguità, perché nel contesto è presente una sola delle due regole. Quando una regola che siete certi di avere scritto chiaramente viene comunque ignorata, analizzare i motivi per cui un’istruzione non viene mai applicata è più utile che riscrivere per la quarta volta la formulazione.
Si riempie di informazioni che l’agente può ricavare dal codice. Una struttura delle directory, un elenco delle dipendenze, un riepilogo del ruolo di ogni package. Il controllo /doctor di Claude Code serve proprio a rimuovere questo tipo di contenuti. "cuts content Claude can derive from the codebase, such as directory layouts, dependency lists, and architecture overviews" e conserva "pitfalls, rationale, and conventions that differ from tool defaults." Questa frase è il criterio migliore che conosco per stabilire se una riga debba essere presente nel file.
L’agente legge il file nella directory root o soltanto quello più vicino?
È qui che la maggior parte delle persone interpreta il modello in modo errato. Per questo è utile riportare la convenzione upstream invece di parafrasarla:
Inserisci un altro AGENTS.md in ogni package. Gli agenti leggono automaticamente il file più vicino nella struttura delle directory, quindi quello più vicino ha la precedenza e ogni subproject può distribuire istruzioni personalizzate.
E per quanto riguarda i conflitti:
Ha la precedenza l’AGENTS.md più vicino al file modificato; i prompt espliciti dell’utente nella chat hanno la precedenza su tutto.
Per molte persone, «ha la precedenza» significa che «il file nella root viene ignorato». Non è così. Negli strumenti che implementano questa convenzione, viene letto ogni file lungo il percorso dalla root del repository fino alla working directory e il contenuto viene unito. Il file più vicino ha la precedenza soltanto quando due file definiscono istruzioni diverse sullo stesso argomento.
Codex descrive esplicitamente il meccanismo: «Codex concatena i file dalla root verso il basso, separandoli con righe vuote. I file più vicini alla directory corrente sostituiscono le indicazioni precedenti». Claude Code segue lo stesso percorso per il proprio nome file. I file nelle directory sopra la working directory «vengono caricati integralmente all’avvio» e «tutti i file rilevati vengono concatenati nel contesto, invece di sostituirsi a vicenda». Le directory sotto la working directory si comportano in modo diverso: Claude Code carica quei file su richiesta, «quando Claude legge file in tali directory».
Da qui derivano due conseguenze pratiche. Il file nella root è un prefisso di ogni sessione nel repository, quindi ogni riga al suo interno rappresenta un costo che sostieni cento volte alla settimana. Un file specifico per directory non comporta alcun costo quando l’agente lavora altrove. Per questo i dettagli possono essere inseriti lì e dovrebbero restare lì.
Questo comportamento è stato verificato nella documentazione di Codex e Claude Code nell’agosto 2026. Gli strumenti implementano la convenzione in modo leggermente diverso e possono modificarla, quindi verifica le regole di caricamento dell’agente utilizzato dal tuo team.
Una struttura concreta per un repository con tre servizi
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 scriptsIl file radice è volutamente breve. Indica dove cercare e contiene soltanto le regole valide in ogni directory.
# 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.Il file specifico della directory contiene i dettagli e può essere lungo quanto richiede la directory.
# 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.Il file del worker ha la stessa struttura, ma contenuti diversi: il comando di installazione, pytest -q, il motivo per cui il consumer deve restare idempotente e la migrazione da eseguire prima che i test abbiano esito positivo. Il file dell'infrastruttura contiene le regole che impediscono a un agente di causare danni. Non eseguire mai terraform apply. Esegui terraform plan e fermati, quindi indica il backend dello stato già configurato, così l'agente non proverà a inizializzarne uno nuovo.
Nessuno di questi file descrive lo scopo dei singoli servizi. Questo compito spetta alle persone. Il progetto upstream traccia la stessa distinzione e afferma che "i file README.md sono destinati alle persone: guide rapide, descrizioni dei progetti e linee guida per i contributi", mentre AGENTS.md contiene "il contesto aggiuntivo, talvolta dettagliato, di cui gli agenti di coding hanno bisogno: passaggi di compilazione, test e convenzioni". La distinzione tra AGENTS.md e un README rivolto alle persone analizza questo confine frase per frase, mentre un DESIGN.md che registra il motivo per cui il codice ha questa struttura tratta il terzo file, quello che spiega le decisioni anziché i comandi.
Chi aggiorna il file quando cambia il codice?
Basta una regola, da inserire nel file radice: chi modifica il codice in una directory aggiorna l'AGENTS.md di quella directory nello stesso commit.
Questa regola funziona per un motivo meccanico, non culturale. Il file specifico della directory si trova nello stesso diff del codice, quindi il revisore della pull request li vede contemporaneamente. Un file radice appartiene a tutti e, proprio per questo, non appartiene a nessuno: non compare mai nel diff che qualcuno sta già esaminando.
Fate rispettare la regola con un controllo sulla pull request. Il controllo individua l'AGENTS.md più vicino sopra ogni file modificato e segnala i casi in cui quel file non è stato modificato.
#!/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"
doneIn un branch che ha riscritto il client API senza modificare la documentazione, l'output è simile al seguente:
note: apps/web/src/api/client.ts changed but apps/web/AGENTS.md was not updatedMantenete il controllo come avviso, non come errore bloccante. Un controllo rigido insegna ad aggiungere una riga vuota al file solo per far risultare verde la CI, e un file modificato per soddisfare un controllo automatico vale meno di nessun file. L'avviso fornisce al revisore una domanda da porre: è questo l'elemento che funziona davvero.
Come individuare un file AGENTS.md non più aggiornato
Oggi è possibile eseguire due controlli e osservare un sintomo durante una sessione.
Confrontate la data di ogni file con quella del codice che descrive. %cs stampa la data del commit come 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")"
doneapps/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-01Una documentazione datata sei mesi prima del codice non dimostra che il file sia errato. Indica quale file leggere per primo, ed è tutto ciò che serve da un controllo che richiede un secondo.
Cercate i percorsi che non esistono più. La documentazione diventa obsoleta in un modo molto specifico: continua a descrivere codice che è stato eliminato. Ogni percorso in questi file è racchiuso tra backtick, quindi è facile estrarlo e verificarlo.
grep -o '`[^`]*`' apps/web/AGENTS.md | tr -d '`' | grep '/' | while read -r p; do
[ -e "$p" ] || [ -e "apps/web/$p" ] || echo "missing: $p"
doneLeggete l'output invece di integrare questo controllo in CI. Segnala anche glob come src/**/*.ts e qualsiasi URL racchiuso tra virgolette, perché entrambi contengono una barra e nessuno dei due è un file presente sul disco.
Il sintomo durante una sessione. L'agent legge il file, prova ad aprire src/api/client.ts perché il file glielo indica e lo strumento restituisce:
No such file or directoryA quel punto fa la cosa ragionevole e scrive il proprio wrapper fetch. Questo è il costo reale di un file non più aggiornato. L'agent non ignora la documentazione. La segue, arriva a un percorso eliminato tre mesi prima e ricostruisce codice che esiste già. Una skill come Ponytail, che vincola l'agent alla modifica minima efficace, rende meno frequente questo comportamento, ma non può trovare un helper a cui il file indicava il percorso sbagliato.
Claude Code legge i file AGENTS.md?
No. È importante dirlo esplicitamente, perché la struttura annidata dipende da questo comportamento. Ad agosto 2026 la documentazione afferma: «Claude Code legge CLAUDE.md, non AGENTS.md». Il metodo funziona comunque: basta aggiungere un CLAUDE.md accanto a ogni AGENTS.md.
La modalità di importazione è adatta quando vuoi aggiungere direttive specifiche per lo strumento a quelle condivise. Inserisci quanto segue in services/worker/CLAUDE.md:
@AGENTS.md
## Claude Code
Use plan mode for changes under `services/worker/migrations/`.La modalità con collegamento simbolico è adatta quando non devi aggiungere nulla di specifico per lo strumento.
git ls-files '*AGENTS.md' | while read -r f; do
ln -s AGENTS.md "$(dirname "$f")/CLAUDE.md"
done
ls -l apps/web/CLAUDE.mdln non stampa nulla se l'operazione riesce, quindi controlla l'elenco con apps/web/CLAUDE.md -> AGENTS.md. Avvia quindi una sessione ed esegui /context: i file caricati vengono visualizzati nella sezione Memory files. In Windows, per creare un collegamento simbolico servono i diritti di amministratore oppure la Developer Mode; usa quindi l'importazione @AGENTS.md.
C'è un'altra particolarità da considerare. Dopo /compact, il file radice viene riletto dal disco, ma i file annidati nelle sottodirectory non vengono reiniettati. Vengono ricaricati la volta successiva in cui l'agente legge un file in quella directory. Se una regola specifica per una directory sembra smettere di essere applicata durante una sessione lunga, questa è in genere la causa. È sufficiente modificare un file nella directory per ricaricarla.
Impostazioni che indicano ad altri agenti il file AGENTS.md
Codex legge AGENTS.md in modo nativo. A ogni livello controlla prima AGENTS.override.md, consentendo a una directory di definire un override locale senza modificare il file condiviso. Interrompe l'unione dei file quando la dimensione complessiva raggiunge 32 KiB, il valore predefinito di project_doc_max_bytes. Questo è un ulteriore motivo per mantenere piccolo il file radice.
Aider lo acquisisce tramite .aider.conf.yml con la riga read: AGENTS.md.
Gemini CLI lo acquisisce tramite .gemini/settings.json con { "context": { "fileName": "AGENTS.md" } }.
La documentazione upstream descrive una ridenominazione compatibile con le versioni precedenti per i repository che usano ancora il vecchio nome al singolare: mv AGENT.md AGENTS.md && ln -s AGENTS.md AGENT.md.
In un monorepo molto grande, l'impostazione claudeMdExcludes di Claude Code esclude i file degli antenati in base al percorso o a un glob. È utile quando la directory di un altro team si trova sopra la tua.
In che cosa differisce dalla memoria dell’agente o da una skill?
Questi meccanismi sembrano simili, ma presentano problemi completamente diversi. È quindi importante individuare con precisione quello da usare.
AGENTS.md viene scritto da voi, salvato in git, verificato tramite pull request ed è identico per tutti coloro che clonano il repository. La memoria dell’agente viene scritta dall’agente, salvata all’esterno del repository ed è locale a una singola macchina. La documentazione di Claude Code traccia la stessa distinzione: CLAUDE.md contiene le «Istruzioni e regole» scritte dall’utente, mentre la memoria automatica contiene gli «Apprendimenti e pattern» scritti da Claude; inoltre, la directory della memoria non viene condivisa tra macchine. Il criterio è semplice. Se un’informazione deve essere valida anche per un collega che esegue un nuovo clone, non può essere archiviata nella memoria. Come persiste la memoria dell’agente tra le sessioni tratta questa parte della distinzione.
Una skill è il terzo elemento. AGENTS.md contiene il contesto che viene caricato in ogni sessione; una skill contiene una procedura che viene caricata quando serve. La documentazione di Claude Code fornisce una regola utile: «Se una voce descrive una procedura composta da più passaggi o è rilevante soltanto per una parte del codebase, spostatela in una skill o in una regola associata a un percorso». La seconda parte della frase descrive esattamente il caso risolto da un AGENTS.md annidato. La prima riguarda le skill dell’agente; quando la stessa procedura serve in più repository, è preferibile condividere la skill tra i repository invece di copiare gli stessi paragrafi in dieci file AGENTS.md diversi.
Il progetto upstream osserva che «al momento della stesura, il repository principale di OpenAI contiene 88 file AGENTS.md». Questo numero riassume l’intero argomento. Un repository di grandi dimensioni non ha bisogno di un file più grande. Ha bisogno di più file piccoli, ciascuno accanto al codice che descrive e assegnato al responsabile dell’ultima modifica di quel codice.
FAQ
Un file AGENTS.md annidato sostituisce il file root o si aggiunge a esso?
Si aggiunge al file root. La documentazione upstream afferma che "ha la precedenza il file più vicino". Questa frase descrive cosa accade in caso di conflitto, non quali file vengono caricati. Codex "concatena i file dalla root verso il basso, separandoli con righe vuote", mentre Claude Code concatena tutti i file trovati risalendo dalla directory di lavoro, invece di sostituirli. Il file più vicino prevale solo quando due file forniscono istruzioni diverse sullo stesso argomento. Scrivi una sola volta le regole condivise nel file root e non ripeterle in ogni directory.
Quanto deve essere grande il file AGENTS.md root?
Deve essere abbastanza piccolo da non creare problemi se venisse incollato all'inizio di ogni richiesta che fai in quel repository, perché è esattamente ciò che accade. La documentazione di Claude Code suggerisce di mantenere ogni file sotto 200 righe e avverte che i file più lunghi "riducono l'aderenza". Per impostazione predefinita, Codex interrompe l'unione dei file di istruzioni quando la dimensione complessiva raggiunge 32 KiB. Se il file root documenta quattro servizi, gran parte del contenuto è irrilevante per una singola attività. Sposta i dettagli nei file delle singole directory e lascia un indice.
Come posso evitare che questi file diventino obsoleti?
Inserisci una regola nel file root: chi modifica il codice in una directory deve aggiornare l'AGENTS.md di quella directory nello stesso commit. Collocare il file accanto al codice rende effettiva questa regola, perché la modifica compare quindi nello stesso diff della pull request che una persona sta già esaminando. Aggiungi un avviso CI che associ ogni percorso modificato all'AGENTS.md più vicino nelle directory superiori e, a intervalli regolari, confronta git log -1 --format=%cs di ogni file con lo stesso comando eseguito sulla directory che il file documenta.
Claude Code legge i file AGENTS.md?
No. Ad agosto 2026 la documentazione afferma che "Claude Code legge CLAUDE.md, non AGENTS.md." Crea un CLAUDE.md nella stessa directory, con @AGENTS.md sulla prima riga. In questo modo carichi il file condiviso e puoi aggiungere sotto le istruzioni specifiche per Claude. Un link simbolico creato con ln -s AGENTS.md CLAUDE.md funziona quando non devi aggiungere altro, ma su Windows richiede i diritti di Administrator o la Developer Mode. Esegui /context in una sessione e verifica che il file compaia nella sezione Memory files.
Dove inserisco una regola che si applica solo in alcuni casi?
Non in AGENTS.md. Questo file viene caricato in ogni sessione, quindi ogni riga compete per l'attenzione con la richiesta che hai effettivamente scritto. Una procedura composta da più passaggi e necessaria solo occasionalmente appartiene a una skill, che viene caricata su richiesta. Una regola applicabile a una sola directory appartiene all'AGENTS.md di quella directory. Un'informazione che l'agente può ricavare direttamente dal codice, come l'albero delle directory o l'elenco delle dipendenze, non appartiene a nessuno dei due.