Geneste AGENTS.md bestanden in een monorepo gebruiken
Voorkom verouderde context en tokensverspilling door AGENTS.md bestanden te nesten. Leer hoe u per directory specifieke instructies beheert in plaats van één groot root-bestand.
Wat geneste AGENTS.md-bestanden betekenen in een monorepo
Geneste AGENTS.md-bestanden in een monorepo betekenen dat er één klein bestand in de root van de repository staat en één extra bestand in elke servicedirectory. Het root-bestand bevat de enkele regels die overal gelden, plus een overzicht van waar de andere bestanden zich bevinden. Elk servicebestand bevat de commando's en conventies die uitsluitend voor die directory gelden. Een agent die services/worker/queue.py bewerkt, leest vervolgens het root-bestand en het worker-bestand, en besteedt geen enkele context aan de front-end waar deze nooit mee in aanraking zal komen.
Er hoeft niets geïnstalleerd te worden. AGENTS.md is een conventie en het upstream-project stelt dit duidelijk:
AGENTS.md is gewoon standaard Markdown. Gebruik welke koppen u maar wilt; de agent parseert simpelweg de tekst die u aanlevert.
Daarom is het de moeite waard om deze techniek goed te leren. Het formaat zal niet zomaar veranderen. Wat wel kan falen is de plaatsing en het onderhoud, en beide zijn uw verantwoordelijkheid.
Waarom stopt één groot root AGENTS.md met werken?
Een enkel AGENTS.md-bestand van 600 regels in de root van een repository met daarin een web-app, een achtergrond-worker en een Terraform-directory faalt op vier verschillende punten.
Het veroudert omdat niemand er eigenaar van is. De engineer die een testscript hernoemt in apps/web, bewerkt bestanden onder apps/web. Het root AGENTS.md-bestand zit niet in die diff, dus geen enkele reviewer ziet de discrepantie. Zes weken later beschrijft het bestand een build-stap die niet meer bestaat, en de persoon die het heeft aangepast is de wijziging vergeten.
Het kost context bij elke taak. Deze bestanden worden geladen aan het begin van de sessie, voordat de agent weet wat u gaat vragen. De documentatie van Claude Code geeft hier een getal aan: "houd het doel onder de 200 regels per CLAUDE.md-bestand. Langere bestanden verbruiken meer context en verminderen de nauwkeurigheid." Codex stopt met het samenvoegen van instructiebestanden zodra hun gecombineerde grootte 32 KiB bereikt, de standaard project_doc_max_bytes. Een root-bestand dat vier services documenteert, verbruikt dat budget voor drie ervan bij elke afzonderlijke taak.
Instructies beginnen elkaar tegen te spreken. De web-directory vereist pnpm test. De worker vereist pytest -q. Wanneer deze in één bestand staan, is elke regel slechts een deel van de tijd correct, waardoor de agent moet raden welke van toepassing is. De documentatie van Claude Code beschrijft het resultaat: "als twee regels elkaar tegenspreken, kan Claude er willekeurig een kiezen." Een bestand per directory neemt het giswerk weg, omdat slechts één van de twee regels ooit in de context staat.
Het raakt gevuld met feiten die de agent uit de code kan lezen. Een directoryboom, een afhankelijkhedenlijst, een samenvatting van wat elk pakket doet. De /doctor-controle van Claude Code bestaat om precies dit te verwijderen. Het "snijdt inhoud weg die Claude uit de codebase kan afleiden, zoals directory-indelingen, afhankelijkhedenlijsten en architectuuroverzichten" en behoudt "valkuilen, rationale en conventies die afwijken van de standaardinstellingen van tools." Die zin is de beste test die ik ken om te bepalen of een regel überhaupt in het bestand thuishoort.
Leest de agent het root-bestand, of alleen het dichtstbijzijnde bestand?
Dit is het punt waar de meeste mensen de werking van het model verkeerd begrijpen. Daarom is het de moeite waard om de upstream-conventie te citeren in plaats van deze te parafraseren:
Plaats een extra AGENTS.md in elk pakket. Agents lezen automatisch het dichtstbijzijnde bestand in de mappenstructuur, dus het meest nabijgelegen bestand krijgt voorrang en elk subproject kan specifieke instructies bevatten.
En over conflicten:
Het AGENTS.md dat zich het dichtst bij het bewerkte bestand bevindt, wint; expliciete prompts van de gebruiker in de chat overschrijven alles.
"Krijgt voorrang" wordt door veel mensen gelezen als "het root-bestand wordt genegeerd". Dat is niet het geval. In de tools die deze conventie implementeren, wordt elk bestand op het pad vanaf de repository-root tot aan de werkmap gelezen en samengevoegd. Het dichtstbijzijnde bestand wint alleen wanneer twee bestanden verschillende instructies geven over hetzelfde onderwerp.
Codex is expliciet over het mechanisme: "Codex voegt bestanden samen vanaf de root naar beneden en verbindt ze met lege regels. Bestanden die dichter bij uw huidige map staan, overschrijven eerdere richtlijnen." Claude Code volgt hetzelfde pad voor zijn eigen bestandsnaam. Bestanden in de mappenhiërarchie boven de werkmap "worden volledig geladen bij het opstarten" en "alle gevonden bestanden worden samengevoegd in de context in plaats van elkaar te overschrijven." Mappen onder de werkmap gedragen zich anders: Claude Code laadt die bestanden op aanvraag, "wanneer Claude bestanden in die mappen leest."
Hieruit volgen twee praktische consequenties. Het root-bestand vormt een voorvoegsel voor elke sessie in de repository; behandel elke regel daar dus als een regel waarvoor u honderden keren per week betaalt. Een bestand per map kost niets wanneer de agent ergens anders werkt, wat betekent dat details daar goedkoop zijn en daar thuishoren.
Dit gedrag is in augustus 2026 gecontroleerd aan de hand van de documentatie van Codex en Claude Code. Tools implementeren de conventie op licht verschillende wijzen en ze veranderen, dus controleer de laadregels voor de agent die uw team gebruikt.
Een werkende lay-out voor een repository met drie 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 scriptsHet root-bestand is bewust kort gehouden. Het geeft aan waar gezocht moet worden en bevat alleen de regels die in elke directory gelden.
# 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.Het per-directory-bestand bevat de details en kan zo lang zijn als de directory vereist.
# 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.Het worker-bestand heeft dezelfde structuur maar met andere inhoud: het installatiecommando, pytest -q, de reden waarom de consumer idempotent moet blijven, en de migratie die moet draaien voordat de tests slagen. Het infra-bestand is de plek waar u de regels schrijft die voorkomen dat een agent schade aanricht. Voer nooit terraform apply uit. Voer terraform plan uit en stop daar, en specificeer de state backend die reeds geconfigureerd is, zodat de agent niet probeert een nieuwe te initialiseren.
Let op wat in geen van deze bestanden staat: een beschrijving van waar elke service voor dient. Dat is informatie voor mensen. Upstream trekt dezelfde grens en stelt: "README.md-bestanden zijn voor mensen: quick starts, projectbeschrijvingen en richtlijnen voor bijdragen", terwijl AGENTS.md "de extra, soms gedetailleerde context bevat die coding agents nodig hebben: build-stappen, tests en conventies." De scheiding tussen AGENTS.md en een mensgerichte README doorloopt zin voor zin die grens, en een DESIGN.md die vastlegt waarom de code op deze manier is vormgegeven behandelt het derde bestand, het bestand dat beslissingen uitlegt in plaats van commando's.
Wie werkt het bestand bij wanneer de code wijzigt?
Er geldt één regel, en deze staat in het root-bestand: wie code in een directory wijzigt, werkt in dezelfde commit het AGENTS.md-bestand van die directory bij.
Dit werkt om een mechanische reden, niet om een culturele. Het bestand per directory bevindt zich in dezelfde diff als de code, waardoor de reviewer van de pull request beide tegelijk ziet. Een root-bestand is van iedereen, wat betekent dat het van niemand is, en het zit nooit in de diff die iemand al aan het lezen is.
Ondersteun de regel met een controle op de pull request. Deze zoekt het dichtstbijzijnde AGENTS.md-bestand boven elk gewijzigd bestand en rapporteert wanneer dat bestand niet is aangepast.
#!/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"
doneOp een branch die de API-client heeft herzien zonder de documentatie aan te passen, ziet de output er als volgt uit:
note: apps/web/src/api/client.ts changed but apps/web/AGENTS.md was not updatedHoud het bij een waarschuwing in plaats van een blokkade. Een harde blokkade leert mensen om een lege regel aan het bestand toe te voegen zodat CI groen wordt; een bestand dat is bewerkt om een robot tevreden te stellen, is minder waard dan helemaal geen bestand. De waarschuwing geeft de reviewer een vraag om te stellen, en dat is het onderdeel dat daadwerkelijk werkt.
Hoe herken ik een verouderd AGENTS.md-bestand?
Er zijn twee controles die u vandaag kunt uitvoeren, en één symptoom dat u tijdens een sessie zult opmerken.
Vergelijk de ouderdom van elk bestand met de ouderdom van de code die het beschrijft. %cs toont de commit-datum als 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-01Een documentatiedatum die zes maanden achterloopt op de code-datum bewijst niet dat het bestand onjuist is. Het geeft alleen aan welk bestand u als eerste moet lezen, en dat is alles wat u nodig heeft van een controle die één seconde duurt.
Zoek naar paden die niet langer bestaan. Documentatie veroudert op een zeer specifieke manier: het blijft code beschrijven die is verwijderd. Elk pad in deze bestanden staat tussen backticks, waardoor ze eenvoudig te extraheren en te testen zijn.
grep -o '`[^`]*`' apps/web/AGENTS.md | tr -d '`' | grep '/' | while read -r p; do
[ -e "$p" ] || [ -e "apps/web/$p" ] || echo "missing: $p"
doneLees de uitvoer in plaats van dit proces te automatiseren in CI. Het markeert ook globs zoals src/**/*.ts en elke URL die u heeft geciteerd, omdat beide een slash bevatten en geen van beide een bestand op de schijf is.
Het symptoom in een sessie. De agent leest het bestand, probeert src/api/client.ts te openen omdat het bestand hem dat opdraagt, en de tool geeft het volgende terug:
No such file or directoryDe agent doet vervolgens het logische: hij schrijft zijn eigen fetch-wrapper. Dat is de werkelijke prijs van een verouderd bestand. De agent negeert uw documentatie niet. Hij volgt de documentatie, komt uit op een pad dat drie maanden geleden is verwijderd en herbouwt code die u al heeft. Een vaardigheid zoals Ponytail, die een agent dwingt tot de kleinst mogelijke werkende wijziging, maakt die herbouw-instincten zeldzamer, maar het kan geen helper vinden die in uw bestand naar de verkeerde locatie verwijst.
Leest Claude Code AGENTS.md-bestanden?
Nee, en dit is belangrijk om expliciet te vermelden omdat de geneste structuur hiervan afhankelijk is. Sinds augustus 2026 stelt de documentatie: "Claude Code leest CLAUDE.md, niet AGENTS.md." Het patroon werkt nog steeds, u moet alleen een CLAUDE.md naast elke AGENTS.md plaatsen.
De import-vorm is de juiste keuze wanneer u tool-specifieke regels wilt toevoegen boven op de gedeelde regels. Plaats dit in services/worker/CLAUDE.md:
@AGENTS.md
## Claude Code
Use plan mode for changes under `services/worker/migrations/`.De symlink-vorm is de juiste keuze wanneer er niets tool-specifieks hoeft te worden toegevoegd.
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 geeft geen uitvoer bij succes, controleer daarom de lijst met: apps/web/CLAUDE.md -> AGENTS.md. Start vervolgens een sessie en voer /context uit, waarbij de geladen bestanden verschijnen onder Memory files. Op Windows vereist een symlink Administrator-rechten of de Developer Mode; gebruik daar daarom de @AGENTS.md-import.
Er is één valkuil. Na /compact wordt het root-bestand opnieuw van schijf gelezen, maar geneste bestanden in submappen worden niet opnieuw geïnjecteerd. Deze worden weer geladen zodra de agent de volgende keer een bestand in die map leest. Als een regel per map halverwege een lange sessie niet meer lijkt te werken, is dit meestal de oorzaak; het aanpassen (touch) van een willekeurig bestand in die map herstelt de werking.
Instellingen die andere agents naar AGENTS.md verwijzen
Codex leest AGENTS.md standaard. Op elk niveau controleert het eerst op AGENTS.override.md, wat de mogelijkheid biedt om een lokale override voor één map toe te passen zonder het gedeelde bestand te bewerken. Het samenvoegen stopt zodra de gecombineerde grootte 32 KiB bereikt, de standaard project_doc_max_bytes; dit is een extra reden om het root-bestand klein te houden.
Aider gebruikt het via .aider.conf.yml met de regel read: AGENTS.md.
Gemini CLI gebruikt het via .gemini/settings.json met { "context": { "fileName": "AGENTS.md" } }.
De upstream-documentatie beschrijft een achterwaarts compatibele naamswijziging voor repositories die nog de oudere enkelvoudige naam gebruiken: mv AGENT.md AGENTS.md && ln -s AGENTS.md AGENT.md.
In een zeer grote monorepo slaat de claudeMdExcludes-instelling van Claude Code ancestor-bestanden over op basis van pad of glob, wat nuttig is wanneer de map van een ander team zich boven die van u bevindt.
Wat is het verschil met agentgeheugen of een skill?
Deze mechanismen lijken op elkaar, maar falen op totaal verschillende manieren. Het is daarom belangrijk om precies te bepalen welke u nodig heeft.
AGENTS.md wordt door u geschreven, naar git gecommit, beoordeeld in een pull request en is identiek voor iedereen die de repository kloont. Agentgeheugen wordt door de agent geschreven, buiten de repository opgeslagen en is lokaal aan één machine. De documentatie van Claude Code trekt dezelfde grens: CLAUDE.md bevat "Instructies en regels" die u schrijft, automatisch geheugen bevat "Leerpunten en patronen" die Claude schrijft, en de geheugenmap wordt niet gedeeld tussen machines. De test is eenvoudig. Als een feit waar moet zijn voor een collega met een verse kloon, kan het niet in het geheugen staan. Hoe agentgeheugen behouden blijft tussen sessies behandelt dat deel van het plaatje.
Een skill is het derde aspect. AGENTS.md is context die bij elke sessie wordt geladen; een skill is een procedure die wordt geladen wanneer deze nodig is. De documentatie van Claude Code geeft een bruikbare regel: "Als een item een procedure met meerdere stappen is of slechts voor één deel van de codebase relevant is, verplaats het dan naar een skill of een regel met een pad-scope." Het tweede deel van die zin is precies wat een geneste AGENTS.md oplost. Het eerste deel is waar agent skills voor bedoeld zijn, en wanneer dezelfde procedure in meer dan één repository nodig is, deel de skill tussen repo's in plaats van dezelfde alinea's in tien verschillende AGENTS.md-bestanden te plakken.
Upstream merkt op dat "op het moment van schrijven de hoofd-repository van OpenAI 88 AGENTS.md-bestanden bevat". Dat getal is het hele argument. Een grote repository heeft geen groter bestand nodig. Het heeft meer kleine bestanden nodig, elk naast de code die het beschrijft, en elk beheerd door degene die die code als laatste heeft gewijzigd.
FAQ
Vervangt een genest AGENTS.md het root-bestand of wordt het eraan toegevoegd?
Het wordt eraan toegevoegd. Upstream stelt dat "het dichtstbijzijnde bestand voorrang heeft", wat beschrijft wat er gebeurt bij een conflict, niet wat er wordt geladen. Codex "voegt bestanden vanaf de root naar beneden samen en scheidt ze met lege regels", en Claude Code voegt elk bestand samen dat het tegenkomt tijdens het doorlopen van de mappenstructuur vanaf de werkmap, in plaats van ze te overschrijven. Het dichtstbijzijnde bestand wint alleen wanneer twee bestanden verschillende instructies geven over hetzelfde onderwerp. Schrijf gedeelde regels één keer in de root en herhaal deze niet in elke map.
Hoe groot moet het root AGENTS.md-bestand zijn?
Klein genoeg dat u het niet erg vindt als het boven elk verzoek wordt geplaatst dat u in die repository doet, want dat is precies wat er gebeurt. De documentatie van Claude Code suggereert om onder de 200 regels per bestand te blijven en waarschuwt dat langere bestanden "de naleving verminderen". Codex stopt standaard met het samenvoegen van instructiebestanden bij 32 KiB in totaal. Als uw root-bestand vier services documenteert, is het grootste deel ervan overbodige ballast voor een specifieke taak. Verplaats details naar bestanden per map en laat een verwijzing achter.
Hoe voorkom ik dat deze bestanden verouderen?
Plaats één regel in het root-bestand: wie code in een map wijzigt, werkt in dezelfde commit ook het AGENTS.md-bestand van die map bij. Het bestand naast de code plaatsen zorgt ervoor dat de regel wordt nageleefd, omdat de wijziging dan in dezelfde pull request-diff verschijnt die een mens al aan het beoordelen is. Voeg een CI-waarschuwing toe die elk gewijzigd pad koppelt aan het dichtstbijzijnde AGENTS.md-bestand erboven, en vergelijk regelmatig git log -1 --format=%cs op elk bestand met hetzelfde commando uitgevoerd op de map die het documenteert.
Leest Claude Code AGENTS.md-bestanden?
Nee. Sinds augustus 2026 stelt de documentatie: "Claude Code leest CLAUDE.md, niet AGENTS.md." Maak een CLAUDE.md in dezelfde map met @AGENTS.md op de eerste regel; dit laadt het gedeelde bestand en stelt u in staat om daaronder Claude-specifieke instructies toe te voegen. Een symbolische link aangemaakt met ln -s AGENTS.md CLAUDE.md werkt wanneer er niets extra's hoeft te worden toegevoegd, hoewel dit op Windows Administrator-rechten of de Ontwikkelaarsmodus vereist. Voer /context uit in een sessie en bevestig dat het bestand verschijnt onder Memory files.
Waar plaats ik een regel die slechts soms van belang is?
Niet in AGENTS.md. Dat bestand wordt in elke sessie geladen, dus elke regel daarin concurreert om aandacht met het verzoek dat u daadwerkelijk heeft getypt. Een procedure met meerdere stappen die slechts af en toe nodig is, hoort thuis in een skill, die op verzoek wordt geladen. Een regel die van toepassing is op één map hoort thuis in het AGENTS.md van die map. Een feit dat de agent direct uit de code kan lezen, zoals de mappenstructuur of de afhankelijkhedenlijst, hoort in geen van beide thuis.