My agents adapt to where they work in the codebase. Here’s how.

On this page
  1. The repo is a map of the instructions#
  2. What I put in each layer#
  3. Concatenation needs scope and precedence#
  4. Watch the work move through the repo#
  5. What the agent actually loads#
  6. How I decide where a file belongs#
  7. Verify the setup with a real task#
For terminals & agents: curl -s https://jedarden.com/notes/dynamic-context-with-agents-md.md

I want an agent changing a frontend component to think about keyboard behavior and design tokens. I want the same agent changing a database migration to think about existing data and whether the migration has already run. Those are different jobs, even when they happen in the same repository.

My way of giving the agent that context is to put AGENTS.md files at the places where the work changes. One at the root for the whole repository. Another in the frontend. Another in the backend. A more specific one around database work, if it needs its own rules.

The agent gets shared instructions plus the instructions that apply to the part of the repo it is working in. The directory structure becomes part of how I write the prompt.

I call this “dynamic” context because the relevant combination changes with the work. The files themselves are ordinary Markdown, sitting beside the code they describe.

The repo is a map of the instructions#

Here is a small example. The paths and rules below are illustrative; this is the arrangement I want readers to be able to copy into their own projects.

app/
├── AGENTS.md                         shared repository rules
├── frontend/
│   ├── AGENTS.md                     interface and browser rules
│   └── Checkout.tsx
├── backend/
│   ├── AGENTS.md                     service and test conventions
│   ├── routes/
│   │   └── orders.ts
│   └── db/
│       ├── AGENTS.md                 migration rules
│       └── migrations/
│           └── 042_orders.sql
└── docs/
    ├── AGENTS.md                     documentation conventions
    └── setup.md

For frontend/Checkout.tsx, the relevant repository instructions are the root file and the frontend file. For backend/db/migrations/042_orders.sql, they are the root file, the backend file, and the database file, in that order.

The frontend file is a sibling of the backend subtree. Its rules do not govern the migration. And routes/ does not need an instruction file merely because it is a directory; it inherits the backend guidance.

Select a file in the visualization to see its applicable instructions assemble. The stack shows scope: which guidance belongs to that file. It does not represent a live trace of a particular agent loading its prompt.

The underlying rule is simple enough to write down:

Instructions for a file
  = shared guidance supplied by the environment
  + repo-root guidance
  + applicable ancestor-directory guidance, broadest to narrowest

This gives me a place to put a fact once, at the level where it becomes true. A convention for every service belongs in the backend file. A constraint that only matters for migrations belongs closer to the migrations.

What I put in each layer#

The root file establishes the working agreement for the repository. I keep it focused on things that should survive a move between directories: how to preserve compatibility, how to find the right checks, and how to discover more specific instructions before editing.

For this example, the root could contain:

# Repository working agreement

- Preserve public interfaces unless the task explicitly changes them.
- Default verification: run the relevant package's tests.
- Before editing a file, inspect applicable nested AGENTS.md files
  along its directory path. Follow their rules for that scope.
- Local files may replace a named default within their scope.
  Other applicable parent rules still apply.

That third instruction matters. It tells the agent to check the area it is about to touch, including when a task starts at the root and later moves into a subdirectory.

In frontend/AGENTS.md, I put the things that distinguish frontend work:

# Frontend

- Reuse the existing design tokens and components.
- Check changed interactions with a keyboard.
- Check the affected screen at a narrow viewport.
- Run the frontend package's tests after changing behavior.

In backend/AGENTS.md, the emphasis changes:

# Backend

- Keep route handlers thin; put business behavior in the service layer.
- For backend changes, replace the root verification default with
  backend unit tests. This is the default backend verification.
- Preserve documented response shapes unless the task changes them.

Then backend/db/AGENTS.md can be more specific still:

# Database

- Treat applied SQL migrations as append-only. Add a new migration
  to change a schema that has already been deployed.
- For SQL migration changes, replace the backend unit-test default
  with the migration integration check against a disposable database.
- Verify both an empty database and an upgrade from the previous schema.
- If application code also changes, run its applicable checks too.

In a real repo, I put the actual commands and their working directories in these files. “Run the integration check” is enough to explain the example, but a worker needs to know which command that means and what success looks like. A command that relies on my memory is an unfinished instruction.

Concatenation needs scope and precedence#

It is useful to picture the instruction files being concatenated into one prompt: the broad agreement first, followed by increasingly local guidance. But concatenation alone does not resolve an ambiguous instruction.

In the database example, the local file names exactly what it replaces: the backend unit-test default for SQL migration changes. The root requirement to preserve public interfaces still applies. So does the requirement to check changed application code when the task touches it.

I prefer an explicit replacement like that to two disconnected commands that happen to disagree. It lets both a human and an agent explain why the verification plan changed.

File being changedApplicable repository filesResulting behavior
frontend/Checkout.tsxRoot → frontendReuse UI conventions; check keyboard behavior and narrow screens.
backend/routes/orders.tsRoot → backendKeep the handler thin; preserve response contracts; run backend unit tests.
backend/db/migrations/042_orders.sqlRoot → backend → databaseAdd a migration; use the migration integration check for the SQL change.
docs/setup.mdRoot → docsVerify the commands and provide runnable examples.

These are instructions within the task’s existing authority. A local file cannot grant permission the agent does not have, or make a repository convention outrank a higher-priority instruction from its environment.

Watch the work move through the repo#

Imagine a task to add an order field. It might touch the checkout form, an API handler, the database schema, and the setup documentation.

The root agreement applies throughout. Each move brings a different set of local concerns into play. The frontend guidance explains how to check the form. The backend guidance explains where the service behavior belongs. The database guidance adds the upgrade path. The documentation guidance makes the examples usable.

Play the walkthrough, or step through one file at a time. Watch the shared layer stay in place while the applicable local layers change. Moving deeper into the database subtree adds another layer; moving across to documentation selects a different branch.

For a task that crosses all four areas, I expect all four areas’ checks to be accounted for. The last file edited does not define the rules for the entire change. Each changed file keeps its scope, and the final verification plan covers the combined work.

Nor does a change of scope mean the model forgets text it has already read. Instructions can remain in the conversation while ceasing to apply to the next file. That is why I make their boundaries explicit.

What the agent actually loads#

There is one implementation detail to get right before relying on this pattern. Instruction scope and automatic discovery are separate things.

Codex documents its initial discovery as a chain built once per run: global guidance, then files along the path from the project root to the current working directory. It includes at most one instruction file per directory, with AGENTS.override.md taking precedence over AGENTS.md at that level. The project instruction budget defaults to 32 KiB. Starting in a deeper directory changes that initial chain. Simply mentioning a deeply nested file from a root session does not mean that initial discovery traverses its path. Official AGENTS.md documentation

That is why my root guidance also tells the agent to inspect applicable nested files before editing. I treat automatic startup loading and deliberate inspection during the task as two parts of the setup. I verify both in the agent environment I am using.

“They become the system prompt” is a convenient shorthand for the effect, but combined instruction context is more precise. OpenAI’s prompting guide describes the discovered AGENTS.md chunks as user-role messages injected into the conversation in root-to-leaf order. They are not a replacement for the model’s underlying system instructions. Official Codex prompting guide

Other agent tools can use different filenames and loading rules. I check those rules before assuming this directory layout is sufficient on its own. I use the exact filename AGENTS.md where that is the supported convention.

How I decide where a file belongs#

I add an instruction file at a boundary where the agent’s decisions should change. A package with different test commands is a good candidate. So is a directory containing generated code, a compatibility-sensitive interface, or schema migrations.

I do not need a file in every directory. If a child file would repeat its parent, inheritance already does the job. If a child needs a paragraph of exceptions to every parent rule, I reconsider whether the parent is claiming too much scope.

My test for an instruction is concrete: what would the agent do differently after reading this? “Write good code” has no useful answer. “Preserve this response shape because older clients still consume it” does. So does “edit the schema source and regenerate this directory.”

I keep these files with the code and update them when the workflow changes. If I replace the test runner, the test command changes in the same work. If a constraint stops being true, I remove it. Stale instructions are executable-looking misinformation.

The instructions also need to fit the available context. Splitting one huge file into several huge files along the same path still creates a huge stack. I keep the standing rules short and point to deeper references when the task needs them.

Verify the setup with a real task#

I packaged this workflow as setup-repo-context, an MIT-licensed skill you can download as a versioned ZIP. It asks the agent to derive instruction boundaries from your repository, preserve existing rules, and show the resulting behavior for representative files and a task that crosses scopes. The repository includes installation instructions; use $setup-repo-context after installing it.

To try this in a repository, I would start with this prompt:

Inspect this repository and its existing agent instructions. Find the
boundaries where the work needs different guidance: test commands,
compatibility constraints, generated files, or data migrations.

Propose the smallest useful set of scoped AGENTS.md changes. Use rules
supported by the code and documented workflow; flag anything uncertain.
Preserve existing instructions and avoid repeating parent rules.

For a representative file in each scope, show the applicable instruction
chain, any explicitly replaced defaults, and the checks you would run.
Also explain how my agent discovers those files during a task.

Before trusting the arrangement, I give the agent a small task in each important area and ask it to identify the applicable instruction files and the checks it will run before it edits anything.

For the migration example, I should be able to see the root, backend, and database guidance reflected in its plan. The meaningful result is a new migration and the right upgrade check. An agent reciting three filenames and then editing an applied migration has not passed the test.

I also try a task that crosses a directory boundary. That tests whether the agent discovers the next area’s instructions, rather than assuming the context it started with is sufficient for everything it will touch.

This setup gives me a practical way to make context travel with the code. The shared expectations stay at the root. The specialized knowledge lives where it becomes relevant. When I want to change how agents work in one part of the repository, I have a small, reviewable file to change beside it.