Context Architecture

Scoping Agent Context in Monorepos: Nested Files and Precedence

David Guzenburg/ / 7 min read

One repository, three languages, three sets of build commands. The root context file cannot answer 'how do I run the tests' — and it should stop trying.

AGENTS.mdmonorepocontext filesprecedence

The problem a single file cannot solve

A monorepo containing a Go service, a TypeScript frontend and a Python data pipeline has no shared answer to "how do I run the tests". A single root context file has three bad options: state all three commands and let the agent guess which applies, state the most common one and be wrong a third of the time, or state none and let the agent discover them.

Nested context files solve this. Most tools that read AGENTS.md support multiple files through the tree, with the file nearest the code being edited taking precedence. The root carries what is true everywhere; each package carries its own specifics.

AGENTS.md                    ← true for the whole repo
packages/
  api/
    AGENTS.md                ← Go service specifics
    cmd/ internal/
  web/
    AGENTS.md                ← TypeScript frontend specifics
    src/
  pipeline/
    AGENTS.md                ← Python specifics
    dags/

Precedence is proximity, not specificity

This is the rule people get wrong. When an agent edits packages/web/src/App.tsx, it reads the root file and packages/web/AGENTS.md. The web file wins on any conflict — not because it is more detailed, but because it is closer.

The practical consequence: if you find yourself writing "except in the web package" in your root file, that exception belongs in the web file. Conditional rules at the root are a smell. They cost tokens on every session regardless of what is being edited, and they force the agent to evaluate a condition it may evaluate wrongly.

Root filePackage file
Commit message formatBuild and test commands
Branch namingLanguage-specific style rules
Secrets handling policyLocal dependencies and their quirks
Cross-package import boundariesFrozen or generated directories
Which packages exist and what each is forTraps specific to this package

The root file's real job in a monorepo

Counterintuitively, the root file in a monorepo should be shorter than in a single-package repo, not longer. Almost everything concrete is package-local. What remains is the map and the rules that cross boundaries.

# AGENTS.md

## Layout
- `packages/api/` Go HTTP service — see its AGENTS.md
- `packages/web/` React frontend — see its AGENTS.md
- `packages/pipeline/` Airflow DAGs — see its AGENTS.md
- `packages/shared/` protobuf schemas, generated clients

## Cross-package rules
- Nothing imports from another package's internals. Cross-package code
  goes through `packages/shared/`.
- `packages/shared/` is generated from `proto/`. Run `make proto`,
  never hand-edit.
- A change touching two packages needs both owners on the PR.

## Everywhere
- Conventional Commits. Branch: `type/short-description`.
- Secrets from env only. Never inline, never in fixtures.

Seventeen lines. An agent editing the frontend pays for those seventeen lines and then gets the web package's file, which tells it about pnpm and Vitest and the component conventions. An agent editing the pipeline pays for the same seventeen and gets a completely different second file.

The pointer pattern

"see its AGENTS.md" costs four tokens and tells the agent a more specific file exists. Without it, an agent that has only opened root-level files may never look. Cheap insurance.

How deep to nest

Two levels is almost always right: root, and one per package. Three levels — root, package, sub-module — occasionally earns its place in a genuinely large package where one subsystem has rules the rest does not.

Beyond that you are describing the code rather than constraining it, and you have re-created the problem the discoverability test exists to prevent. If a directory needs its own context file to be comprehensible, consider whether the directory needs restructuring instead.

Verifying resolution actually works

Do not assume your tool resolves nesting the way you expect. Support varies, and a file that is never read is worse than no file, because you will believe a rule is in force when it is not.

The check takes two minutes. Put a distinctive, harmless instruction in a package file — something you would never write by convention:

## Verification
When asked "which context files can you see", reply with the exact
string: WEB-CONTEXT-LOADED

Open a session scoped to that package, ask the question, and see whether the string comes back. Then ask from the repository root, where it should not appear. That tells you both that nesting works and that scoping works. Delete the block afterwards, or keep it — it costs three lines and it is the only direct evidence you will get.

What happens when a package file goes missing

A failure mode specific to nesting: an agent working in a package whose context file does not exist falls back to the root, silently. It does not announce that it found no local file. It just proceeds with less information than you assumed it had.

In a repository where three of five packages have context files, the two without them get noticeably worse agent output, and the difference is invisible until someone compares. New packages are the usual culprits — the scaffolding creates the source layout and the CI config and nobody remembers the context file, because unlike those two, nothing breaks without it.

Two mitigations, both cheap. Put a context file in whatever template you use to scaffold a new package, even if it starts as four lines. And add a check that every directory under packages/ contains one:

#!/bin/bash
missing=0
for d in packages/*/; do
  if [ ! -f "$d/AGENTS.md" ]; then
    echo "missing: $d/AGENTS.md"
    missing=1
  fi
done
exit $missing

Six lines, runs in CI, and converts a silent degradation into a visible failure. That trade — making an invisible problem noisy — is the recurring theme of everything in this pillar.

Ownership

Package context files should be owned by the team that owns the package, and enforced through the same mechanism — a CODEOWNERS entry covering packages/*/AGENTS.md means changes route to the people who will live with them.

The root file is a different matter. It affects every agent session in the repository, and it is exactly the kind of file that accumulates well-meaning additions until it is two hundred lines of nobody-remembers-why. Give it a named owner and a size budget, and treat a proposal to add ten lines as a proposal to slow down every session in the repo — because that is what it is.

Takeaway

Root file: the map, and rules that cross boundaries. Package files: everything concrete. Precedence follows proximity, so push exceptions downward rather than qualifying them upward. And verify your tooling actually reads the nested files before trusting them.

Keep reading
Context Architecture

Why Duplicating Your README Into AGENTS.md Makes Agents Worse

Copying project overview into a context file measurably degrades agent performance. The three mechanisms behind it, and a discoverability test for deciding what to cut.

Context Architecture

The AGENTS.md Specification: Anatomy of a Repository Context File

What belongs in an AGENTS.md file, the six sections that carry the weight, why short files outperform comprehensive ones, and where context files stop working.

Context Architecture

AGENTS.md vs CLAUDE.md vs .cursorrules: When One File Isn't Enough

Whether to keep one context file or several, the three cases where a second file is justified, and why the symlink workaround usually disappoints.

Context Architecture

Encoding Architectural Constraints and Module Boundaries for Agents

Why naming your architecture pattern doesn't work, how to state dependency directions as checkable rules, and why every prohibition needs an escape hatch.

AST-Based Repository Indexing: Giving an Agent Exact Answers →

All context architecture articles  ·  Every article