A practical, opinionated guide to building an agent instruction system that works across GitHub Copilot, Claude Code, Cursor, OpenAI Codex, Windsurf, and other autonomous coding agents. Designed for real-world codebases — not toy examples.
Last updated: 2026-02-25
- Philosophy
- Core Architecture
- Step-by-Step Setup
- Root AGENTS.md Template
- Per-Directory AGENTS.md
- Documentation Routing
- Agent Adapter Files
- Cursor .mdc Rules
- GitHub Copilot Integration
- MCP Tool Integration
- Codebase Health Alerts
- Anti-Patterns
- Maintenance
- Reference Implementation
Studies on AI coding agents consistently find:
- Context files that are too large degrade performance by ~20-25% and increase costs proportionally. Every unnecessary token in the context window competes for model attention.
- Negative instructions backfire ("don't use jQuery") — the "pink elephant effect" makes agents more likely to reach for the thing you told them to avoid.
- Outdated instructions actively sabotage agents — stale architectural descriptions cause agents to fight the code rather than work with it.
- Modern agents are excellent explorers — they can
grep, readpackage.json, and discover patterns dynamically. They don't need a prose walkthrough of your codebase.
- Route, don't replicate. AGENTS.md is an index into your documentation, not a copy of it. Point to files; let the agent read them when needed.
- Minimal token footprint. Root file under 200 lines. Per-directory files under 60 lines. Total injection for editing a single file: ~5K tokens max.
- Progressive disclosure. Global rules always apply. Lane/module-specific rules load only when the agent is editing in that area.
- Positive instructions only. State what to use and how, not what to avoid. If something is wrong, fix the code.
- Examples over prose. Link to real files as exemplars. One good code example teaches more than a paragraph of rules.
- Single source of truth. One canonical AGENTS.md, with lightweight adapter files for each agent tool. Never duplicate rules across files.
- Durable over comprehensive. Include only rules that change slowly (architecture, invariants, commands). Leave volatile content (recent changes, TODOs) out.
your-repo/
├── AGENTS.md # Root routing hub (canonical, ~150-200 lines)
├── CLAUDE.md # Adapter → AGENTS.md (for Claude Code)
├── CODEX.md # Adapter → AGENTS.md (for OpenAI Codex)
├── .windsurfrules # Adapter → AGENTS.md (for Windsurf)
├── .cursor/rules/ # Cursor .mdc rules with glob routing
│ ├── global.mdc # alwaysApply: true → reads AGENTS.md
│ ├── backend.mdc # globs: src/backend/** → backend rules
│ └── frontend.mdc # globs: src/frontend/** → frontend rules
├── .github/agents/
│ └── copilot-instructions.md # Pointer → AGENTS.md (for GitHub Copilot)
├── .docs/ # Curated library documentation
│ ├── README.md # Documentation index
│ └── <library>-docs/ # Per-library docs
├── src/
│ ├── backend/
│ │ └── AGENTS.md # Backend-specific rules
│ └── frontend/
│ └── AGENTS.md # Frontend-specific rules
| Agent | Discovery mechanism |
|---|
| GitHub Copilot | Reads .github/agents/copilot-instructions.md + AGENTS.md at repo root. Respects hierarchical AGENTS.md in subdirectories. |
| Claude Code | Reads CLAUDE.md at repo root. Walks directory tree for additional CLAUDE.md files. |
| OpenAI Codex | Reads AGENTS.md at repo root + directory-local AGENTS.md. Respects CODEX.md. |
| Cursor | Reads .cursor/rules/*.mdc files. Routes by YAML globs frontmatter, description (semantic match), and alwaysApply flag. |
| Windsurf | Reads .windsurfrules at repo root. |
| Generic | Most new agents check for AGENTS.md at repo root — it's becoming the de facto standard. |
Before writing any instruction files, understand what you have:
What languages/runtimes?
What are the major components/modules?
What libraries require special knowledge?
What are the non-negotiable rules (data integrity, security, compliance)?
What commands do developers run? (build, test, lint, format, deploy)
What documentation already exists?
This is the single most important file. It must be:
- Under 200 lines — agents read this for every interaction
- Structured with headers — agents parse markdown headers to find relevant sections
- Action-oriented — commands, rules, pointers. Not essays.
Only create these for modules/components with distinct rules, dependencies, or patterns that don't apply globally. Each file should:
- Reference the root AGENTS.md for global rules
- Be under 60 lines
- Cover only what's unique to that directory
Lightweight pointers that tell each agent tool to read AGENTS.md. Takes 5 minutes. Zero maintenance.
If you have local documentation (API docs, library guides, architecture docs), create an index file and reference it from AGENTS.md.
Glob-based rules that automatically inject context when the agent is editing files matching specific patterns.
Copy and adapt this template. Delete sections that don't apply. Keep it under 200 lines.
# AGENTS.md — [Project Name]
[One-line description of the project.]
## Stack
- [Language/runtime] — [purpose]
- [Framework] — [purpose]
- [Database] — [purpose]
## Commands
Use `[task runner]` as the canonical task runner. Run `[task runner]` to see all commands.
| Task | Command |
|------|---------|
| Install deps | `[command]` |
| Run tests | `[command]` |
| Lint | `[command]` |
| Format | `[command]` |
| Build | `[command]` |
| Start dev | `[command]` |
## Safety & Permissions
**Allowed without asking:** read files, format, lint, run scoped tests, search codebase.
**Ask first:** adding dependencies, schema migrations, CI changes, deleting files.
## Documentation & Dependencies
### Local docs (`.docs/`) — read these first
| Library | Entry point | Read when editing |
|---------|-------------|-------------------|
| [lib] | `.docs/[lib]-docs/index.md` | [relevant files/modules] |
See `.docs/README.md` for the full index.
### Live doc lookup (MCP context7) — fallback
When local docs are insufficient or missing:
1. `resolve-library-id` → find the library
2. `query-docs` → ask a specific question
## Key Invariants
[List non-negotiable rules that agents must never violate. These should be things
that cause data loss, security holes, or correctness failures if broken.]
1. **[Name]:** [description]
2. **[Name]:** [description]
## Code Style
- **[Language]:** [2-3 key conventions]
## Codebase Health Alerts
If you encounter genuinely surprising, architecturally inconsistent, or confusing code
that is not trivially fixable within your current task:
1. Surface it — tell the developer what is confusing and where
2. Explain why — describe the inconsistency or risk
3. Do not attempt large-scope refactors without approval
## Project Structure
[Copy your actual directory tree, annotated with one-line descriptions.
Keep it to top-level directories only.]
## When Stuck
1. Search the codebase — existing patterns are the best guide
2. Read the relevant docs in `.docs/`
3. Use MCP tools for live documentation
4. Ask the developer — propose a plan, don't guess on important decisionsCreate a per-directory AGENTS.md when a component has:
- Different language/runtime than the rest (e.g., Rust module in a Python project)
- Unique dependencies requiring special knowledge (e.g., XBRL parsing, GPU kernels)
- Critical safety rules not covered by the root file (e.g., financial compliance, crypto)
- Non-obvious architecture that an agent would misinterpret without context
- The module follows the same patterns as everything else
- The rules would just repeat the root AGENTS.md
- The module is < 5 files
# AGENTS.md — [Component Name]
> Global rules: see `../../AGENTS.md`
## Purpose
[One sentence: what this component does.]
## Key Dependencies
| Package | Purpose | Docs |
|---------|---------|------|
| [pkg] | [purpose] | `.docs/[pkg]-docs/` or `MCP context7` |
## Module Map
[Directory tree with one-line annotations for each file/folder.]
## Critical Rules
- [rule specific to this component]
- [rule specific to this component]
## Testing
[How to run tests for just this component.]
## Style
[Any style rules that differ from or supplement the root file.]Embedding documentation into AGENTS.md wastes tokens on every interaction. Routing tells the agent where to find docs and when to read them — so documentation is only loaded into context when the agent is actually working in a relevant area.
.docs/
├── README.md # Index — lists all doc sets with entry points
├── react-docs/
│ ├── index.md # Entry point agents read first
│ └── hooks/ # Deeper docs loaded on demand
├── prisma-docs/
│ └── index.md
└── stripe-docs.xml # XML API docs (for detailed signatures)
# Documentation Index
| Directory | Library | Entry Point | Scope |
|-----------|---------|-------------|-------|
| `react-docs/` | React | `react-docs/index.md` | Hooks, server components, patterns |
| `prisma-docs/` | Prisma | `prisma-docs/index.md` | Schema, migrations, client API |
| `stripe-docs.xml` | Stripe | (single file) | Payment API signatures |Where to get library docs for .docs/:
- Context7 MCP — query live docs and save relevant portions locally
- Official docs repos — many libraries publish markdown docs on GitHub
- repomix / doc2md — convert HTML docs to markdown
- Manual curation — write short guides covering your usage patterns (most valuable)
The routing table is the core of the system. It maps:
- Domain → what area of the codebase this covers
- Library → which dependency
- Entry point → where to start reading
- Trigger → when to read (which files/modules being edited)
| Domain | Library | Entry point | Read when editing |
|--------|---------|-------------|-------------------|
| Auth | NextAuth | `.docs/nextauth-docs/index.md` | `src/auth/`, middleware |
| DB | Prisma | `.docs/prisma-docs/index.md` | `prisma/`, `src/db/` |
| Payments | Stripe | `.docs/stripe-docs.xml` | `src/billing/` |Each agent tool looks for its own config file. Rather than duplicating instructions in each, create lightweight pointer files that all reference the canonical AGENTS.md.
# CLAUDE.md
All instructions are in `AGENTS.md` at the repo root. Read it fully before starting work.
Per-directory rules:
- `src/backend/AGENTS.md`
- `src/frontend/AGENTS.md`
Documentation index: `.docs/README.md`Same format as CLAUDE.md. OpenAI Codex reads AGENTS.md natively but also checks CODEX.md.
Same format. Windsurf reads this file from the repo root.
If you find yourself copying rules from AGENTS.md into an adapter file, stop. The adapter should only say "read AGENTS.md." If a tool doesn't support reading referenced files, keep the adapter as a condensed summary (under 20 lines) of the most critical rules only.
Cursor's .mdc format is the most powerful routing mechanism available. It uses YAML frontmatter to control when rules are injected.
---
description: Human-readable description (also used for semantic matching)
globs: # File patterns that trigger this rule
- src/backend/**/*.ts
- src/backend/**/*.py
alwaysApply: false # If true, loads for every interaction
---| Tier | Mechanism | When injected |
|---|
| Global | alwaysApply: true | Every interaction — use sparingly |
| Automatic | globs: [pattern] | When editing files matching the glob |
| Semantic | description field | When the agent's task semantically matches the description |
.cursor/rules/
├── global.mdc # alwaysApply: true — read AGENTS.md
├── backend.mdc # globs: src/backend/** — backend rules
├── frontend.mdc # globs: src/frontend/** — frontend rules
├── database.mdc # globs: prisma/**, src/db/** — DB rules
└── testing.mdc # globs: **/*.test.*, **/*.spec.* — test rules
---
description: Database layer — Prisma schema, migrations, query patterns
globs:
- prisma/**
- src/db/**
- src/**/*.repository.ts
---
Read `src/db/AGENTS.md` for database-specific rules.
Key constraints:
- Always use transactions for multi-table writes
- Never use raw SQL — use Prisma client
- Run `npx prisma generate` after schema changes
- Docs: `.docs/prisma-docs/index.md`This file is Copilot's primary instruction source. After setting up AGENTS.md, slim it down to a pointer:
# GitHub Copilot Instructions
All development guidelines live in `AGENTS.md` at the repo root.
Read it as your primary instruction source.
Per-directory rules: see `AGENTS.md` → "Project Structure" section.
Documentation: `.docs/README.md`The Copilot coding agent (used for GitHub Issues and PRs) reads:
.github/agents/copilot-instructions.mdAGENTS.mdat the repo root- Hierarchical
AGENTS.mdfiles in subdirectories
It also runs the setup steps defined in .github/workflows/copilot-setup-steps.yml to prepare the environment.
MCP (Model Context Protocol) tools like context7 give agents the ability to fetch live, up-to-date documentation for any library at query time. This supplements your local .docs/ directory.
Local .docs/ → preferred (curated for your project's patterns)
↓ (if insufficient)
MCP context7 → fallback (live upstream docs)
Add this to your Documentation section:
### Live documentation lookup (MCP context7) — fallback
When local docs are insufficient, outdated, or missing for a library:
1. `resolve-library-id` — find the library's context7 identifier
2. `query-docs` — ask a specific question about that library's API
Use for: libraries without local docs, version-specific API questions, niche features.| Scenario | Use |
|---|
| Library has curated .docs/ entry | Local docs |
| Library not in .docs/ | MCP context7 |
| Need latest API for a specific version | MCP context7 |
| Need project-specific patterns | Local docs |
| Quick API signature lookup | MCP context7 |
This is one of the most valuable meta-instructions you can give an agent. Instead of only executing tasks, the agent becomes a passive codebase auditor that surfaces problems organically during normal work.
Add this to your root AGENTS.md:
## Codebase Health Alerts
If you encounter code that is genuinely surprising, architecturally inconsistent,
or likely to confuse future developers, and the issue is not trivially fixable
within your current task:
1. Surface it — tell the developer what is confusing and where
2. Explain why — describe the inconsistency or risk
3. Do not attempt large-scope refactors without approval
4. Do not flag minor style issues, TODOs, or things you can fix inline- Agents read thousands of lines of code during every task — they see patterns humans miss
- This creates a free, continuous codebase quality audit
- The "not trivially fixable" filter prevents noise from minor issues
- The "don't refactor without approval" guard prevents agents from going rogue
- Over time, the alerts tell you which parts of your codebase need the most attention
An advanced technique (credit: Theo Browne): add an instruction saying "if you get confused, update AGENTS.md with what confused you." You don't actually want the agent to modify AGENTS.md — but when it tries, you can see exactly what parts of your codebase are confusing to agents (and likely to humans too), giving you a prioritized refactoring backlog.
Problem: 500+ line AGENTS.md that describes every module, every pattern, every decision. Why it fails: Tokens compete for attention. The model drowns in irrelevant context. Fix: Keep AGENTS.md under 200 lines. Route to detailed docs.
Problem: "Do NOT use jQuery," "Never use class components," "Avoid lodash." Why it fails: The pink elephant effect — mentioning something makes the model more likely to use it. Fix: State what to use: "Use React hooks for state management." Delete the mention of the old thing entirely.
Problem: Same rules in AGENTS.md, CLAUDE.md, .cursorrules, and copilot-instructions.md. Why it fails: They inevitably drift. Agent sees conflicting instructions. Fix: One canonical AGENTS.md. All others are pointers.
Problem: AGENTS.md describes the architecture from 6 months ago. Why it fails: Agent generates code that doesn't match current patterns. Actually worse than no instructions. Fix: Only include architecture that changes slowly (invariants, major components). Leave volatile details out.
Problem: Paragraphs explaining why a pattern was chosen. Why it fails: Agents need what and how, not why. Explanations burn tokens. Fix: Tables, bullet points, code examples. Save the "why" for ADRs or design docs.
Problem: AGENTS.md tells agents what to do but not how to verify. Why it fails: An agent that can't run tests can't validate its changes. Fix: Always include commands for test, lint, and format. These are the agent's self-check mechanism.
Problem: Every function edit requires reading 3 doc files. Why it fails: Excessive doc reads slow agents down and burn tokens/cost. Fix: Only route to docs for libraries that require special knowledge. Standard language features don't need doc routing.
- New major component added to the project → add to structure, possibly create per-directory file
- New critical invariant discovered → add to Key Invariants
- Breaking change in a key dependency → update routing table
- Command changes (new task runner, new test command) → update Commands table
- Architecture shift (new service, removed component) → update structure
- Minor refactors within existing patterns
- New features that follow established patterns
- Bug fixes
- Dependency version bumps (unless the API changed)
- Adding TODOs, recent changes, or changelogs (these belong in git history)
Every 1-3 months, do a quick pass:
- Does the project structure section still match reality? (
tree -L 2) - Do the commands still work? (Run each one)
- Are the key invariants still true? (Check the code)
- Are any docs in
.docs/outdated? (Check library versions) - Are there new libraries that need routing?
This takes 15 minutes and prevents the #1 failure mode: stale instructions.
This guide was developed for and applied to Project ARGUS, a multi-lane financial data lakehouse. The implementation includes:
AGENTS.md # Root routing hub (~160 lines)
CLAUDE.md # Pointer → AGENTS.md
CODEX.md # Pointer → AGENTS.md
.windsurfrules # Pointer → AGENTS.md
.cursor/rules/
argus-global.mdc # alwaysApply: true
ingestor-rs.mdc # globs: apps/ingestor-rs/**
worker-py.mdc # globs: apps/worker-py/**
api-py.mdc # globs: apps/api-py/**
analytics-duckdb.mdc # globs: analytics/duckdb/**
.github/agents/copilot-instructions.md # Slimmed pointer → AGENTS.md
.docs/README.md # Documentation index
apps/ingestor-rs/AGENTS.md # Rust lane rules
apps/worker-py/AGENTS.md # Python worker lane rules
apps/api-py/AGENTS.md # Python API lane rules
analytics/duckdb/AGENTS.md # DuckDB analytics lane rules
| Metric | Value |
|---|---|
| Root AGENTS.md | ~160 lines / ~3.5K tokens |
| Per-app AGENTS.md | ~50-80 lines / ~1.5K tokens each |
| Max cold-start injection | ~5K tokens (root + one per-app) |
| Adapter files | ~10 lines each |
| Cursor .mdc files | ~15 lines each |
| Local doc libraries | 9 (with README index) |
| Total maintenance surface | 1 canonical file + 4 per-app files |
The golden ratio: root AGENTS.md + one per-directory file < 6K tokens. This leaves >95% of the context window available for actual code analysis and generation, even on smaller models.