Вкладені AGENTS.md для монорепозиторію
Один root AGENTS.md застаріває й витрачає контекст на зайві каталоги. Дізнайтеся, як розкласти правила по сервісах і залишити спільні в корені.
Що означають вкладені AGENTS.md у монорепозиторії
Вкладені AGENTS.md у монорепозиторії означають, що в корені репозиторію розміщується один невеликий файл, а ще по одному файлу — у каталозі кожного сервісу. У кореневому файлі зберігаються кілька правил, спільних для всього репозиторію, а також карта розташування інших файлів. У файлі кожного сервісу описано команди та правила, які стосуються лише цього каталогу. Агент, який редагує services/worker/queue.py, читає кореневий файл і файл worker-сервісу, не витрачаючи контекст на front end, якого він не змінюватиме.
Нічого встановлювати не потрібно. AGENTS.md — це домовленість, і upstream-проєкт прямо це зазначає:
AGENTS.md — це звичайний Markdown. Використовуйте будь-які потрібні заголовки; агент просто аналізує наданий вами текст.
Саме тому цю техніку варто опанувати належним чином. Формат не зміниться без вашої участі. Проблеми виникають через неправильне розташування та неналежне обслуговування файлів, і за це відповідаєте ви.
Чому один великий root AGENTS.md перестає працювати?
Один AGENTS.md на 600 рядків у корені репозиторію, де зберігаються web app, background worker і каталог Terraform, дає збій з чотирьох окремих причин.
Файл застаріває, бо за нього ніхто не відповідає. Інженер, який перейменовує тестовий скрипт у apps/web, редагує файли в apps/web. Кореневий AGENTS.md не входить до цього diff, тому жоден reviewer не бачить невідповідність. Через шість тижнів файл описує крок збірки, якого вже не існує, а людина, яка спричинила проблему, уже забула про цю зміну.
Файл витрачає контекст під час кожного завдання. Такі файли завантажуються на початку сесії, ще до того, як агент дізнається, що саме ви попросите. У документації Claude Code наведено конкретне обмеження: «для кожного файла CLAUDE.md рекомендовано не перевищувати 200 рядків. Довші файли споживають більше контексту та знижують дотримання інструкцій». Codex припиняє об’єднувати файли інструкцій, коли їхній загальний розмір досягає 32 KiB, що є типовим значенням project_doc_max_bytes. Кореневий файл, який документує чотири сервіси, витрачає цей бюджет на три з них під час кожного завдання.
Інструкції починають суперечити одна одній. Web directory потребує pnpm test. Worker потребує pytest -q. В одному файлі кожне правило правильне лише в окремих випадках, тому агент має вгадувати, яке з них застосовується. У документації Claude Code описано такий результат: «якщо два правила суперечать одне одному, Claude може довільно вибрати одне з них». Файл у кожному каталозі усуває цю невизначеність, оскільки в контексті завжди перебуває лише одне з двох правил. Якщо правило, яке ви точно сформулювали зрозуміло, все одно ігнорується, корисніше розібратися з причинами, через які інструкція не застосовується, ніж учетверте переписувати формулювання.
Файл заповнюється фактами, які агент може прочитати з коду. Дерево каталогів, список залежностей, опис призначення кожного пакета. Перевірка /doctor у Claude Code призначена саме для вилучення такого вмісту. Вона «видаляє дані, які Claude може отримати з codebase, наприклад структуру каталогів, списки залежностей і огляди архітектури», та залишає «проблемні місця, обґрунтування і conventions, що відрізняються від типових налаштувань інструментів». Це найкращий відомий мені тест, який допомагає визначити, чи взагалі має конкретний рядок бути у файлі.
Чи читає агент кореневий файл, чи лише найближчий?
Саме тут більшість людей неправильно розуміє модель, тому варто навести висхідну угоду, а не перефразовувати її:
Розміщуйте ще один AGENTS.md у кожному пакеті. Агенти автоматично читають найближчий файл у дереві каталогів, тому найближчий файл має пріоритет, а кожен підпроєкт може містити спеціально адаптовані інструкції.
Щодо конфліктів:
Перемагає найближчий до редагованого файлу AGENTS.md; явні запити користувача в чаті мають пріоритет над усім іншим.
Для багатьох формулювання «має пріоритет» означає, що «кореневий файл ігнорується». Це не так. В інструментах, які реалізують цю угоду, читаються всі файли на шляху від кореня репозиторію до робочого каталогу, після чого їхній вміст об’єднується. Найближчий файл має пріоритет лише тоді, коли два файли містять різні вказівки щодо одного питання.
Codex чітко описує цей механізм: «Codex об’єднує файли від кореня вниз, розділяючи їх порожніми рядками. Файли, розташовані ближче до поточного каталогу, замінюють попередні вказівки». Claude Code проходить тим самим шляхом для власного імені файлу. Файли в ієрархії каталогів над робочим каталогом «повністю завантажуються під час запуску», а «всі виявлені файли об’єднуються в контекст, а не замінюють один одного». Каталоги нижче робочого каталогу працюють інакше: Claude Code завантажує такі файли на вимогу, «коли Claude читає файли в цих каталогах».
З цього випливають два практичні наслідки. Кореневий файл є префіксом кожного сеансу в репозиторії, тому сприймайте кожен його рядок як рядок, за який ви платите сто разів на тиждень. Файл для окремого каталогу не створює витрат, коли агент працює в іншому місці, тому подробиці краще зберігати саме там.
Цю поведінку перевірено за документацією Codex і Claude Code у серпні 2026 року. Інструменти реалізують цю угоду дещо по-різному, і правила завантаження можуть змінюватися, тому перевірте їх для агента, який використовує ваша команда.
Приклад структури репозиторію з трьома сервісами
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 scriptsКореневий файл навмисно короткий. У ньому вказано, де шукати потрібну інформацію, і містяться лише правила, чинні в кожному каталозі.
# 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.Файл для окремого каталогу містить деталі. Його обсяг може відповідати складності цього каталогу.
# 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.Файл worker має таку саму структуру, але інший вміст: команду встановлення, pytest -q, пояснення, чому consumer має залишатися ідемпотентним, і міграцію, яку потрібно виконати до успішного проходження тестів. У файлі infra задають правила, що не дають агенту завдати шкоди. Ніколи не запускайте terraform apply. Виконайте terraform plan і на цьому зупиніться. Також укажіть уже налаштований backend стану, щоб агент не намагався ініціалізувати новий.
Зверніть увагу, чого немає в жодному з цих файлів: опису призначення кожного сервісу. Це призначено для людей. Upstream проводить таку саму межу: «файли README.md призначені для людей: короткі інструкції з запуску, описи проєктів і рекомендації для учасників», тоді як AGENTS.md містить «додатковий, іноді докладний контекст, потрібний агентам кодування: кроки збирання, тести та правила». Розподіл між AGENTS.md і README для людей послідовно розглядає цю межу, а файл DESIGN.md, у якому записано причини структури коду присвячено третьому файлу — тому, що пояснює рішення, а не команди.
Хто оновлює файл, коли змінюється код?
У кореневому файлі має бути одне правило: той, хто змінює код у каталозі, оновлює AGENTS.md цього каталогу в тому самому коміті.
Це працює з механічної, а не культурної причини. Файл для конкретного каталогу міститься в тому самому diff, що й код, тому рев’юер pull request бачить їх одночасно. Кореневий файл стосується всіх, а отже, фактично не належить нікому. Він також ніколи не входить до diff, який хтось уже переглядає.
Підкріпіть це правило перевіркою pull request. Вона знаходить найближчий AGENTS.md вище кожного зміненого файлу, а потім повідомляє, якщо цей файл не було змінено.
#!/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"
doneУ гілці, де було перероблено API client без змін у документації, результат має такий вигляд:
note: apps/web/src/api/client.ts changed but apps/web/AGENTS.md was not updatedЗалиште це попередженням, а не помилкою. Жорстке блокування привчає додавати до файлу порожній рядок, щоб CI став зеленим. Файл, змінений лише для задоволення робота, менш цінний, ніж повна відсутність файлу. Попередження дає рев’юеру запитання, яке потрібно поставити. Саме це на практиці й працює.
Як виявити застарілий файл AGENTS.md?
Сьогодні можна виконати дві перевірки. Крім того, під час сеансу ви побачите один характерний симптом.
Порівняйте вік кожного файла з віком коду, який він описує. %cs виводить дату коміту у форматі 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-01Якщо дата документа відстає від дати коду на шість місяців, це ще не доводить, що файл неправильний. Це лише показує, який файл слід прочитати першим. Для перевірки, що виконується за одну секунду, цього достатньо.
Перевірте шляхи, яких більше не існує. Документація застаріває дуже характерним способом: вона продовжує описувати код, який уже видалено. Усі шляхи в цих файлах записано в backticks, тому їх легко витягнути й перевірити.
grep -o '`[^`]*`' apps/web/AGENTS.md | tr -d '`' | grep '/' | while read -r p; do
[ -e "$p" ] || [ -e "apps/web/$p" ] || echo "missing: $p"
doneПрочитайте результат замість того, щоб додавати цю перевірку до CI. Вона також позначає glob-вирази, наприклад src/**/*.ts, і будь-який URL, який ви взяли в лапки, оскільки і в одному, і в іншому є slash, але жоден із них не є файлом на диску.
Симптом під час сеансу. Агент читає файл, намагається відкрити src/api/client.ts, оскільки файл вказує йому це зробити, а інструмент повертає:
No such file or directoryТому агент робить логічний висновок і створює власну обгортку fetch. У цьому полягає реальна вартість застарілого файла. Агент не ігнорує вашу документацію. Він дотримується документації, переходить до шляху, який було видалено три місяці тому, і повторно створює код, який у вас уже є. Така навичка, як Ponytail, що змушує агента вносити найменшу працездатну зміну, зменшує ймовірність такого повторного створення, але не може знайти допоміжний компонент, на який файл вказав неправильним шляхом.
Чи читає Claude Code файли AGENTS.md?
Ні. Це важливо зазначити, оскільки від цього залежить вкладена структура. Станом на серпень 2026 року в документації зазначено: «Claude Code читає CLAUDE.md, а не AGENTS.md». Цей підхід і далі працює, але поруч із кожним AGENTS.md потрібно розмістити CLAUDE.md.
Форма імпорту підходить, якщо потрібно додати специфічні для інструмента рядки поверх спільних. Додайте це до services/worker/CLAUDE.md:
@AGENTS.md
## Claude Code
Use plan mode for changes under `services/worker/migrations/`.Форма із symlink підходить, якщо специфічні для інструмента налаштування не потрібні.
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 нічого не виводить у разі успіху, тому перевірте список: apps/web/CLAUDE.md -> AGENTS.md. Потім запустіть сеанс і виконайте /context. Завантажені файли з’являться в розділі Memory files. У Windows для symlink потрібні права Administrator або Developer Mode, тому замість нього використовуйте імпорт @AGENTS.md.
Є ще одна особливість. Після /compact кореневий файл повторно читається з диска, але вкладені файли в підкаталогах не завантажуються повторно. Вони знову завантажуються наступного разу, коли агент читає файл у цьому каталозі. Якщо правило для окремого каталогу перестає застосовуватися під час тривалого сеансу, зазвичай причина саме в цьому. Щоб завантажити його знову, достатньо змінити будь-який файл у каталозі.
Налаштування для вказування іншим агентам на AGENTS.md
Codex нативно читає AGENTS.md. На кожному рівні він спочатку перевіряє AGENTS.override.md. Це дає змогу налаштувати локальне перевизначення для одного каталогу без редагування спільного файла. Об’єднання припиняється, коли загальний розмір досягає 32 KiB — значення за замовчуванням для project_doc_max_bytes. Це ще одна причина не перевантажувати кореневий файл.
Aider використовує .aider.conf.yml з таким рядком: read: AGENTS.md.
Gemini CLI використовує .gemini/settings.json із { "context": { "fileName": "AGENTS.md" } }.
Документація upstream описує зворотно сумісне перейменування для репозиторіїв, які й далі використовують стару назву в однині: mv AGENT.md AGENTS.md && ln -s AGENTS.md AGENT.md.
У дуже великому monorepo параметр claudeMdExcludes у Claude Code пропускає файли з батьківських каталогів за шляхом або glob-шаблоном. Це корисно, коли каталог іншої команди розташований вище за ваш.
Чим це відрізняється від пам’яті агента або skill?
Ці механізми виглядають подібними, але виходять з ладу з різних причин. Тому важливо точно визначити, який саме механізм вам потрібен.
AGENTS.md створюєте ви, фіксуєте в git і перевіряєте в pull request. Його вміст однаковий для всіх, хто клонує репозиторій. Пам’ять агента створює агент, зберігає поза репозиторієм і використовує лише на одній машині. Документація Claude Code проводить таку саму межу: CLAUDE.md містить «інструкції та правила», які пишете ви, а auto memory містить «отримані знання та шаблони», які записує Claude. Каталог пам’яті не спільний для різних машин. Перевірка проста. Якщо факт має бути чинним для колеги після свіжого клонування репозиторію, його не можна зберігати в пам’яті. У розділі Як пам’ять агента зберігається між сеансами описано цю частину питання.
Skill — це третій механізм. Контекст з AGENTS.md завантажується в кожному сеансі, а skill завантажується лише за потреби. Документація Claude Code містить практичне правило: «Якщо запис є багатоетапною процедурою або стосується лише однієї частини кодової бази, перенесіть його до skill або правила, обмеженого шляхом». Друга частина цього речення описує саме те, що вирішує вкладений AGENTS.md. Перша частина стосується skill для агентів. Якщо та сама процедура потрібна в кількох репозиторіях, скористайтеся підходом поширити skill між репозиторіями, а не вставляйте однакові абзаци в десять різних файлів AGENTS.md.
В upstream зазначено, що «на момент написання основний репозиторій OpenAI має 88 файлів AGENTS.md». Це число саме по собі є аргументом. Великому репозиторію не потрібен більший файл. Йому потрібно більше невеликих файлів. Кожен файл має розташовуватися поруч із кодом, який він описує, і належати тому, хто востаннє змінював цей код.
FAQ
Чи замінює вкладений AGENTS.md кореневий файл, чи доповнює його?
Він доповнює кореневий файл. В upstream-документації сказано, що «пріоритет має найближчий файл». Це описує поведінку в разі конфлікту, а не те, які файли завантажуються. Codex «об’єднує файли від кореня вниз, розділяючи їх порожніми рядками», а Claude Code об’єднує всі знайдені файли, рухаючись від робочого каталогу вгору, а не замінює їх. Найближчий файл має перевагу лише тоді, коли два файли містять різні вказівки щодо одного питання. Записуйте спільні правила один раз у кореневому файлі та не дублюйте їх у кожному каталозі.
Якого розміру має бути кореневий AGENTS.md?
Він має бути достатньо малим, щоб ви не заперечували проти його додавання на початку кожного запиту в цьому репозиторії, оскільки саме це відбувається. Документація Claude Code рекомендує обмежувати кожен файл 200 рядками та попереджає, що довші файли «знижують дотримання інструкцій». Codex за замовчуванням припиняє об’єднання файлів інструкцій після досягнення загального розміру 32 KiB. Якщо ваш кореневий файл описує чотири сервіси, більша його частина не потрібна для жодного окремого завдання. Перенесіть докладні відомості до файлів у відповідних каталогах, а в кореневому файлі залиште карту.
Як запобігти застаріванню цих файлів?
Додайте в кореневий файл правило: той, хто змінює код у каталозі, оновлює AGENTS.md цього каталогу в тому самому коміті. Розміщення файлу поруч із кодом допомагає дотримуватися цього правила, оскільки така зміна потрапляє до того самого pull request diff, який уже переглядає людина. Додайте попередження CI, яке зіставляє кожен змінений шлях із найближчим AGENTS.md вище в ієрархії, а час від часу порівнюйте git log -1 --format=%cs у кожному файлі з результатом виконання тієї самої команди в каталозі, який цей файл описує.
Чи читає Claude Code файли AGENTS.md?
Ні. Станом на August 2026 документація зазначає: «Claude Code читає CLAUDE.md, а не AGENTS.md». Створіть CLAUDE.md у тому самому каталозі та додайте @AGENTS.md у перший рядок. Це завантажить спільний файл і дасть змогу додати нижче інструкції для Claude. Символічне посилання, створене за допомогою ln -s AGENTS.md CLAUDE.md, працює, якщо додаткові інструкції не потрібні, хоча у Windows для цього потрібні права Administrator або Developer Mode. Виконайте /context у сеансі та переконайтеся, що файл відображається в розділі Memory files.
Куди додати правило, яке потрібне лише іноді?
Не в AGENTS.md. Цей файл завантажується в кожному сеансі, тому кожен його рядок конкурує за увагу із запитом, який ви фактично ввели. Процедура з кількома кроками, яка потрібна час від часу, має бути skill, що завантажується за потреби. Правило, яке стосується одного каталогу, належить до AGENTS.md у цьому каталозі. Факт, який агент може безпосередньо прочитати з коду, наприклад дерево каталогів або список залежностей, не належить до жодного з цих файлів.