Cómo usar AGENTS.md anidados en un monorepo
Evita que un AGENTS.md raíz se vuelva obsoleto. Aprende a distribuir la configuración por directorios para reducir el consumo de contexto y mejorar la precisión del agente.
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 específicas para ese directorio. Un agente que edita services/worker/queue.py lee entonces el archivo raíz y el archivo del trabajador, y no consume contexto alguno sobre 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 supervisión. Lo que puede fallar es la ubicación y el mantenimiento, y ambos son su responsabilidad.
¿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 por cuatro motivos distintos.
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 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: "mantenga los archivos CLAUDE.md por debajo de las 200 líneas. 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 escritos en un solo archivo, cada regla solo es correcta a veces, por lo que el agente debe adivinar cuál se 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 incertidumbre, ya que solo una de las dos reglas está presente en el contexto.
Se llena de datos 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 resúmenes de 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 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 muchos como "el archivo raíz se ignora". No es así. En las herramientas que implementan la 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 distintas sobre el mismo tema.
Codex es explícito sobre el mecanismo: "Codex concatena los 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 instrucciones anteriores". Claude Code sigue el mismo proceso 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 forma distinta: 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 coste cuando el agente trabaja en otro lugar, lo que significa que los detalles son económicos allí y deben ubicarse 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 solo contiene 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 del trabajador 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í, y especifique 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 función de cada servicio. Eso pertenece a los humanos. Upstream establece el mismo límite al señalar que "los archivos README.md son para humanos: inicios rápidos, descripciones de proyectos y guías de contribución", mientras que AGENTS.md contiene "el contexto adicional, a veces detallado, que necesitan los agentes de codificació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 ese mismo 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 quien revisa el pull request ve ambos a la vez. 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 el pull request. Esta busca el archivo AGENTS.md más cercano por encima de cada archivo modificado y notifica si dicho archivo no ha sido 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 archivo 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 (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")"
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 debe 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 (globs) 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 establece: "Claude Code lee CLAUDE.md, no AGENTS.md". El patrón sigue funcionando, solo necesita un CLAUDE.md junto a cada AGENTS.md.
El formato de importación es el correcto 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/`.El formato de enlace simbólico es el correcto 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 aparecerán bajo Memory files. En Windows, un enlace simbólico requiere privilegios de administrador o el Modo de desarrollador, por lo que debe usar la importación @AGENTS.md en ese sistema.
Existe una trampa relacionada con esto. Después de /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 razón, y tocar cualquier archivo en el directorio la reactiva.
Configuración que apunta otros agentes a 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 project_doc_max_bytes predeterminado, 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 original incluye 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 vale la pena ser precisos sobre cuál de ellos se debe utilizar.
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 es local para 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 la tercera opción. 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 de la base de 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 el argumento completo. 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é ocurre en caso de conflicto, no qué archivos se cargan. Codex "concatena 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 desde el directorio de trabajo en lugar de sobrescribirlos. El archivo más cercano prevalece solo cuando dos archivos ofrecen instrucciones distintas 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 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 sucede. 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á peso muerto 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 en la jerarquía superior y, periódicamente, compare el resultado de git log -1 --format=%cs en cada archivo con el mismo comando ejecutado en el directorio que documenta.
¿Claude Code lee 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 CLAUDE.md en el mismo directorio con @AGENTS.md en la primera línea; esto 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 (Memory files).
¿Dónde pongo una regla que solo es relevante 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 solo se necesita ocasionalmente pertenece a una habilidad (skill), la cual se carga bajo demanda. Una regla que se aplica a un directorio pertenece al AGENTS.md de ese directorio. Un dato 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.