Every coding agent session starts with no memory of your project. It does not know that tests need a database container, that money is stored in cents, or that one package is frozen. Instruction files are how you tell it, once, instead of in every chat: a Markdown file in the repository that the agent loads into its context at the start of each session. AGENTS.md is the vendor-neutral form, read by many agents; CLAUDE.md is Claude Code's; skills package longer procedures that load only when needed.

Most instruction files are written once, grow by accretion and quietly stop working: too long to be followed, full of things the agent could have discovered itself, and silent on the three gotchas that actually cost time. This guide explains how these files reach the model, what belongs in each layer, a worked example for a monorepo, how to share one file across tools, how to test the files, and when an instruction should not be an instruction at all but a hook or a permission rule.

Advertisement

How instruction files reach the model

An instruction file is not configuration in the usual sense. The agent reads it and places its text in the context window, usually near the start of the conversation, where the model weighs it alongside everything else. Claude Code's documentation is explicit that CLAUDE.md is delivered as context rather than enforced configuration, and that specific, concise instructions are followed more consistently than long or vague ones. That one fact explains most of this guide: every line costs context in every session, and every line competes for attention with every other line.

Files are layered. Claude Code loads a managed organisation-wide file, the user's ~/.claude/CLAUDE.md, and CLAUDE.md or .claude/CLAUDE.md files from the working directory and each directory above it, concatenated from the broadest scope to the most specific, so project instructions appear after user ones. A personal, gitignored CLAUDE.local.md is appended after the project file at the same level. Files in subdirectories below the working directory load on demand, when the agent reads files there. AGENTS.md takes a similar hierarchical approach: agents read the nearest file in the directory tree, the closest one takes precedence, and the user's explicit chat prompt overrides both. The precise loading rules for other agents vary, so check each tool's documentation rather than assuming.

Where each kind of instruction reaches the agentAlways loadedroot AGENTS.md / CLAUDE.md, user fileLoaded on path matchnested files, path-scoped rulesLoaded on demandskill body when relevant or invokedEnforced outside the modelhooks, permissions, CIAgent context windowproject instructions: every sessionrules for the files being editedskill descriptions: short, always listedskill body: only when usedall of this is advice the model weighs, not a guaranteeTool call gatea hook or permission rule can block the action regardless of the model
Four layers. Always-loaded files cost context in every session; path-scoped rules load with matching files; skill bodies load only when used. Anything that must happen belongs in the fourth layer, enforced by the harness rather than requested of the model.

What belongs in the always-loaded file

The test for a line in the root file is: would a competent engineer new to this repository get this wrong, and does it apply to almost every task? That selects a small set of categories. Commands: how to install, run one package's tests, lint and type-check, with the non-obvious parts (the full suite takes twenty minutes; run one package). Conventions that differ from defaults: the model already knows how to write idiomatic Python, so tell it only where your codebase departs from that. Gotchas: the failure messages that mean something specific here, the directories not to touch. Definition of done: which checks must pass before the agent reports success.

Equally important is what to leave out. Directory listings, dependency lists and architecture overviews are things the agent can discover by reading the code, and they go stale. Claude Code's own trim check for CLAUDE.md removes exactly those and keeps pitfalls, rationale and conventions that differ from tool defaults. Claude Code's guidance is to keep each CLAUDE.md under about 200 lines, and to make each instruction concrete enough to verify: 'run make check before finishing' rather than 'test your changes'.

# AGENTS.md  (repository root)

## Project
Orders service: Python 3.12, FastAPI, Postgres. Monorepo; packages under packages/.

## Commands
- install: `make setup`
- test one package: `make test PKG=orders`  (full suite takes 20 min; avoid)
- lint + types: `make check`  (must pass before you say you are done)

## Conventions that differ from defaults
- money is integer minor units (cents), never float; see packages/money
- DB access only through repositories in */repo.py; no raw SQL in handlers
- new endpoints need an OpenAPI example; CI fails without one

## Gotchas
- tests need `docker compose up db` first; failures mentioning port 5433 mean it is down
- packages/legacy_billing is frozen: do not edit, open an issue instead

## Pull requests
- one logical change per PR; title "area: summary"; link the issue
Advertisement

AGENTS.md: the shared format

AGENTS.md is a plain Markdown file with no required fields or schema; you use whatever headings help. The project site suggests project overview, build and test commands, code style, testing instructions and security considerations, plus things like pull request conventions and deployment steps. It is now stewarded by the Agentic AI Foundation under the Linux Foundation. In a monorepo, put a root file with repository-wide rules and a nested AGENTS.md in each package with that package's commands and conventions. Because the nearest file wins, a package file can override a root default, which is useful but also a way to create silent contradictions, so keep overrides explicit ('unlike the root, this package uses pytest-xdist').

Agents act on listed commands: list tests and checks and they will run them and fix failures, so keep the commands exact and fast.

CLAUDE.md, imports and scoped rules

If your repository already has AGENTS.md and you also use Claude Code, the portable pattern is a thin CLAUDE.md that imports it with an @AGENTS.md line and adds only Claude-specific instructions below. Imports use @path syntax, resolve relative to the importing file, and can nest up to four hops; imported files still load at launch, so imports organise text without saving context. Recent Claude Code versions can also read AGENTS.md directly when no CLAUDE.md is present, but the import works regardless of version and makes the relationship explicit. A symlink also works, but Windows clones may check it out as a plain text file.

The root CLAUDE.md for the monorepo above is then just this:

@AGENTS.md

## Claude Code specifics
- use plan mode for changes under packages/payments/

Instructions that apply only to some files belong in .claude/rules/. A rule file with a paths list in its YAML frontmatter loads only when the agent works with matching files, so migration rules cost nothing while the agent edits a handler. Rules without paths load every session, like the main file. Save this as .claude/rules/migrations.md; the frontmatter must be the first thing in the file:

---
paths:
  - "packages/*/migrations/**/*.py"
---
- migrations must be reversible: implement downgrade()
- never combine a schema change and a data backfill in one migration

Skills: procedures that load on demand

When a section of an instruction file grows into a multi-step procedure used for one kind of task, move it into a skill. A skill is a folder with a SKILL.md file: YAML frontmatter with a name and a description, then Markdown instructions, plus optional supporting files such as templates or reference notes. Claude Code follows the Agent Skills open standard for this format. In a normal session only each skill's description sits in context; the body loads when the model judges the skill relevant or the user invokes it by name. That makes the description the trigger, so write it as 'what it does, and when to use it', with the key use case first. Keep SKILL.md under about 500 lines and push reference material into supporting files the skill tells the agent to read. This one is saved as .claude/skills/add-endpoint/SKILL.md:

---
name: add-endpoint
description: Adds a new REST endpoint to a package in this monorepo, with
  repository method, handler, OpenAPI example and tests. Use when asked to add
  or expose an API route.
---
1. Find the package's router in packages/<pkg>/api/routes.py.
2. Add a repository method in packages/<pkg>/repo.py; no SQL in the handler.
3. Add the handler; validate input with the package's pydantic models.
4. Add an OpenAPI example (see examples.md in this skill folder for the format).
5. Add tests: success, validation error, auth failure. Run `make test PKG=<pkg>`.
6. Run `make check`. Report the commands you ran and their results.

Skills that perform side effects, such as deployments, are usually better invoked only by a person; Claude Code supports a disable-model-invocation frontmatter flag for that. Skill architecture, discovery at scale and versioning are covered in depth in Agent Skills Architecture and Skill Versioning and Composition, and the common mistakes in Agent Skills Anti-Patterns.

When an instruction should be a hook instead

Instruction files are requests. For anything that must happen, or must never happen, use a mechanism the harness enforces. Claude Code hooks run shell commands at fixed lifecycle events, such as before a tool call, and can block the action; permission rules can deny tools, commands or paths outright; CI can reject a pull request. 'Do not edit packages/legacy_billing' in AGENTS.md is a good explanation of intent; a PreToolUse hook that rejects writes to that path is the guarantee. Keep both: the instruction tells the agent why, so it does not waste turns fighting the hook. In .claude/settings.json, register a command hook for file edits:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [{ "type": "command", "command": "python scripts/guard_frozen.py" }]
      }
    ]
  }
}

The hook receives the pending tool call as JSON on standard input, with the target path in tool_input.file_path for file tools. Exiting with code 2 blocks the call, and the message on standard error is fed back as the reason:

# scripts/guard_frozen.py: the hook receives the tool call as JSON on stdin
import json, sys
path = json.load(sys.stdin).get("tool_input", {}).get("file_path", "")
if "packages/legacy_billing/" in path.replace("\\", "/"):
    print("packages/legacy_billing is frozen; open an issue instead", file=sys.stderr)
    sys.exit(2)   # exit code 2 blocks the tool call; stderr explains why

The same logic applies to style. If a formatter can fix it, run the formatter in a hook or in CI and delete the style instructions; the model should not spend attention on what a tool does deterministically. The general principle, that system-level rules should override conversational ones, is discussed in Instruction Hierarchy.

Testing and maintaining instruction files

Instruction files rot like documentation, with a worse failure mode: the agent follows a stale command confidently. Two practices keep them honest. First, lint them in CI: size, references to paths that no longer exist, commands that are not real targets. Second, evaluate them: keep a handful of representative tasks, run the agent on them before and after changing an instruction file, and compare outcomes such as whether it ran the right tests or touched a frozen directory. The testing approaches in Skill Testing and Validation apply equally to instruction files.

# Lint instruction files in CI: size, dead paths, dead commands.
import re, sys
from pathlib import Path

FILES = [p for p in Path(".").rglob("*") if p.name in ("AGENTS.md", "CLAUDE.md")]
MAKE_TARGETS = set(re.findall(r"^([\w-]+):", Path("Makefile").read_text(), flags=re.M))
problems = []
for f in FILES:
    text = f.read_text(encoding="utf-8")
    lines = text.count("\n") + 1
    if lines > 200:
        problems.append(f"{f}: {lines} lines; move procedures to skills or scoped rules")
    for path in re.findall(r"\b(packages/[\w./-]+)", text):
        if "*" not in path and "<" not in path and not Path(path.rstrip(".")).exists():
            problems.append(f"{f}: references missing path {path}")
    for target in re.findall(r"`make ([\w-]+)", text):
        if target not in MAKE_TARGETS:
            problems.append(f"{f}: `make {target}` is not a Makefile target")
print("\n".join(problems) or "instruction files ok")
sys.exit(1 if problems else 0)

Add to the files from evidence, not imagination. Good triggers are the agent making the same mistake twice, a reviewer catching something the agent should have known, or you typing the same correction into chat that you typed last week. Remove lines when the underlying problem is fixed in code.

Failure modes

  • The kitchen-sink file. Eight hundred lines covering everything, so nothing stands out. Adherence drops as length grows; split into scoped rules and skills.
  • Contradictions across layers. A user file, a root file and a nested file disagree, and the model picks one arbitrarily. Audit the layers together.
  • Stale commands. The Makefile target was renamed and the file was not. Lint references in CI.
  • Discoverable content. Directory trees and dependency lists that the agent could read itself, going stale and costing tokens every session.
  • Instructions as enforcement. Security-critical rules written only as prose. Back them with hooks, permissions or CI.
  • Vague skill descriptions. 'Helper for API stuff' never triggers, or triggers on everything. Name the task and the trigger phrases.

Trade-offs

Always-loaded text is the most reliable way to reach the model and the most expensive, because it is paid for in every session and dilutes itself as it grows. Scoped rules and skills are cheaper but depend on the agent loading them at the right time. Hooks are reliable but blunt, and they explain nothing. A good setup uses all four layers: a short root file of commands, conventions and gotchas, rules for file-specific constraints, skills for procedures, and enforcement for the few things that must never go wrong.

What to do next

  • Read your current AGENTS.md or CLAUDE.md and delete every line the agent could discover from the code.
  • Make sure the file lists exact commands for install, single-package tests and checks, and states which must pass before done.
  • Add your top three gotchas: the errors and directories that have cost your team time with agents.
  • Move file-specific rules into path-scoped rules and multi-step procedures into skills with precise descriptions.
  • If you use several agents, keep one AGENTS.md and import it from a thin CLAUDE.md.
  • Turn every 'never' that matters for safety into a hook, permission rule or CI check.
  • Add the linter above to CI and rerun a small set of representative agent tasks whenever the files change.
Key takeaway: Instruction files are context the model weighs, not rules it must obey, so they work when they are short, specific and about things the agent cannot discover: exact commands, conventions that differ from defaults, gotchas and the definition of done. Layer them: a root AGENTS.md or CLAUDE.md for every session, path-scoped rules for specific files, skills for on-demand procedures, and hooks, permissions or CI for anything that must be enforced. Lint them, test them against real tasks, and grow them only from observed mistakes.