В большом репозитории первое решение принимают ещё до запроса - выбором стартового каталога. Именно он определяет, какой root и какую конфигурацию Claude считает рабочими. Запуск из корня монорепозитория подходит для cross-package изменения; запуск из пакета сужает область поиска и контекст. Ключевое правило: неверный стартовый scope не компенсируют огромным промптом. Если агент читает не то и не там, дело чаще в точке входа, а не в недостатке инструкций.
Инструкции в большом дереве раскладывают слоями, а не сваливают в один файл. Корневой CLAUDE.md содержит только инварианты всего дерева - общий build, архитектуру, границы. Каталожные файлы загружаются лениво, когда Claude читает файлы в соответствующей области. Полезно один раз увидеть такую раскладку: корневой CLAUDE.md, cross-cutting rule в .claude/rules, и per-package CLAUDE.md и skill рядом с кодом сервиса. Это дешевле и точнее, чем одна гигантская корневая память на все случаи.
У ленивой загрузки есть тонкость, которую надо помнить. При создании нового файла каталожный CLAUDE.md может не подгрузиться заранее - Claude ещё не читал файлы этой области. Поэтому критичное правило лучше продублировать в задаче или в path-scoped rule. Per-directory CLAUDE.md хорош, когда правила принадлежат пакету как целому; .claude/rules с paths - для cross-cutting паттерна вроде всех миграций. А если сотни слоёв начали дублироваться, общую процедуру выносят в plugin или skill.
Отдельная задача - сократить бесполезное чтение, и это прямая экономия контекста и денег. Полезно один раз задать deny на чтение сгенерированного и служебного - dist, coverage, vendor, generated - и включить respectGitignore. Оговорка обязательна: не блокируют сгенерированный код, если задача как раз требует проверить сгенерированный API или фикстуру. А LSP и code-intelligence уменьшают bruteforce-чтения: определения и ссылки часто точнее повторного grep всего дерева.
Sparse worktrees изолируют работу над частью монорепозитория. Флаг --worktree отделяет ветку и сессию, а sparse-checkout может включать только нужные пакеты - но пути зависимостей и тестов должны остаться доступными, иначе прогон сломается. Файл .worktreeinclude копирует перечисленные extra-untracked файлы в управляемый worktree, и его не используют для секретов. Так каждая параллельная работа над своим пакетом идёт в лёгком изолированном дереве, а не в полной копии огромного репозитория.
Доступ к соседним пакетам дают --add-dir или permissions.additionalDirectories - но доступ не означает автоматической загрузки всех источников конфигурации оттуда. Это важное различие: агент получает возможность читать и править sibling-пакет, но его CLAUDE.md, rules и настройки сами собой не подхватываются. Перед cross-repo правкой определяют владельца, совместимость версий и стратегию коммитов для каждого репозитория - иначе изменение расползётся по чужой территории без согласования.
Cross-package изменение стоит вести по явному плану, а не наугад. Порядок такой: найти публичный контракт и всех его потребителей; зафиксировать стратегию совместимости и миграции; разделить ownership по пакетам; изменить контракт; обновить потребителей и фикстуры; прогнать focused-тесты каждого пакета; запустить интеграционный прогон по затронутому графу; независимо отревьюить публичный API и порядок раскатки. Каждый шаг опирается на предыдущий, а не прыгает к финалу через всё дерево сразу.
Наконец, структура тестов - это интерфейс для агента. Команды package-level, affected-тесты и полный suite документируют отдельно: один test без ожидаемого времени заставляет агента либо тратить часы, либо пропускать проверку. Типичный провал монорепо - неверная точка входа плюс огромный промпт вместо слоёв контекста; правильный ход - стартовать в нужной области, разложить инструкции слоями и закрыть шум.
monorepo/
├── CLAUDE.md # только инварианты всего дерева
├── .claude/rules/security.md # cross-cutting rule (paths)
├── services/api/
│ ├── CLAUDE.md # правила пакета как целого
│ └── .claude/skills/deploy-staging/SKILL.md
└── apps/web/
└── CLAUDE.md # frontend conventions{
"permissions": {
"deny": ["Read(/dist/**)", "Read(/coverage/**)",
"Read(/vendor/**)", "Read(/generated/**)"]
},
"respectGitignore": true
}
// не блокируйте generated, если задача требует его проверить