Cómo estructurar archivos AGENTS.md anidados en monorepos
Evita que el contexto de tu agente se sature con reglas innecesarias. Aprende a distribuir archivos AGENTS.md por directorios para optimizar el rendimiento en monorepos grandes.
Qué significa AGENTS.md anidado en un monorepo
Un archivo AGENTS.md anidado en un monorepo consiste en un archivo pequeño en la raíz del repositorio y otro archivo adicional dentro de cada directorio de servicio. El archivo raíz contiene las pocas reglas que se aplican en todas partes, además de un mapa de la ubicación de los otros archivos. Cada archivo de servicio contiene los comandos y las convenciones exclusivas para ese directorio. Un agente que edita services/worker/queue.py lee entonces el archivo raíz y el archivo del trabajador, sin gastar contexto alguno en el frontend que nunca tocará.
No hay nada que instalar. AGENTS.md es una convención, y el proyecto original lo indica claramente:
AGENTS.md es simplemente Markdown estándar. Utilice los encabezados que desee; el agente simplemente analiza el texto que usted proporciona.
Por eso vale la pena aprender esta técnica correctamente. El formato no cambiará bajo su responsabilidad. Lo que puede fallar es la ubicación y el mantenimiento, y ambos son su tarea.
¿Por qué deja de funcionar un único archivo AGENTS.md en la raíz?
Un archivo AGENTS.md de 600 líneas en la raíz de un repositorio que contiene una aplicación web, un proceso en segundo plano y un directorio de Terraform falla de cuatro formas distintas.
Queda obsoleto porque nadie es responsable de él. El ingeniero que renombra un script de prueba en apps/web está editando archivos bajo apps/web. El archivo AGENTS.md de la raíz no está en ese diff, por lo que ningún revisor detecta la discrepancia. Seis semanas después, el archivo describe un paso de compilación que ya no existe y la persona que lo rompió ha olvidado el cambio.
Consume contexto en cada tarea. Estos archivos se cargan al inicio de la sesión, antes de que el agente sepa qué le vas a pedir. La documentación de Claude Code cuantifica esto: "mantén el objetivo por debajo de 200 líneas por archivo CLAUDE.md. Los archivos más largos consumen más contexto y reducen el cumplimiento". Codex deja de fusionar archivos de instrucciones una vez que su tamaño combinado alcanza los 32 KiB, el valor predeterminado de project_doc_max_bytes. Un archivo raíz que documenta cuatro servicios gasta ese presupuesto en tres de ellos para cada tarea.
Las instrucciones comienzan a contradecirse. El directorio web requiere pnpm test. El proceso en segundo plano requiere pytest -q. Al estar escritas en un mismo archivo, cada regla solo es correcta a veces, por lo que el agente debe adivinar cuál aplica. La documentación de Claude Code describe el resultado: "si dos reglas se contradicen, Claude puede elegir una arbitrariamente". Un archivo por directorio elimina la suposición, ya que solo una de las dos reglas está en el contexto. Cuando una regla que escribiste claramente es ignorada de todos modos, revisar las razones por las que una instrucción nunca se aplica es más efectivo que reescribir la redacción por cuarta vez.
Se llena de hechos que el agente podría leer del código. Un árbol de directorios, una lista de dependencias, un resumen de lo que hace cada paquete. La comprobación /doctor de Claude Code existe precisamente para eliminar esto. "Recorta el contenido que Claude puede deducir de la base de código, como estructuras de directorios, listas de dependencias y visiones generales de la arquitectura" y conserva "dificultades, fundamentos y convenciones que difieren de los valores predeterminados de las herramientas". Esa frase es la mejor prueba que conozco para determinar si una línea pertenece realmente al archivo.
¿El agente lee el archivo raíz o solo el más cercano?
Aquí es donde la mayoría de las personas malinterpreta el modelo, por lo que vale la pena citar la convención original en lugar de parafrasearla:
Coloque otro AGENTS.md dentro de cada paquete. Los agentes leen automáticamente el archivo más cercano en el árbol de directorios, por lo que el más próximo tiene prioridad y cada subproyecto puede incluir instrucciones personalizadas.
Y sobre los conflictos:
El archivo AGENTS.md más cercano al archivo editado prevalece; las instrucciones explícitas del usuario en el chat anulan todo lo demás.
"Tiene prioridad" se interpreta por muchas personas como "el archivo raíz se ignora". No es así. En las herramientas que implementan esta convención, cada archivo en la ruta desde la raíz del repositorio hasta el directorio de trabajo se lee y se concatena. El archivo más cercano solo prevalece cuando dos archivos dicen cosas diferentes sobre el mismo tema.
Codex es explícito sobre el mecanismo: "Codex concatena archivos desde la raíz hacia abajo, uniéndolos con líneas en blanco. Los archivos más cercanos a su directorio actual anulan las directrices anteriores". Claude Code sigue el mismo camino para su propio nombre de archivo. Los archivos en la jerarquía de directorios por encima del directorio de trabajo "se cargan por completo al iniciar", y "todos los archivos descubiertos se concatenan en el contexto en lugar de anularse entre sí". Los directorios por debajo del directorio de trabajo se comportan de manera diferente: Claude Code carga esos archivos bajo demanda, "cuando Claude lee archivos en esos directorios".
De esto se derivan dos consecuencias prácticas. El archivo raíz es un prefijo en cada sesión del repositorio, así que trate cada línea allí como una línea por la que paga cien veces a la semana. Un archivo por directorio no tiene costo cuando el agente trabaja en otro lugar, lo que significa que los detalles son económicos allí y deben colocarse en ese nivel.
Este comportamiento se verificó con la documentación de Codex y Claude Code en agosto de 2026. Las herramientas implementan la convención de forma ligeramente distinta y cambian con el tiempo, así que confirme las reglas de carga para el agente que utilice su equipo.
Un diseño funcional para un repositorio con tres servicios
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 scriptsEl archivo raíz es breve a propósito. Indica dónde buscar y contiene únicamente las reglas que se aplican en todos los directorios.
# 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.El archivo por directorio es donde se detallan los pormenores, y puede ser tan extenso como el directorio lo requiera.
# 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.El archivo de trabajo tiene la misma estructura pero con contenido distinto: el comando de instalación, pytest -q, la razón por la que el consumidor debe ser idempotente y la migración que debe ejecutarse antes de que las pruebas sean exitosas. El archivo de infraestructura es donde se escriben las reglas que impiden que un agente cause daños. Nunca ejecute terraform apply. Ejecute terraform plan y deténgase ahí, especificando el backend de estado que ya está configurado para que el agente no intente inicializar uno nuevo.
Observe lo que no figura en ninguno de estos archivos: una descripción de la finalidad de cada servicio. Eso corresponde a los humanos. Upstream establece el mismo límite al afirmar que "los archivos README.md son para humanos: inicios rápidos, descripciones de proyectos y directrices de contribución", mientras que AGENTS.md contiene "el contexto adicional, a veces detallado, que necesitan los agentes de programación: pasos de compilación, pruebas y convenciones". La división entre AGENTS.md y un README orientado a humanos recorre frase por frase ese límite, y un archivo DESIGN.md que registra por qué el código tiene la forma que tiene cubre el tercer archivo, aquel que explica las decisiones en lugar de los comandos.
¿Quién actualiza el archivo cuando cambia el código?
Existe una regla, y debe incluirse en el archivo raíz: quien modifique código en un directorio debe actualizar el archivo AGENTS.md de dicho directorio en el mismo commit.
Esto funciona por una razón mecánica, no cultural. El archivo por directorio aparece en el mismo diff que el código, por lo que el revisor de la pull request ve ambos al mismo tiempo. Un archivo raíz pertenece a todos, lo que significa que no pertenece a nadie, y nunca aparece en el diff que alguien esté leyendo.
Refuerce esta regla con una comprobación en la pull request. Esta busca el archivo AGENTS.md más cercano por encima de cada archivo modificado y notifica si dicho archivo no fue 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"
doneEn una rama que modificó el cliente de la API sin tocar la documentación, el resultado se muestra así:
note: apps/web/src/api/client.ts changed but apps/web/AGENTS.md was not updatedManténgalo como una advertencia en lugar de un error bloqueante. Un bloqueo estricto enseña a los usuarios a añadir una línea en blanco al archivo solo para que el CI pase, y un archivo editado para satisfacer a un robot vale menos que no tener archivo alguno. La advertencia le da al revisor una pregunta que plantear, que es la parte que realmente funciona.
¿Cómo detecto un AGENTS.md que ha quedado obsoleto?
Existen dos comprobaciones que puede ejecutar hoy mismo y un síntoma que observará durante una sesión.
Compare la antigüedad de cada archivo con la antigüedad del código que describe. %cs imprime la fecha de confirmación 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")"
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 fecha de documentación con seis meses de retraso respecto al código no demuestra que el archivo sea incorrecto. Solo le indica qué archivo leer primero, y eso es todo lo que necesita de una comprobación que toma un segundo.
Busque rutas que ya no existen. La documentación se degrada de una forma muy específica: sigue describiendo código que fue eliminado. Cada ruta en estos archivos está escrita entre comillas invertidas, por lo que es fácil extraerlas y probarlas.
grep -o '`[^`]*`' apps/web/AGENTS.md | tr -d '`' | grep '/' | while read -r p; do
[ -e "$p" ] || [ -e "apps/web/$p" ] || echo "missing: $p"
doneLea la salida en lugar de integrar esto en su CI. También marcará patrones globales como src/**/*.ts y cualquier URL que haya citado, ya que ambos contienen una barra diagonal y ninguno es un archivo en el disco.
El síntoma en una sesión. El agente lee el archivo, intenta abrir src/api/client.ts porque el archivo se lo indicó, y la herramienta devuelve:
No such file or directoryPor lo tanto, hace lo lógico y escribe su propio contenedor fetch. Ese es el costo real de un archivo obsoleto. El agente no ignora su documentación. Sigue la documentación, llega a una ruta que fue eliminada hace tres meses y reconstruye código que usted ya tiene. Una habilidad como Ponytail, que limita al agente al cambio más pequeño que funciona, hace que ese instinto de reconstrucción sea menos frecuente, pero no puede encontrar un asistente al que su archivo apuntó a un lugar incorrecto.
¿Claude Code lee archivos AGENTS.md?
No, y es importante aclararlo porque el diseño anidado depende de ello. A fecha de agosto de 2026, la documentación indica: "Claude Code lee CLAUDE.md, no AGENTS.md". El patrón sigue funcionando, solo necesita un CLAUDE.md junto a cada AGENTS.md.
La forma de importación es correcta cuando desea añadir líneas específicas de una herramienta sobre las compartidas. Coloque esto en services/worker/CLAUDE.md:
@AGENTS.md
## Claude Code
Use plan mode for changes under `services/worker/migrations/`.La forma de enlace simbólico (symlink) es correcta cuando no hay nada específico de la herramienta que añadir.
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 no imprime nada cuando tiene éxito, así que verifique el listado: apps/web/CLAUDE.md -> AGENTS.md. Luego inicie una sesión y ejecute /context, donde los archivos cargados aparecen bajo Memory files. En Windows, un enlace simbólico requiere privilegios de administrador o el Modo de desarrollador, así que utilice la importación @AGENTS.md en ese sistema.
Existe una trampa relacionada con esto. Tras /compact, el archivo raíz se vuelve a leer desde el disco, pero los archivos anidados en subdirectorios no se vuelven a inyectar. Estos regresan la próxima vez que el agente lee un archivo en ese directorio. Si una regla por directorio parece dejar de aplicarse a mitad de una sesión larga, esa suele ser la causa, y tocar cualquier archivo en el directorio la reactiva.
Ajustes que dirigen a otros agentes hacia AGENTS.md
Codex lee AGENTS.md de forma nativa. En cada nivel, comprueba primero AGENTS.override.md, lo que permite a un directorio tener una anulación local sin editar el archivo compartido. Deja de fusionar una vez que el tamaño combinado alcanza los 32 KiB, el valor predeterminado de project_doc_max_bytes, lo cual es una razón más para mantener el archivo raíz pequeño.
Aider lo toma a través de .aider.conf.yml con la línea read: AGENTS.md.
Gemini CLI lo toma a través de .gemini/settings.json con { "context": { "fileName": "AGENTS.md" } }.
La documentación oficial menciona un cambio de nombre compatible con versiones anteriores para repositorios que aún utilizan el nombre singular antiguo: mv AGENT.md AGENTS.md && ln -s AGENTS.md AGENT.md.
En un monorepo muy grande, el ajuste claudeMdExcludes de Claude Code omite archivos ancestros por ruta o glob, lo cual es útil cuando el directorio de otro equipo se encuentra por encima del suyo.
¿En qué se diferencia esto de la memoria del agente o de una habilidad?
Estos mecanismos parecen similares pero fallan de formas completamente distintas, por lo que es importante ser preciso sobre cuál de ellos está utilizando.
AGENTS.md es escrito por usted, enviado a git, revisado en un pull request e idéntico para cualquiera que clone el repositorio. La memoria del agente es escrita por el agente, almacenada fuera del repositorio y local a una sola máquina. La documentación de Claude Code traza la misma línea: CLAUDE.md contiene "Instrucciones y reglas" que usted escribe, la memoria automática contiene "Aprendizajes y patrones" que Claude escribe, y el directorio de memoria no se comparte entre máquinas. La prueba es sencilla. Si un hecho debe ser cierto para un colega en un clon nuevo, no puede residir en la memoria. Cómo persiste la memoria del agente entre sesiones cubre esa parte del panorama.
Una habilidad es el tercer elemento. AGENTS.md es contexto que se carga en cada sesión; una habilidad es un procedimiento que se carga cuando es necesario. La documentación de Claude Code ofrece una regla útil: "Si una entrada es un procedimiento de varios pasos o solo importa para una parte del código, muévala a una habilidad o a una regla con alcance de ruta". La segunda mitad de esa frase es precisamente lo que resuelve un AGENTS.md anidado. La primera mitad es para lo que sirven las habilidades del agente, y cuando el mismo procedimiento es necesario en más de un repositorio, comparta la habilidad entre repositorios en lugar de pegar los mismos párrafos en diez archivos AGENTS.md diferentes.
Upstream señala que "en el momento de escribir este artículo, el repositorio principal de OpenAI tiene 88 archivos AGENTS.md". Esa cifra es todo el argumento. Un repositorio grande no necesita un archivo más grande. Necesita más archivos pequeños, cada uno ubicado junto al código que describe, y cada uno bajo la responsabilidad de quien haya modificado ese código por última vez.
FAQ
¿Un archivo AGENTS.md anidado reemplaza al archivo raíz o se suma a él?
Se suma a él. La documentación oficial indica que "el más cercano tiene prioridad", lo cual describe qué sucede en caso de conflicto, no qué archivos se cargan. Codex "concatena los archivos desde la raíz hacia abajo, uniéndolos con líneas en blanco", y Claude Code concatena cada archivo que encuentra al recorrer el árbol de directorios desde el directorio de trabajo en lugar de sobrescribirlos. El archivo más cercano prevalece solo cuando dos archivos dan instrucciones diferentes sobre el mismo tema. Escriba las reglas compartidas en la raíz una sola vez y no las repita en cada directorio.
¿Qué tamaño debe tener el archivo AGENTS.md raíz?
Lo suficientemente pequeño como para que no le importe que se añada al principio de cada petición que realice en ese repositorio, porque eso es exactamente lo que ocurre. La documentación de Claude Code sugiere un límite de 200 líneas por archivo y advierte que los archivos más largos "reducen la adherencia". Codex deja de combinar archivos de instrucciones al alcanzar los 32 KiB combinados de forma predeterminada. Si su archivo raíz documenta cuatro servicios, la mayor parte será información irrelevante para cualquier tarea específica. Mueva los detalles a archivos por directorio y deje un mapa en la raíz.
¿Cómo evito que estos archivos queden obsoletos?
Incluya una regla en el archivo raíz: quien modifique código en un directorio debe actualizar el AGENTS.md de ese directorio en el mismo commit. Colocar el archivo junto al código es lo que hace que la regla se cumpla, ya que el cambio aparece en el mismo diff del pull request que un humano ya está revisando. Añada una advertencia en la CI que asocie cada ruta modificada con el AGENTS.md más cercano y, periódicamente, compare el resultado de git log -1 --format=%cs de cada archivo con el mismo comando ejecutado en el directorio que documenta.
¿Claude Code lee los archivos AGENTS.md?
No. A fecha de agosto de 2026, la documentación establece que "Claude Code lee CLAUDE.md, no AGENTS.md". Cree un archivo CLAUDE.md en el mismo directorio con @AGENTS.md en la primera línea, lo cual carga el archivo compartido y le permite añadir instrucciones específicas para Claude debajo. Un enlace simbólico creado con ln -s AGENTS.md CLAUDE.md funciona cuando no hay nada adicional que añadir, aunque en Windows requiere privilegios de administrador o el Modo de desarrollador. Ejecute /context en una sesión y confirme que el archivo aparece en los archivos de memoria.
¿Dónde pongo una regla que solo importa a veces?
No en AGENTS.md. Ese archivo se carga en cada sesión, por lo que cada línea compite por la atención con la petición que usted ha escrito. Un procedimiento con varios pasos que se necesita ocasionalmente pertenece a una habilidad (skill), la cual se carga bajo demanda. Una regla que se aplica a un solo directorio pertenece al AGENTS.md de ese directorio. Un hecho que el agente puede leer directamente del código, como el árbol de directorios o la lista de dependencias, no pertenece a ninguno de los dos.