Skip to content

Path-specific rules with applyTo

The repo-wide file has one blind spot: it treats every file in the repo the same. That’s fine until part of the repo deserves stricter handling than the rest — and shared-lib is exactly that case. It’s one repository, but the validation, auth, and audit helpers in it are imported by a dozen services, so a sloppy change there ripples outward in a way a change to a private utility never would. You want the helpers held to a tighter standard than the repo’s tests or scripts, and a single repo-wide file can’t express “be more careful here.”

Path-specific instructions are the tool for that. You write a rule that only applies to files matching a glob, and Copilot pulls it in in addition to the repo-wide file when it’s working on those files.

Path-specific rules live as *.instructions.md files under .github/instructions/ — Copilot looks there recursively, so you can organize them in subfolders. Each file carries frontmatter, and the load-bearing field is applyTo:

---
applyTo: "src/helpers/**/*.ts"
description: "Stricter rules for the shared helpers consumed by 12 services"
---
These files are imported by ~12 downstream services. Treat every change as
potentially breaking.
- Never change an exported function's signature or return type without flagging
it explicitly in your summary — it is a breaking change for consumers.
- Add new behavior behind new exports; prefer additive changes over edits to
existing exports.
- Every audit event goes through the existing event-type union — extend the
union, don't pass free-form strings.
- Validation rules are pure and side-effect free. Keep them that way.

The fields:

  • applyTo (required) — a glob, relative to the workspace root, that decides which files this rule attaches to. "src/helpers/**/*.ts" scopes it to the helper tree and nothing else.
  • name and description (optional) — labels that describe what the rule is for.

By default Copilot reads .github/instructions/; if your team keeps these somewhere else, chat.instructionsFilesLocations points it at additional locations.

This is the part to internalize: when Copilot edits a file that matches your glob, the path-specific rule combines with the repo-wide copilot-instructions.md (or your AGENTS.md / CLAUDE.md) — it doesn’t override it. So for a file under src/helpers/, Copilot has both the repo’s general conventions and the stricter helper rules in context at once. The repo-wide file says “this is how we write code here”; the path-specific file adds “and in this directory, be extra careful about breaking consumers.” Layered, not either-or.

That’s why this maps so cleanly onto shared-lib. The general conventions apply everywhere; the high-blast-radius helpers get an extra ring of rules wrapped around exactly the paths that ripple.

For the two repos in this course, a clean division falls out:

  • orders-service — mostly a repo-wide file is enough; it’s your squad’s app and the stakes are even across it.
  • shared-lib — a repo-wide file for the general conventions, plus a path-specific file over the helper directory that encodes the “twelve consumers, treat every change as breaking” discipline.

That difference in how tightly you scope rules mirrors the difference in blast radius you learned to read in the modes chapter. Same instinct, expressed in files instead of mode choices.

Now: rules can come from more than one place at once — your machine, the repo, your organization. When they disagree, something has to win. How rules layer — personal, repo, organization.