Skip to content

Instruction Layering and Scoping

Declare an instruction's timing — when it loads — and its scope — which files it applies to. The goal is separating always-on instructions from situational ones, not cutting total volume — it works because only what's relevant remains.

Problem

Instructions load in full, all the time, the moment they're written. A task as small as writing one SQL statement drags along naming conventions for an unrelated language and the release procedure besides. Irrelevant conventions surface not because the model is careless — it's because no one ever states when that instruction applies. The person who wrote it knows the context; the instruction file doesn't.

And residency isn't free. In long instruction files, instructions that were written still get overlooked. This isn't a guess — two vendors, in two separate documents, independently tie length to reduced adherence (Official, see in Practice; what each source actually names is scoped there).

So stacking everything into a single tier means adding actually subtracts. The next line you add dilutes the one already there.

Context

Applies when:

  • Instructions have grown — each addition makes it harder to tell what's written where
  • Conventions differ by file type — language, layer, or artifact each has its own rules to follow
  • Some instructions apply only to specific work — release procedures, migration steps, quirks of a particular service

Does not apply when:

  • There are only a handful of instructions — the cost of building tiers outweighs the benefit of separating them. With just a few, reading all of them works fine
  • A constraint should apply equally to every file — handling secrets, banning destructive operations. Scoping it creates a hole wherever the scope doesn't reach. Scoping only works for what's fine to scope
  • The scope can't be stated in words — "when the file matters" isn't a scope. A declaration that can't be matched against is no better than no declaration

Boundary with neighboring patterns:

Solution

The structure of instruction layering and scopingOn the left, scope isn't declared: all four instructions always load, including the three irrelevant to the current task. On the right, scope and timing are declared: only the two that match the current task load, and the two that don't stay silent. The two axes declared are a time axis — resident versus loaded on call — and a scope axis — which files it applies to.Not declared — stacked in one tierNo declaration, so all four always loadAll-file constraintSQL conventionsNaming rules for another languageRelease procedureCurrent task — write one SQL statementAll four load. Three are unrelated to this taskThe longer it gets, the more written instructions get overlookedDeclared — scope and timing statedOnly matching instructions loadAll-file constraintScope: allSQL conventionsScope: *.sqlNaming rules for another languageScope: different typeRelease procedureOn callCurrent task — write one SQL statementTwo load. The two that don't match stay silentThe freed seat goes to what's relevantSolid = loads Dashed = silent / Two axes — time axis: resident or loaded on call Scope axis: which files it applies toEffectiveness comes not from the amount cut, but from what remains being relevant

Why this works. The starting point is a single fact: instructions are context, not enforcement (Official, see in Practice). Not a setting, not a constraint — text handed to the model to read.

This is where things diverge. If it were enforcement, adding more wouldn't weaken what's already there. Text to read is different. The more there is to read, the thinner each individual piece gets read.

So an instruction file isn't a place for addition — it's a place where instructions compete for a seat. An instruction irrelevant to the current task sits in the same seat as a relevant one. Declaring a scope means freeing that seat wherever the instruction isn't needed.

The freed seat goes to whatever instruction is relevant right now. That's the whole of this pattern's effect, and it isn't a reduction in total volume — a scoped instruction still loads in full wherever its scope matches. What changes is everywhere else.

There are two axes to declare:

  • Time axis — resident, or loaded only when called
  • Scope axis — which files, which work it applies to

The two are independent. A constraint that should always apply is "resident, full scope." Conventions for a specific file type are "scoped." A procedure needed only rarely is "on call."

Cram everything into a single instruction file and these three kinds collapse into one tier. A collapsed tier has no room to record the distinction.

This design has a counterintuitive asymmetry: an instruction whose scope was never declared falls on the side of not applying (Official, see in Practice). Declaring isn't narrowing — it's activation, and the default is off.

Layering isn't an exercise in weakening instructions. It's an exercise in claiming, one at a time, where each one applies. What isn't claimed stays quietly silent.

Trade-offs

Advantages

  • Irrelevant conventions stop surfacing. Writing SQL no longer drags in naming rules for another language as justification. An instruction with a declared scope stays silent outside it.
  • What remains gets read more reliably. The official docs state that long instruction files can cause some instructions to be overlooked (Official, see in Practice; the scope of what the original text names is limited there). Reducing residency works in favor of what's left being read.

Costs

  • An instruction whose scope was never declared doesn't apply. The default falls on the side of not applying (Official, see in Practice). An instruction that's written but doesn't apply is worse off than one never written at all — the person who wrote it believes it's in effect.
  • It gets harder to tell what's actually applying. The more tiers accumulate, the less a human can say which instruction produced the current response. Adding a layer also raises the difficulty of tracing ("One Authoritative Source for Instructions").

GitHub Copilot in Practice

Copilot isn't a single product. Scope declaration exists in both VS Code and Copilot CLI, and the semantics agree. Each surface is shown with its own primary text.

VS Code — applyTo declares scope

Source: VS Code — Custom instructions (retrieved 2026-07-16). The instruction file's applyTo property is defined as follows Official:

Glob pattern that defines which files the instructions apply to automatically, relative to the workspace root. Use ** to apply to all files. If not specified, the instructions are not applied automatically, but you can still add them manually to a chat request.

A glob declares which files get automatic application. ** covers all files. And — if not specified, the instructions are not applied automatically. The asymmetry described in Solution is written here directly as a product specification. You can still add them manually, but that only works when a human remembers to, every time.

What determines application isn't just the glob Official:

The agent determines which instructions files to apply based on the file patterns specified in the applyTo property in the instructions file header or semantic matching of the instruction description to the current task.

It's decided either by the applyTo glob or by semantic matching between the instruction's description and the current task. The scope axis has two entry points: one is string matching, the other is how the description is written. Declaring scope isn't only about writing a glob — how you write the description is also a scope declaration.

The official docs recommend splitting itself Official:

For task or language-specific instructions, use multiple *.instructions.md files per topic and apply them selectively by using the applyTo property.

Instead of one big file, split by topic into multiple files and apply them selectively with applyTo — this pattern's procedure shows up as official advice in its own right.

Copilot CLI — the same semantics, on a different surface

Source: Copilot CLI — Adding custom instructions (retrieved 2026-07-16) Official:

Path-specific instructions are included only when their applyTo value matches a file that Copilot CLI is working with. An instruction file that you disable using /instructions is not included.

applyTo is included only when its value matches the file currently being worked with. The same semantics as VS Code hold on a different surface, under the same property name. Portability is confirmed right here — this pattern isn't a feature of a single surface.

The CLI has one more opening — a way for a human to look directly into the hierarchy Official:

Use the /instructions command to view the instruction files discovered for the current session and enable or disable individual files.

It lists which instruction files were discovered for the current session and lets each one be toggled individually. This surface pays back the cost of "losing track of what's applying" in the form of a listing.

Differences across surfaces

SurfaceScope declarationCan a human see which instructions currently apply?
VS CodeapplyTo glob, or semantic match between description and task. Not applying automatically without a declarationNot confirmed in this catalogue. That isn't a claim it's absent
Copilot CLIapplyTo glob. Included only when it matches the file currently being worked withListed and toggled individually via /instructions

Sources are each surface's docs above. The mechanism — "scoped instructions" — is the same, yet whether a human can see the hierarchy differs by surface, as far as this catalogue could confirm.

A sense of scale

This is territory where readers most want an answer, yet each vendor can only speak to its own numbers. Shown by range, with sourcing attached. No single number gets rounded to a universal rule.

What this section's GitHub-side Official quotes actually cover

Every GitHub quote below describes custom instructions for Copilot code review. Do not cite it as a benchmark for instruction files in general. Both the 1,000-line figure and the 10–20 instruction figure are about code review.

TargetGuidelineLabelSource
Instruction file (Copilot code review custom instructions)Cap of about 1,000 lines. Beyond that, response quality can deteriorateOfficialcustomize-code-review (retrieved 2026-07-16)
Number of instructions (Copilot code review custom instructions)Start with 10–20 specific instructionsOfficialsame as above
CLAUDE.md (Claude Code)target under 200 linesa target, not a ceilingOfficialcode.claude.com/docs/en/memory (retrieved 2026-07-16)
CLAUDE.md60–80 lines as "industry best practice"Folkloreprimary source untraceable (below)
Global tier15 lines or fewerFolkloresource unknown (same as above)
SKILL.mdBloated past 4,000 tokensFolkloresource unknown (same as above)
One real-world instanceIn one individual repository, the project CLAUDE.md was 86 lines, and of the skill bodies, only the description was resident — about 9%Measuredobservation from an individual environment (below). Not written as a general law

GitHub's original text (same source above, retrieved 2026-07-16) Official:

Begin with 10–20 specific instructions that address your most common review needs, then test whether these are influencing Copilot code review in the way you intended.

Best practice: Limit any single instruction file to a maximum of about 1,000 lines. Beyond this, the quality of responses may deteriorate.

The same page also states what length causes Official:

  • Context limits: Very long instruction files may result in some instructions being overlooked.

This is the basis for the overlooking described in Problem and Trade-offs. But as the warning above states, what the original text names is code review custom instructions, not instruction files in general.

Claude Code's original text (code.claude.com/docs/en/memory, retrieved 2026-07-16) Official:

Size: target under 200 lines per CLAUDE.md file. Longer files consume more context and reduce adherence. If your instructions are growing large, use path-scoped rules so instructions load only when Claude works with matching files.

"target under" is a target, not a ceiling. Don't read it as "stay under 200 lines." And the second half — once instructions grow large, use path-scoped rules so they load only when Claude works with matching files — is a different vendor saying the same thing applyTo says, under a different name. Scoping isn't one product's invention.

The same page also states why this works Official:

CLAUDE.md files are loaded into the context window at the start of every session, consuming tokens alongside your conversation. ... Because they're context rather than enforced configuration, how you write instructions affects how reliably Claude follows them. Specific, concise, well-structured instructions work best.

Context rather than enforced configuration — this is one of the rare places where the single fact placed at the start of Solution is written in the official docs' own words. Precisely because it isn't enforced configuration, how you write it changes how reliably it's followed.

Don't confuse the two "200"s

The same page has another 200 — the truncation threshold for the automatic memory file MEMORY.md Official:

The first 200 lines of MEMORY.md, or the first 25KB, whichever comes first, are loaded at the start of every conversation. Content beyond that threshold is not loaded at session start.

CLAUDE.md's 200 is a target (recommended); MEMORY.md's 200 is a hard cutoff. The former is still read past 200 lines (though the original text says adherence drops). The latter simply isn't read past the threshold. Same number, different meaning. Conflating them is a mistake.

Provenance of the three Folklore figures

60–80 lines, 15 lines or fewer, and 4,000 tokens circulate in the community but their primary source can't be traced.

The document carrying these numbers also stated, as fact, the owner name of a GitHub Action that doesn't exist (this catalogue confirmed the 404). It's a document with a tendency to state unverified claims as fact. Its reliability as a source is low.

Even so, the numbers aren't dropped. Dropping them would leave readers thinking "the official 200 is the only answer." The official docs state 200 lines as a target, and the community holds a stricter 60–80 line view (though its source can't be traced) — both are shown, with neither presented as the sole correct answer. Disclosing the provenance and keeping the numbers lets readers judge for themselves, more than silently discarding them would.

One real-world instance Measured

In one individual repository (audit as of 2026-07-07, Claude Code environment, n=1), the project CLAUDE.md was 86 lines, and of the skill bodies, only the description was resident — about 9% of the total. The rest loads only when called. This is an observation that the time-axis hierarchy was actually run at this ratio in one environment.

Don't draw "layering reduces tokens" from this. The ratio is visible without running a counterfactual, but "what it would have been without layering" is only visible by running without layering and counting — and no one counted. Measured can only cover what's visible without running a counterfactual.

Equivalents in other tools — two axes, two separate names

Anthropic has Official documentation for both axes of this pattern, but in separate resources. The scope axis is CLAUDE.md's path-scoped rules, above. The time axis has its own name (source: Anthropic — Agent Skills, retrieved 2026-07-16) Official:

This filesystem-based architecture enables progressive disclosure: Claude loads information in stages as needed, rather than consuming context upfront.

Loading in stages, as needed — rather than consuming context upfront. This is the time axis itself. The same page splits skill content into three kinds, stating "each loaded at a different time." The first tier's heading is "Level 1: Metadata (always loaded)" — only the metadata is resident.

This catalogue is what binds the two into a single pattern. Progressive disclosure lives in the Agent Skills docs; path-scoped rules live in the memory docs. The reason for binding them is in Solution — the two are independent axes, and either alone leaves a gap in the other's situation.

Also Known As

NameSource
Progressive disclosurePrimary — Anthropic gives this name to staged loading in the Agent Skills docs (source: in Practice section above). Names only the time axis (below)
Instruction Layering and ScopingDescriptivethis catalogue's descriptive name; no primary source uses it

Progressive disclosure isn't equated with this pattern's name. The original text says "Claude loads information in stages as needed" — when to load. This pattern includes that plus which files it applies to. The former is the time axis, the latter the scope axis — close, but not the same.

The difference shows up in practice. Staged loading achieves "don't load everything up front," but that alone can't say "this instruction applies only when handling SQL." Scope declaration (applyTo / path-scoped rules, both in Practice) is what covers that side. Using one's name for the whole makes the other invisible. So this catalogue gave a descriptive name that covers both axes.

  • Failure as Institutional Memory — what to write is that pattern; where to make it apply is this pattern. This pattern makes the memory that pattern narrowed to "write only what the model has no way of knowing" load only in the situations where that memory is needed
  • Rules Ranked by Binding Force — where an instruction applies (scope) is this pattern; how strongly it applies (binding force) is that pattern. Different axes, used together
  • Resident Context Inventory — scoping reduces what's resident as this pattern; counting and discarding is that pattern. Declaring scope is something that can be done before making a discard decision
  • Making the Verification Target Explicit — which instructions apply is this pattern; what to verify is that pattern. The same kind of scope declaration serves a different purpose
  • One Authoritative Source for Instructions — the more tiers you build, the harder it gets to tell what's applying. That pattern deals with this side effect
  • If reading just one more next: Rules Ranked by Binding Force — having scoped where instructions apply, it's next to rank them by binding force