AGENTS.md imbriqués pour un monorepo
Découvrez pourquoi un AGENTS.md unique devient obsolète et comment répartir les règles par service pour réduire le contexte lu par l’agent.
Ce que signifie un fichier AGENTS.md imbriqué dans un monorepo
Un fichier AGENTS.md imbriqué dans un monorepo consiste à placer un petit fichier à la racine du dépôt, puis un autre fichier dans chaque répertoire de service. Le fichier racine contient les quelques règles valables partout, ainsi qu’une carte indiquant où se trouvent les autres fichiers. Chaque fichier de service contient les commandes et les conventions propres à ce répertoire. Un agent qui modifie services/worker/queue.py lit alors le fichier racine et celui du worker, sans utiliser de contexte pour le front-end auquel il ne touchera jamais.
Il n’y a rien à installer. AGENTS.md est une convention, et le projet en amont l’indique clairement :
AGENTS.md est simplement du Markdown standard. Utilisez les niveaux de titre de votre choix ; l’agent analyse simplement le texte que vous lui fournissez.
C’est pourquoi cette technique mérite d’être correctement maîtrisée. Le format ne changera pas sans que vous le sachiez. En revanche, l’emplacement et la maintenance peuvent poser problème, et ces deux aspects relèvent de votre responsabilité.
Pourquoi un seul AGENTS.md à la racine finit-il par ne plus fonctionner ?
Un fichier AGENTS.md unique de 600 lignes à la racine d’un dépôt qui contient une application web, un worker en arrière-plan et un répertoire Terraform échoue de quatre façons distinctes.
Il devient obsolète, car personne n’en est responsable. L’ingénieur qui renomme un script de test dans apps/web modifie des fichiers sous apps/web. Le fichier AGENTS.md racine ne figure pas dans ce diff, donc aucun reviewer ne voit l’incohérence. Six semaines plus tard, le fichier décrit une étape de build qui n’existe plus, et la personne à l’origine de la modification a oublié ce changement.
Il consomme du contexte à chaque tâche. Ces fichiers sont chargés au début de la session, avant que l’agent sache ce que vous allez lui demander. La documentation de Claude Code donne un objectif chiffré : « visez moins de 200 lignes par fichier CLAUDE.md. Les fichiers plus longs consomment davantage de contexte et réduisent le respect des instructions ». Codex arrête de fusionner les fichiers d’instructions lorsque leur taille cumulée atteint 32 KiB, la valeur par défaut de project_doc_max_bytes. Un fichier racine qui documente quatre services consomme ce budget avec trois d’entre eux à chaque tâche.
Les instructions commencent à se contredire. Le répertoire web impose pnpm test. Le worker impose pytest -q. Dans un même fichier, chaque règle n’est correcte que dans certains cas ; l’agent doit donc deviner laquelle s’applique. La documentation de Claude Code décrit le résultat : « si deux règles se contredisent, Claude peut en choisir une arbitrairement ». Un fichier propre à chaque répertoire élimine ce choix, car une seule des deux règles se trouve alors dans le contexte. Lorsqu’une règle que vous êtes certain d’avoir écrite clairement est malgré tout ignorée, comprendre les raisons pour lesquelles une instruction ne prend pas effet est plus efficace que de réécrire sa formulation une quatrième fois.
Il se remplit d’informations que l’agent peut lire dans le code. Une arborescence, une liste de dépendances, un résumé du rôle de chaque package. Le contrôle /doctor de Claude Code sert précisément à supprimer ce contenu. Il « supprime les informations que Claude peut déduire du codebase, comme les arborescences, les listes de dépendances et les vues d’ensemble de l’architecture » et conserve « les pièges, la justification des choix et les conventions qui diffèrent des valeurs par défaut des outils ». Cette phrase constitue le meilleur test que je connaisse pour déterminer si une ligne doit réellement figurer dans le fichier.
L’agent lit-il le fichier à la racine, ou uniquement le fichier le plus proche ?
C’est sur ce point que la plupart des utilisateurs se trompent. Il est donc préférable de reprendre la convention officielle plutôt que de la paraphraser :
Placez un autre fichier AGENTS.md dans chaque package. Les agents lisent automatiquement le fichier le plus proche dans l’arborescence. Le fichier le plus proche est donc prioritaire, et chaque sous-projet peut fournir des instructions adaptées.
Et en cas de conflit :
Le fichier AGENTS.md le plus proche du fichier modifié est prioritaire ; les prompts explicites de l’utilisateur dans le chat remplacent toutes les autres instructions.
Pour beaucoup, « est prioritaire » signifie que « le fichier à la racine est ignoré ». Ce n’est pas le cas. Dans les outils qui appliquent cette convention, tous les fichiers situés entre la racine du repository et le répertoire de travail sont lus et concaténés. Le fichier le plus proche est prioritaire uniquement lorsque deux fichiers donnent des instructions différentes sur le même sujet.
Codex décrit explicitement ce mécanisme : « Codex concatène les fichiers depuis la racine, en les séparant par des lignes vides. Les fichiers plus proches de votre répertoire actuel remplacent les instructions précédentes. » Claude Code parcourt la même arborescence pour rechercher son propre nom de fichier. Les fichiers situés dans les répertoires au-dessus du répertoire de travail « sont chargés intégralement au démarrage », et « tous les fichiers détectés sont concaténés dans le contexte au lieu de se remplacer mutuellement ». Les répertoires situés sous le répertoire de travail fonctionnent différemment : Claude Code charge ces fichiers à la demande, « lorsque Claude lit des fichiers dans ces répertoires ».
Deux conséquences pratiques en découlent. Le fichier à la racine est un préfixe de chaque session dans le repository. Considérez donc chaque ligne comme une ligne dont le coût est payé une centaine de fois par semaine. Un fichier propre à un répertoire ne coûte rien lorsque l’agent travaille ailleurs. Vous pouvez donc y placer les détails, qui sont ainsi moins coûteux.
Ce comportement a été vérifié dans la documentation de Codex et de Claude Code en août 2026. Les outils appliquent cette convention de manière légèrement différente et leur fonctionnement évolue. Vérifiez donc les règles de chargement de l’agent utilisé par votre équipe.
Une structure adaptée à un dépôt contenant trois services
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 scriptsLe fichier racine est volontairement court. Il indique où chercher et contient uniquement les règles qui s’appliquent à tous les répertoires.
# 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.Le fichier propre à chaque répertoire contient les détails. Sa longueur dépend de ce que le répertoire nécessite.
# 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.Le fichier du worker suit la même structure, avec un contenu différent : la commande d’installation, pytest -q, la raison pour laquelle le consumer doit rester idempotent et la migration qui doit s’exécuter avant la réussite des tests. Le fichier d’infrastructure contient les règles qui empêchent un agent de causer des dommages. N’exécutez jamais terraform apply. Exécutez terraform plan, puis arrêtez-vous là. Indiquez également le state backend déjà configuré afin que l’agent n’essaie pas d’en initialiser un nouveau.
Remarquez ce qui ne figure dans aucun de ces fichiers : une description du rôle de chaque service. Cette information est destinée aux utilisateurs. Le projet amont établit la même distinction : « les fichiers README.md sont destinés aux utilisateurs : guides de démarrage rapide, descriptions de projet et consignes de contribution », tandis que AGENTS.md contient « le contexte supplémentaire, parfois détaillé, dont les agents de programmation ont besoin : étapes de build, tests et conventions ». La séparation entre AGENTS.md et un README destiné aux utilisateurs examine cette limite phrase par phrase. Le fichier DESIGN.md qui explique pourquoi le code est structuré ainsi présente le troisième fichier, celui qui explique les décisions plutôt que les commandes.
Qui met à jour le fichier quand le code change ?
Une seule règle, à placer dans le fichier racine : toute personne qui modifie du code dans un répertoire met à jour le fichier AGENTS.md de ce répertoire dans le même commit.
Cette règle fonctionne pour une raison mécanique, et non culturelle. Le fichier propre au répertoire apparaît dans le même diff que le code. Le reviewer de la pull request voit donc les deux en même temps. Un fichier racine concerne tout le monde, donc personne en particulier. Il n’apparaît jamais dans le diff que quelqu’un est déjà en train de lire.
Ajoutez un contrôle sur la pull request. Il recherche le fichier AGENTS.md le plus proche au-dessus de chaque fichier modifié, puis signale les cas où ce fichier n’a pas été modifié.
#!/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"
doneSur une branche qui a remanié le client API sans modifier la documentation, la sortie ressemble à ceci :
note: apps/web/src/api/client.ts changed but apps/web/AGENTS.md was not updatedConservez ce contrôle sous forme d’avertissement plutôt que d’en faire un échec. Un blocage strict apprend aux utilisateurs à ajouter une ligne vide au fichier pour faire passer la CI au vert. Un fichier modifié uniquement pour satisfaire un robot vaut moins que l’absence de fichier. L’avertissement donne au reviewer une question à poser. C’est cette partie qui fonctionne réellement.
Comment repérer un fichier AGENTS.md devenu obsolète ?
Vous pouvez effectuer deux vérifications dès aujourd’hui et observer un symptôme pendant une session.
Comparez l’ancienneté de chaque fichier avec celle du code qu’il décrit. %cs affiche la date du commit au format 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-01Une documentation datant de six mois avant le code ne prouve pas que le fichier est incorrect. Elle vous indique quel fichier lire en premier. C’est tout ce que vous devez attendre d’une vérification qui prend une seconde.
Recherchez les chemins qui n’existent plus. La documentation se dégrade d’une manière très précise : elle continue de décrire du code qui a été supprimé. Chaque chemin de ces fichiers est écrit entre backticks. Il est donc facile de les extraire et de les tester.
grep -o '`[^`]*`' apps/web/AGENTS.md | tr -d '`' | grep '/' | while read -r p; do
[ -e "$p" ] || [ -e "apps/web/$p" ] || echo "missing: $p"
doneLisez le résultat plutôt que d’intégrer cette vérification à la CI. Elle signale également les globs tels que src/**/*.ts et toute URL que vous avez mise entre guillemets, car les deux contiennent une barre oblique et aucun des deux ne correspond à un fichier présent sur le disque.
Le symptôme pendant une session. L’agent lit le fichier, tente d’ouvrir src/api/client.ts parce que le fichier le lui indique, puis l’outil renvoie :
No such file or directoryIl fait donc ce qui semble raisonnable et écrit son propre wrapper fetch. C’est le véritable coût d’un fichier obsolète. L’agent n’ignore pas votre documentation. Il la suit, arrive sur un chemin supprimé trois mois auparavant et recrée du code que vous avez déjà. Une compétence telle que Ponytail, qui oblige un agent à appliquer la plus petite modification fonctionnelle, rend cette tendance à recréer le code moins fréquente, mais elle ne peut pas trouver un helper vers lequel votre fichier pointait au mauvais endroit.
Claude Code lit-il les fichiers AGENTS.md ?
Non. Il est important de le préciser, car l’organisation imbriquée en dépend. En août 2026, la documentation indique : « Claude Code lit CLAUDE.md, pas AGENTS.md. » Le modèle reste utilisable, mais vous devez placer un CLAUDE.md à côté de chaque AGENTS.md.
La méthode par import convient lorsque vous souhaitez ajouter des lignes propres à l’outil aux lignes communes. Placez ceci dans services/worker/CLAUDE.md :
@AGENTS.md
## Claude Code
Use plan mode for changes under `services/worker/migrations/`.La méthode par lien symbolique convient lorsqu’il n’y a aucune configuration propre à l’outil à ajouter.
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 n’affiche rien en cas de réussite. Vérifiez donc la liste avec apps/web/CLAUDE.md -> AGENTS.md. Démarrez ensuite une session et exécutez /context. Les fichiers chargés apparaissent sous Memory files. Sous Windows, la création d’un lien symbolique nécessite les droits Administrator ou le Developer Mode. Utilisez donc l’import @AGENTS.md à la place.
Un piège mérite d’être signalé. Après /compact, le fichier racine est relu depuis le disque, mais les fichiers imbriqués dans les sous-répertoires ne sont pas réinjectés. Ils réapparaissent la prochaine fois que l’agent lit un fichier de ce répertoire. Si une règle propre à un répertoire semble cesser de s’appliquer au cours d’une longue session, c’est généralement la cause. Touchez n’importe quel fichier du répertoire pour la réactiver.
Paramètres qui indiquent à d’autres agents d’utiliser AGENTS.md
Codex lit AGENTS.md nativement. À chaque niveau, il recherche d’abord AGENTS.override.md. Cela permet de définir une surcharge locale pour un répertoire sans modifier le fichier partagé. La fusion s’arrête lorsque la taille combinée atteint 32 KiB, valeur par défaut de project_doc_max_bytes. C’est une raison supplémentaire de conserver un fichier racine de petite taille.
Aider le prend en charge via .aider.conf.yml avec la ligne read: AGENTS.md.
Gemini CLI le prend en charge via .gemini/settings.json avec { "context": { "fileName": "AGENTS.md" } }.
La documentation amont décrit un renommage rétrocompatible pour les dépôts qui utilisent encore l’ancien nom au singulier : mv AGENT.md AGENTS.md && ln -s AGENTS.md AGENT.md.
Dans un très grand monorepo, le paramètre claudeMdExcludes de Claude Code ignore les fichiers des répertoires parents selon leur chemin ou leur glob. Cette option est utile lorsqu’un répertoire appartenant à une autre équipe se trouve au-dessus du vôtre.
En quoi cela diffère-t-il de la mémoire de l’agent ou d’une skill ?
Ces mécanismes semblent similaires, mais leurs modes d’échec sont complètement différents. Il est donc utile de déterminer précisément lequel vous devez utiliser.
AGENTS.md est rédigé par vous, versionné dans git, relu dans une pull request et identique pour toutes les personnes qui clonent le repository. La mémoire de l’agent est écrite par l’agent, stockée en dehors du repository et propre à une seule machine. La documentation de Claude Code établit la même distinction : CLAUDE.md contient les « Instructions and rules » que vous écrivez, la mémoire automatique contient les « Learnings and patterns » que Claude écrit, et le répertoire de mémoire n’est pas partagé entre les machines. Le test est simple. Si un fait doit être vrai pour un collègue qui effectue un clone vierge, il ne peut pas être stocké dans la mémoire. Comment la mémoire de l’agent est conservée entre les sessions couvre cette partie.
Une skill est le troisième élément. AGENTS.md fournit un contexte chargé à chaque session ; une skill fournit une procédure chargée lorsque cela est nécessaire. La documentation de Claude Code donne une règle pratique : « Si une entrée décrit une procédure en plusieurs étapes ou ne concerne qu’une partie du codebase, déplacez-la dans une skill ou dans une règle limitée à un chemin. » La seconde moitié de cette phrase décrit précisément le rôle d’un AGENTS.md imbriqué. La première concerne les skills d’agent ; lorsque la même procédure est nécessaire dans plusieurs repositories, partagez la skill entre les repositories au lieu de copier les mêmes paragraphes dans dix fichiers AGENTS.md différents.
Le projet amont indique qu’« au moment de la rédaction, le repository principal d’OpenAI contient 88 fichiers AGENTS.md ». Ce nombre résume tout l’argument. Un gros repository n’a pas besoin d’un fichier plus long. Il a besoin de davantage de petits fichiers, chacun placé à côté du code qu’il décrit et géré par la personne qui a modifié ce code en dernier.
FAQ
Un fichier AGENTS.md imbriqué remplace-t-il le fichier racine ou s’y ajoute-t-il ?
Il s’y ajoute. La documentation amont indique que « le fichier le plus proche est prioritaire ». Cela décrit le comportement en cas de conflit, et non les fichiers chargés. Codex « concatène les fichiers depuis la racine vers les sous-répertoires en les séparant par des lignes vides », tandis que Claude Code concatène tous les fichiers trouvés en remontant depuis le répertoire de travail, au lieu de les remplacer. Le fichier le plus proche est prioritaire uniquement lorsque deux fichiers donnent des instructions différentes sur le même sujet. Écrivez les règles communes une seule fois à la racine et ne les répétez pas dans chaque répertoire.
Quelle doit être la taille du fichier AGENTS.md racine ?
Il doit être suffisamment court pour que vous ne voyiez aucun inconvénient à l’ajouter au début de chaque requête effectuée dans ce dépôt, car c’est ce qui se produit. La documentation de Claude Code recommande de viser moins de 200 lignes par fichier et avertit que les fichiers plus longs « réduisent le respect des instructions ». Par défaut, Codex cesse de fusionner les fichiers d’instructions lorsque leur taille combinée dépasse 32 KiB. Si votre fichier racine documente quatre services, la majeure partie de son contenu est inutile pour une tâche donnée. Déplacez les détails dans des fichiers propres à chaque répertoire et laissez une vue d’ensemble à la racine.
Comment éviter que ces fichiers deviennent obsolètes ?
Ajoutez une règle dans le fichier racine : toute personne qui modifie du code dans un répertoire met à jour le fichier AGENTS.md de ce répertoire dans le même commit. Placer le fichier à côté du code permet de faire respecter cette règle, car la modification apparaît alors dans la même diff de pull request qu’une personne examine déjà. Ajoutez un avertissement CI qui associe chaque chemin modifié au fichier AGENTS.md le plus proche dans les répertoires parents, puis comparez régulièrement git log -1 --format=%cs de chaque fichier avec l’exécution de la même commande dans le répertoire qu’il documente.
Claude Code lit-il les fichiers AGENTS.md ?
Non. En août 2026, la documentation indique que « Claude Code lit CLAUDE.md, et non AGENTS.md ». Créez un fichier CLAUDE.md dans le même répertoire, avec @AGENTS.md sur la première ligne. Cela charge le fichier commun et vous permet d’ajouter ensuite des instructions propres à Claude. Un lien symbolique créé avec ln -s AGENTS.md CLAUDE.md fonctionne lorsqu’aucune instruction supplémentaire n’est nécessaire. Sous Windows, il nécessite toutefois les droits Administrator ou le Developer Mode. Exécutez /context dans une session et vérifiez que le fichier apparaît sous Memory files.
Où placer une règle qui ne s’applique que dans certains cas ?
Pas dans AGENTS.md. Ce fichier est chargé à chaque session. Chaque ligne entre donc en concurrence avec la requête que vous avez réellement saisie. Une procédure en plusieurs étapes, nécessaire seulement à l’occasion, doit se trouver dans une skill, chargée à la demande. Une règle qui s’applique à un seul répertoire doit se trouver dans le fichier AGENTS.md de ce répertoire. Un fait que l’agent peut lire directement dans le code, comme l’arborescence ou la liste des dépendances, ne doit figurer dans aucun de ces fichiers.