Mastering Hierarchical AGENTS.md in Monorepos — Precise AI Agent Control Through Root and Subdirectory Separation
Hierarchical AGENTS.md in Monorepos: Controlling AI Agents with Precision
Once you bring an AI coding agent into your team, the first problem you run into is this: the agent works hard, but it doesn't know your team's conventions, or it blindly copies the style of the wrong package. I started out by creating a single AGENTS.md at the root and calling it done — but as the monorepo grew, I started wondering if that was really the right approach. Frontend style guides were bleeding into the payment service, and the agent was reading an 80K-token architecture document in full every single time.
The real power of AGENTS.md lies not in a single file, but in its hierarchical structure. When you divide the root file and subdirectory files by purpose, the agent receives only the context that's relevant to the directory it's working in. By the end of this post, you'll be able to make three judgments immediately: how small to keep the root AGENTS.md, which rules should be pushed down to subdirectories, and when to reach for AGENTS.override.md.
Core Concepts
Hierarchical Discovery: How Agents Read Files
When an AI agent edits a specific file, it doesn't simply read a single AGENTS.md at the root. Starting from the directory containing that file, it walks up to the Git root, collecting every AGENTS.md along the path. It then concatenates them in order from root to the current directory to form a single context.
The key point is that files deeper in the directory tree are appended later and therefore take higher priority. This is append-based, not override-based — all file contents are merged, but when the agent resolves conflicts between rules, it treats content that appears later (from deeper directories) as more authoritative.
monorepo/
├── AGENTS.md ← root (read 1st, can be overridden later)
├── apps/
│ └── web/
│ └── AGENTS.md ← read 2nd (applied last, highest priority)
└── services/
└── payments/
└── AGENTS.override.md ← ignores root AGENTS.md, applied standaloneFor example, if an agent edits apps/web/src/Button.tsx, it reads monorepo/AGENTS.md → monorepo/apps/web/AGENTS.md in that order and merges them. The context has nothing to do with services/payments/.
Thanks to this automatic discovery, developers don't need to manually tell the agent "also read this file." The agent loads the rules appropriate for its current working location on its own. Later, when looking at real-world examples, you might wonder "what's the point of writing pointers?" — the answer is right here: pointers aren't instructions for the agent to go find a file, but rather contextual guidance added to files that will be auto-loaded via hierarchical discovery.
AGENTS.override.md — When this file exists in a directory, the full AGENTS.md inheritance from parent paths is not applied; only this file is used standalone. Useful for security-regulated subsystems or those with a completely different tech stack.
Discovery Priority and the 32 KiB Limit
Based on OpenAI Codex, the agent first looks for AGENTS.override.md in each directory, and falls back to AGENTS.md if not found. Only one file per directory is included, and the agent reads from the root downward, stopping once the cumulative size of all files along the path exceeds 32 KiB. Subdirectory files beyond that point are not loaded at all.
I initially thought "32 KB seems pretty generous," but once you pile in team convention docs, architecture overviews, and library lists at the root, it fills up faster than you'd expect. When the root becomes bloated, you end up in the paradoxical situation where the subdirectory rules that matter most never reach the agent.
Context Window — The maximum length of text an LLM can process in one pass. AGENTS.md content occupies this window, so unnecessary content reduces the actual working space the agent has for code.
Practical Application
Example 1: Using the Root as a Pointer Map Only
Instead of putting everything in the root AGENTS.md, this approach gives it a single job: a map that tells the agent which file to consult for a given task. This is a strategy actually adopted by the Datadog frontend team — they use the root solely as "a map for agents to understand their territory" and delegate the actual rules to each subdirectory. This pattern shines especially in monorepos with clearly separated concerns: email components, Go services, shared utilities, and so on.
Honestly, when I first saw this pattern I thought "can it really be this simple?" — but context efficiency visibly improves in practice.
<!-- monorepo/AGENTS.md -->
# Project Guide
## Common Rules
- Commit messages: imperative mood
- Always run `pnpm test` before a PR
- Use `pnpm add` when adding dependencies
## Subsystem-Specific Guides
- Working on the web app → see `apps/web/AGENTS.md`
- Working on the payment service → see `services/payments/AGENTS.md`
- Working on UI components → see `packages/ui/AGENTS.md`
- Working on auth → see `packages/auth/AGENTS.md`| Component | Role |
|---|---|
| Common rules section | Minimal conventions shared by all team members and agents |
| Subsystem pointers | Path guidance for files auto-loaded via hierarchical discovery |
| Root file size | Keep as small as possible (1–2 KB recommended) |
Example 2: Dedicated Rule Files per Subdirectory
This approach concentrates each package or app directory's rules in one place. It's also the structure adopted by the Mercari engineering team when they consolidated individual rule files for Cursor and Claude into a single AGENTS.md. The root serves only as an architecture overview and link map, while actual content is delegated to each subdirectory.
<!-- apps/web/AGENTS.md -->
# Web App Development Guide
## Architecture
- Server Components by default; Client Components require explicit `'use client'`
- Data fetching handled in Server Actions or Server Components
- State management: Zustand (global), React Query (server state)
## Component Conventions
- File names: PascalCase (e.g., UserProfile.tsx)
- Props types: declared as interfaces at the top of the file
- Styling: Tailwind CSS; custom CSS is prohibited
## Testing
- Component tests: @testing-library/react
- E2E: Playwright (`pnpm test:e2e`)
- No snapshot tests (maintenance burden)<!-- services/payments/AGENTS.md -->
# Payment Service Guide
## Security Rules
- Never log card information under any circumstances
- Handling raw card data is prohibited under PCI-DSS
- All monetary calculations must use integers (smallest currency unit)
## Tech Stack
- Node.js + Express (not Next.js)
- Testing: Jest + supertest (integration tests required)
- DB: PostgreSQL, raw SQL without an ORMWith this setup, an agent working in apps/web sees only the web rules, and one working in services/payments sees only the payment rules. There's no reason for security rules like "never log card information" to be exposed to a frontend agent, and equally no reason for Tailwind conventions to bleed into the payment service.
Example 3: Replacing Rules Entirely with AGENTS.override.md
This is useful when legacy codebases or services with a completely different tech stack coexist inside a monorepo. I run into this situation often in practice — the whole team has migrated to TypeScript, but a single legacy Java service is still alive. Inheriting root rules in that scenario only creates more confusion.
<!-- services/legacy-billing/AGENTS.override.md -->
# Legacy Billing Service (Standalone Rules)
⚠️ This service does not follow the root AGENTS.md rules.
## Technical Environment
- Java 11, Spring Boot 2.x (not TypeScript/Node)
- Maven build (`mvn clean install`)
- Testing: JUnit 5
## Modification Principles
- This service is frozen
- No new features beyond bug fixes
- Always verify existing tests pass before making changesEven if TypeScript rules exist at the root, agents working inside this directory read only the file above. This proactively blocks the strange behavior of "trying to migrate a legacy service to TypeScript."
Pros and Cons
Advantages
Two standout benefits of hierarchical structure deserve mention first.
The first is scope isolation. Different teams can maintain different conventions in one repo without conflict, and security-sensitive rules are never exposed to the wrong agent.
The second is context efficiency. Using the root as a pointer map only means the agent doesn't waste context window space reading rules irrelevant to its current task. This isn't merely about being "faster" — it directly affects the quality of the agent's actual decision-making.
| Item | Details |
|---|---|
| Tool neutrality | Over 20 AI tools including Codex, Copilot, Cursor, Windsurf, and Devin all recognize the same AGENTS.md |
| Scope isolation | Payment team rules are never exposed to frontend agents |
| Context efficiency | Using the root as a pointer map ensures agents load only what they need |
| Team alignment | All agents and engineers work from the same convention document |
| Faster onboarding | There are reports of AI agent session setup time dropping from tens of minutes to under 2 minutes |
Disadvantages and Caveats
Honestly, the two most common problems are root bloat and documentation rot.
Root bloat starts from the "let's just put everything in for now" mindset when first introducing AGENTS.md. Piling architecture docs, full team conventions, and onboarding guides into the root causes the 32 KiB limit to kick in, which means the subdirectory files that actually matter never get loaded.
Documentation rot happens when code changes over time but AGENTS.md stays put. The agent ends up repeatedly attempting bizarre tasks like "trying to import a deleted module." I didn't notice this at first, but it got much better once I developed the habit of reviewing the relevant AGENTS.md alongside the code during code review.
| Item | Details | Mitigation |
|---|---|---|
| Context waste | Putting large docs in the root means agents consume unrelated 80K tokens every time | Root as pointer only; push details to subdirectories |
| Documentation rot | Mismatches between code and AGENTS.md cause agents to repeat incorrect patterns | Review relevant AGENTS.md alongside code during code review |
| 32 KiB limit | Reading from root downward; once the limit is exceeded, subsequent files are not loaded at all | Keep each file as concise as possible |
| Tool behavioral differences | Claude Code prioritizes CLAUDE.md; Gemini CLI prioritizes GEMINI.md | In multi-agent environments, consider patterns that use tool-specific files in parallel |
| Backfire from LLM-generated content | According to arXiv research, AGENTS.md generated by LLMs lowered success rates by −3% and increased costs by over 20% | Always write files by hand as a developer |
Why you shouldn't use LLM-generated AGENTS.md as-is — LLMs tend to describe generic patterns without having "seen" the codebase. When content that doesn't match the actual project's specifics is included, the agent takes it as fact and repeats work in the wrong direction. A file written by a developer — even if short — is far more effective.
The Most Common Mistakes in Practice
- Dumping all architecture documentation into the root AGENTS.md — The full context is loaded on every task, which either hits the 32 KiB limit or shrinks the agent's actual working space.
- Writing AGENTS.md once and never updating it — If conventions change after a refactor but the file stays the same, the agent will try to restore deleted patterns or import modules that no longer exist.
- Having an LLM generate the AGENTS.md draft — "Read this project's code and create an AGENTS.md" looks convenient, but empirical research shows it actually degrades performance. A file written directly by a developer — even a short one — is far more effective.
Closing Thoughts
Keep the root lean, put rules in the relevant directory, handle exceptions with override — following just these three principles will make a visible difference in how well you control AI agents in a monorepo.
Three steps you can take right now:
- Check the current size of your root AGENTS.md. Run
wc -c AGENTS.mdto see the byte count. If it's over 2 KB, it's worth reconsidering what content actually needs to apply to every single task. - Pick one subdirectory you work in most often and create a dedicated AGENTS.md for it. Write 3–5 items yourself — the frameworks, testing tools, and forbidden patterns that apply only to that directory.
- Add a pointer section to the root AGENTS.md. Create a
## Subsystem Guidessection and add a single line pointing to the subdirectory file you just created. That completes the first step of a hierarchical structure.
Next post: How to keep AGENTS.md consistently maintained across an entire team — a practical look at how to catch the "code has changed but AGENTS.md is three months out of date" situation during code review, and how to naturally integrate document synchronization into team workflow.
References
- Custom instructions with AGENTS.md – OpenAI Codex 공식 문서
- AGENTS.md 공식 사이트
- GitHub – agentsmd/agents.md
- Steering AI Agents in Monorepos with AGENTS.md – DEV Community (Datadog)
- Taming Agents in the Mercari Web Monorepo – Mercari Engineering
- A good AGENTS.md is a model upgrade – Augment Code Blog
- How to Build Your AGENTS.md (2026) – Augment Code
- Evaluating AGENTS.md: Are Repository-Level Context Files Helpful? – arXiv 2602.11988
- On the Impact of AGENTS.md Files on the Efficiency of AI Coding Agents – arXiv 2601.20404
- AGENTS.md customization files – GitLab Docs
- CLAUDE.md, AGENTS.md & Copilot Instructions: Configure Every AI Coding Assistant – DeployHQ
- Will AI turn 2026 into the year of the monorepo? – Spectro Cloud