Split Instructions Across Files

Read21 min · Plan → Implement → Verify → Evolve · Updated 2026-09-15

You end this lesson with: Your instruction set split into a root contract plus scoped rule files.

Chapters

  1. The Vicious Cycle at the Root
    01
  2. Core Concepts
    02
  3. Instruction Architecture
    03
  4. How to Split
    04
  5. Mapping to Claude Code Primitives
    05
  6. Trace It: The 600-Line File
    06
view

Practice project: Project 02. Agent-readable workspace

Lecture 04. Split Instructions Across Files

Illustrative composite. A three-person team at a logistics startup kept everything their coding agent needed to know about the codebase in one file that grew every time something broke: 300 lines after the first month, 450 after the second, 600 after the third. A new hire's routine bug-fix session in month four read the whole thing, silently skipped a database-safety rule sitting past line 300, and shipped a query built by string concatenation. Tracing the break and reverting it cost the team most of an afternoon — the second time that quarter a buried rule had gone unread.

That single growing file is what harness engineering calls AGENTS.md. Packing in every rule, constraint, and lesson learned the moment you think of it feels responsible enough — it is also exactly how a 600-line file happens, and why the agent's performance quietly gets worse: on a simple bug fix it burns through context processing irrelevant deployment instructions, a critical security constraint buried at line 300 gets ignored outright, and three contradictory code style rules mean it picks one at random each time.

This is the "giant instruction file" trap. Everything seems useful, so you cram it all in, and finding one specific rule means rifling through the entire file. You wrote 600 lines, but only a third of it is relevant to the task at hand.

The Vicious Cycle at the Root

The most common vicious cycle goes like this: the agent makes a mistake, you say "add a rule to prevent this," you add it to AGENTS.md, and it works, temporarily. Then the agent makes a different mistake, so you add another rule. Repeat until the file bloats out of control.

This is a perfectly natural reaction. "Add a rule" every time something goes wrong feels reasonable. But the cumulative effect is disastrous. Let's look at exactly what goes wrong.

Context budget gets eaten alive. The agent's context window is finite. Say your agent has a 200K token window (Claude's standard). A bloated instruction file might consume 10-20K tokens. Seems like there's still plenty of headroom? But a complex task might need to read dozens of source files, tool execution output also takes up context, and conversation history keeps accumulating. By the time the agent actually needs to understand the code, the budget is already exhausted.

Lost in the middle. The "Lost in the Middle" paper (Liu et al., 2023) clearly demonstrated that LLMs use information in the middle of long texts significantly less effectively than at the beginning or end. Your AGENTS.md is 600 lines long, and line 300 says "all database queries must use parameterized queries." That's a security hard constraint. But it's buried in the middle, and the agent will almost certainly ignore it.

Priority conflicts. The file mixes non-negotiable hard constraints ("never use eval()"), important design guidelines ("prefer functional style"), and a specific historical lesson ("fixed a WebSocket memory leak last week, watch for similar patterns"). These three rules have completely different importance levels, but in the file they all look identical. The agent has no reliable signal to distinguish which is a red line and which is merely a suggestion.

Maintenance decay. Large files are inherently hard to maintain. Outdated instructions rarely get deleted, because the consequences of deletion are uncertain ("maybe something else depends on this rule?"), but adding new instructions feels cost-free. The result: the file only grows, never shrinks, and the signal-to-noise ratio steadily declines. This is the same problem as technical debt accumulation in software.

Contradiction accumulation. Instructions added at different times start contradicting each other, one says "use TypeScript strict mode," another says "some legacy files are allowed to use any." The agent picks one at random each time.

Core Concepts

  • Instruction Bloat: When an instruction file starts occupying a double-digit share of the context window, it crowds out budget for code reading and task reasoning.
  • Lost in the Middle: Information in the middle of long texts is easily overlooked. Liu et al.'s 2023 research showed that LLMs use information in the middle of long texts significantly less effectively than information at the beginning or end. A critical constraint buried at line 300 of a 600-line file has a very high probability of being ignored.
  • Instruction Signal-to-Noise Ratio (SNR): The proportion of instructions in a file that are relevant to the current task. Being forced to read 50 lines of deployment instructions during a bug fix: that's low SNR.
  • Entry File: A short entry file whose purpose is to guide the agent toward more detailed documentation, rather than containing everything itself. 50-200 lines is sufficient.
  • Reveal on Demand: Give overview information first, detailed information when needed. Good harness design is like good UI design, don't dump all options on the user at once.
  • Can't Tell What Matters: When all instructions appear in the same format and location, the agent cannot distinguish non-negotiable hard constraints from suggestive soft guidelines.

Illustrative composite. A 600-line AGENTS.md can easily run to 10,000-20,000 tokens — enough to noticeably eat into a 128K window before the agent has read a single source file.

Instruction Architecture

diagram
drawing
diagram
drawing

How to Split

The placement rule: put an instruction in the entry file only when every session needs it regardless of task type; otherwise it belongs in a topic doc, a skill, or the code itself. The condition is observable per instruction: would a bug-fix session, a deploy session, and a docs-only session all need this to succeed? Yes means entry file. No means it loads on demand instead.

Instruction typeNeeded by every session?Destination
Hard constraint (all endpoints require auth)YesEntry file, top or bottom
First-run and verification commandsYesEntry file
API design conventionsOnly when touching that APITopic doc, loaded on demand
A one-off historical bug-fix noteRarely, and prose can't enforce it anywayA regression test, or delete it
A pattern the agent should notice unprompted while reading matching codeOnly when that kind of code is in playA Skill — description always visible, body loads on match

The entry file AGENTS.md stays at 50-200 lines, containing only the most essential items: a project overview (one or two sentences that make it clear what this is), first-run commands (make setup && make test), global hard constraints (no more than 15 non-negotiable rules), and links to topic documents (one-line description plus applicability condition).

markdown
# AGENTS.md

## Project Overview

Python 3.11 FastAPI backend, PostgreSQL 15 database.

## Quick Start

- Install: `make setup`
- Test: `make test`
- Full verification: `make check`

## Hard Constraints

- All APIs must use OAuth 2.0 authentication
- All database queries must use SQLAlchemy 2.0 syntax
- All PRs must pass pytest + mypy --strict + ruff check

## Topic Docs

- API Design Patterns (`docs/api-patterns.md`) — Required reading when adding endpoints
- Database Rules (`docs/database-rules.md`) — Required when modifying database operations
- Testing Standards (`docs/testing-standards.md`) — Reference when writing tests

Each topic document is 50-150 lines, organized by subject in the docs/ directory or next to the corresponding module. The agent only reads them when needed. Think of it like packing cubes for your luggage, underwear in one cube, toiletries in another, chargers in a third. Finding what you need doesn't require emptying the entire bag.

Some information is better placed directly in the code, type definitions, interface comments, explanations in config files. The agent naturally sees these when reading code, so there's no need to duplicate them in instructions.

Every instruction should document its source ("why was this rule added?"), applicability condition ("when is this rule needed?"), and expiry condition ("under what circumstances can this rule be removed?"). Audit regularly and delete outdated, redundant, or contradictory entries. Manage your instructions the way you manage code dependencies, unused dependencies should be removed, otherwise they only slow the system down.

If an instruction absolutely must be in the entry file, put it at the top or bottom, never in the middle. The "lost in the middle" effect tells us that LLMs use information at the extremes of a long text significantly better than in the center. But the better approach is to move instructions into topic documents for on-demand loading.

Both OpenAI and Anthropic implicitly endorse this split approach. OpenAI says entry files should be "short and routing-oriented," while Anthropic says control information for long-running agents should be "concise and high-priority." Both are saying the same thing: don't stuff everything into a single file.

Mapping to Claude Code Primitives

If you work in Claude Code, the split maps onto concrete primitives:

  • The entry file is CLAUDE.md, same router role, same 50-200 line budget.
  • Topic documents can be plain linked files (docs/*.md), but a link has a weakness: the agent must remember to open it when the topic comes up. Nothing enforces the routing decision.
  • Skills are the sharper realization of reveal-on-demand. A skill's one-line description is always visible to the agent, but its full body loads only when invoked. The routing decision, "is this topic relevant now?", happens by matching the description, not by relying on the agent's memory to follow a link. The description is the always-loaded index entry; the body is the on-demand payload.
  • Scoped rule files (.claude/rules/*.md or per-directory CLAUDE.md) put area-specific rules where they apply, so they load with the code they govern, the "knowledge next to code" principle from Lecture 03 applied to instructions.

Trace It: The 600-Line File

A team's AGENTS.md grew from 50 lines to 600, tech stack versions, coding standards, historical bug-fix notes, API guides, deployment steps, personal preferences, all mixed together. A security constraint, "all database queries must use parameterized queries," sits at line 300.

Predict before reading on: does that constraint get followed reliably? Why or why not?

Trace it against what you know so far in this lecture: the entry file is always fully loaded, so the rule is physically present in every request. But "lost in the middle" means position in a long file, not presence, determines whether the model actually attends to it. Line 300 of 600 is deep middle, exactly where attention is weakest.

The team splits the file: AGENTS.md trimmed to 80 lines (overview, run commands, ~15 hard constraints, the security rule now near the top), topic documents split out (docs/api-patterns.md, docs/database-rules.md, docs/testing-standards.md), historical notes converted to test cases or deleted.

Faded case

Skip to the open case if this is familiar. A different team's CLAUDE.md sits at a lean 90 lines, well within budget. But three of its "hard constraints" are actually deployment notes ("staging deploys go through the #deploys Slack channel"), and two are contradictory style preferences left over from two different tech leads. The file is short; the lost-in-the-middle problem this lecture spent most of its time on doesn't apply here. Something is still wrong with it.

Before reading on, decide: which of this lecture's failure modes does a short-but-mixed file still have, and what's the fix, given that moving things to the top or bottom won't help this time?

Open case

Open your own longest instruction file, CLAUDE.md, AGENTS.md, or equivalent, and count two things: the total line count, and how many entries actually are non-negotiable hard constraints as opposed to deployment notes, style preferences, historical bug-fix reminders, and everything else that has quietly accumulated. If the second number runs past roughly 15, or if you can't tell at a glance which lines are red lines and which are suggestions, you have this lecture's failure mode, whether or not the file itself has crossed 300 lines.

Key Takeaways

  • "Add a rule" is short-term pain relief and long-term poison. Before adding any rule, consider whether it belongs in a topic document instead.
  • The entry file is a router, not an encyclopedia. 50-200 lines, overview, hard constraints, and links only.
  • Use the "lost in the middle" effect: put important information at the top or bottom, and move less critical items to topic documents.
  • Manage instruction bloat the way you manage technical debt. Regular audits, and every instruction should have a source, applicability condition, and expiry condition.
  • After splitting, SNR improves and the agent spends more of its context budget on the actual task instead of processing irrelevant instructions.

Example Files

Copy-ready course examples referenced in this lecture.

AGENTS-short.md

A real router-style entry file at its natural size, start-here reading order, run/verify commands, and three hard rules; everything else lives behind the linked docs.

markdown
# AGENTS.md

## Start Here

- Read `docs/ARCHITECTURE.md`
- Read `docs/PRODUCT.md`
- Use `npm run dev` to start the app
- Use `npm run check` before marking work complete

## Hard Rules

- Do not change Electron main/preload/renderer boundaries without reading
  `docs/ARCHITECTURE.md`
- Do not mark a feature complete without verification
- Leave a clean state for the next session

anti-patterns.md

Five instruction-file anti-patterns to grep your own setup for, each one is a bloat source this lecture diagnosed.

markdown
# Instruction File Anti-Patterns

- Putting all repository knowledge into one file
- Repeating the same rule in multiple places
- Encoding obsolete rules that nobody audits
- Writing conditional instructions so specific that they rarely apply
- Embedding long tool manuals into the startup context

split-vs-monolithic.ts

Runnable simulation: builds a 200-line monolithic instruction file and the same content split into four topic files, then measures how many lines an agent must scan to find each of four specific rules under each layout.

ts
/**
 * split-vs-monolithic.ts
 *
 * Creates a monolithic instruction file (~200 lines) and then shows how
 * splitting into 4 focused files dramatically reduces the context needed
 * for any single query. Simulates an "agent" searching for a specific rule
 * and measures how many lines it must read in each approach.
 *
 * Run: npx tsx docs/lectures/lecture-04-why-one-giant-instruction-file-fails/code/split-vs-monolithic.ts
 */

// ---------------------------------------------------------------------------
// Simulated monolithic instruction file (200 lines of rules)
// ---------------------------------------------------------------------------

const monolithicInstructions: { lineNumber: number; section: string; content: string }[] = [];

// Section 1: Project Overview (lines 1-50)
for (let i = 1; i <= 50; i++) {
  monolithicInstructions.push({
    lineNumber: i,
    section: "Project Overview",
    content: i === 25 ? "This project uses React 18 with TypeScript strict mode." : `Overview detail line ${i}`,
  });
}

// Section 2: Code Style Rules (lines 51-100)
for (let i = 51; i <= 100; i++) {
  monolithicInstructions.push({
    lineNumber: i,
    section: "Code Style",
    content:
      i === 72
        ? "RULE: Always use explicit return types on exported functions."
        : i === 78
          ? "RULE: Use const assertions for immutable arrays."
          : `Style rule detail line ${i}`,
  });
}

// Section 3: Testing Standards (lines 101-150)
for (let i = 101; i <= 150; i++) {
  monolithicInstructions.push({
    lineNumber: i,
    section: "Testing",
    content:
      i === 120
        ? "RULE: Every new endpoint must have integration tests."
        : i === 135
          ? "RULE: Test files must mirror the source file structure."
          : `Testing detail line ${i}`,
  });
}

// Section 4: Deployment Rules (lines 151-200)
for (let i = 151; i <= 200; i++) {
  monolithicInstructions.push({
    lineNumber: i,
    section: "Deployment",
    content:
      i === 175
        ? "RULE: Never deploy on Fridays. Deploy window is Tue-Thu 10am-3pm."
        : `Deployment detail line ${i}`,
  });
}

// ---------------------------------------------------------------------------
// Split instruction files (4 focused files)
// ---------------------------------------------------------------------------

const splitInstructions: Record<string, { lineNumber: number; section: string; content: string }[]> = {
  "01-project-overview.md": monolithicInstructions.filter((l) => l.section === "Project Overview"),
  "02-code-style.md": monolithicInstructions.filter((l) => l.section === "Code Style"),
  "03-testing.md": monolithicInstructions.filter((l) => l.section === "Testing"),
  "04-deployment.md": monolithicInstructions.filter((l) => l.section === "Deployment"),
};

// ---------------------------------------------------------------------------
// Simulated queries -- the agent needs to find specific rules
// ---------------------------------------------------------------------------

interface Query {
  description: string;
  targetRule: string;
  relevantSection: string;
}

const queries: Query[] = [
  {
    description: "Find the rule about return types",
    targetRule: "explicit return types",
    relevantSection: "Code Style",
  },
  {
    description: "Find the deployment window rule",
    targetRule: "deploy on Fridays",
    relevantSection: "Deployment",
  },
  {
    description: "Find the integration test rule",
    targetRule: "integration tests",
    relevantSection: "Testing",
  },
  {
    description: "Find the test file structure rule",
    targetRule: "mirror the source file",
    relevantSection: "Testing",
  },
];

// ---------------------------------------------------------------------------
// Search simulation
// ---------------------------------------------------------------------------

function searchMonolithic(query: Query): { linesRead: number; found: boolean } {
  // Agent must scan from the top, reading each line until it finds the rule.
  // In the worst case it reads all lines.
  let linesRead = 0;
  let found = false;

// … trimmed for the lecture — the pattern continues in the same shape

What You Have Now

Your instruction set split into a root contract plus scoped rule files.

Take your current instruction file, keep only the always-true contract at the root, and move everything area-specific into scoped files that load where they apply. If a rule survived the split without a clear owner, it was probably noise, delete it.

Further Reading

Exercises

  1. SNR Audit: Take your current entry instruction file and list all instruction entries. Pick 5 different common task types and mark whether each instruction is relevant to that task. Calculate the SNR for each task type. Instructions that are noise for most tasks should be moved to topic documents.

  2. Reveal on Demand Refactor: If you have an instruction file over 300 lines, split it into: (a) an entry file under 100 lines, (b) 3-5 topic documents. Run the same set of tasks (at least 5) before and after refactoring, and compare success rates.

  3. Lost in the Middle Verification: In a long instruction file, place a critical constraint at the top, middle, and bottom respectively, running the same task set each time (at least 5 runs per position). See if there's a difference in compliance rate. You might be surprised by how strong the position effect is.

Check your understanding


Reading is free — your progress isn't being saved

Nothing you did on this page is recorded. Paid students get saved progress and verified completions, recorded quiz answers, the spaced-repetition review queue, labs, and a certificate for each course they finish.

30-day money-back guarantee. One-time payment — lifetime access and updates.