AI Skill Certs
Claude Code Configuration & Workflows·Task 3.3·Bloom: apply·Difficulty 3/5·9 min read·Updated 2026-06-07

Designing Path Specific Rule Sets in Claude Code

Apply path-specific rules for conditional convention loading

SUBy Solomon UdohReviewed by Solomon UdohAI-assisted · human-reviewed
In short
Designing path-specific rule sets is the skill of writing .claude/rules/ files whose paths globs match exactly the files each convention should govern, no more and no less. A good rule set pairs a precise glob with focused instructions, so test, API, and infrastructure conventions each load for their own files and stay out of unrelated work.

What good path specific rule sets look like

Designing path specific rule sets is an apply-level skill: you are handed a convention and a codebase and you write the rule file that delivers that convention to exactly the right files. The output is concrete. Each rule is a markdown file in .claude/rules/, named for its topic, carrying a paths glob that selects its target files and a short body of instructions that Claude will follow when those files are in play. The craft is almost entirely in the glob. Get the pattern right and the convention lands precisely where it should; get it wrong and the rule either bleeds into unrelated code or quietly misses the files it was meant to govern.

Good rule sets share three habits. They keep one convention per file, so testing.md, api-design.md, and infra.md stay independently readable and reviewable. They write the narrowest glob that still covers every intended file, balancing reach against noise. And they quote every pattern, because the paths value is YAML and an unquoted glob beginning with * or a brace is invalid and silently fails to parse. With those habits in place, building a new rule becomes a small, repeatable task rather than a guessing game.

Path-specific rule set
A collection of .claude/rules/ files, each scoping one convention to its target files with a quoted paths glob. Designing one well means choosing a pattern that matches all the intended files and no unintended ones, then writing focused instructions that apply when those files are read.

Three workhorse patterns: tests, APIs, infrastructure

Most projects need the same handful of scoped conventions, and learning their canonical globs covers the majority of real cases. Start with test conventions. Test files are scattered beside the code they cover, so the glob is recursive and keyed to the naming scheme:

---
paths:
  - "**/*.{test,spec}.{ts,tsx}"
---

# Testing conventions
- One behaviour per test; name tests after the behaviour, not the method
- Avoid mocks where a real fixture is cheap to construct
- Cover the logged-out and error paths, not just the happy path

Next, API standards. API handlers usually live under a recognisable directory segment, so match on that segment rather than on extension alone:

---
paths:
  - "**/routers/**"
  - "**/api/**/*.ts"
---

# API conventions
- Validate every request body before use
- Return the standard error envelope on failure
- Document each endpoint with an OpenAPI comment block

Finally, infrastructure config, which tends to sit in a dedicated tree and span a couple of tools:

---
paths:
  - "terraform/**/*"
  - "pulumi/**/*"
---

# Infrastructure conventions
- Tag every resource with owner and cost-center
- Pin provider versions; never float to latest
- Keep state remote; commit no local state files

Notice the use of brace expansion in the test pattern. "**/*.{test,spec}.{ts,tsx}" matches .test.ts, .test.tsx, .spec.ts, and .spec.tsx in a single line, and a pattern like "{src,lib}/**/*.ts" matches the same shape under two roots. Brace expansion keeps a rule set compact when one convention legitimately covers related file types or sibling directories.

Calibrating the glob: too broad vs too narrow

The single most common design error is a miscalibrated glob, and it fails in two opposite directions. A too-broad glob drags the rule into work it has no business touching. Writing "**/*" for an API rule means the validation and error-envelope instructions load whenever Claude reads any file at all, reintroducing exactly the context noise that path scoping exists to remove. A too-narrow glob lets target files slip through. Writing "*.test.ts" without the leading **/ matches only test files in the project root, so the dozens of tests nested beside their components never trigger the rule, and the convention silently fails to apply where it matters most.

The calibration discipline is to picture the exact set of files the convention should govern, then write the narrowest pattern that still covers all of them. Recursive coverage almost always needs a leading **/. Type-specific conventions key off the extension; location-specific ones key off a directory segment; conventions spanning a few related types use brace expansion. When in doubt, err slightly toward the pattern that matches the intended set precisely rather than one that over-reaches, since an over-broad rule quietly degrades every unrelated session.

**/
leading recursion for repo-wide matches
{a,b}
brace expansion for related types
1 topic
one convention per rule file
Three rule files, three matched file sets
Loading diagram...
A precise glob maps each rule to exactly its target file set, keeping conventions independent and scoped.

Worked example

A full-stack TypeScript repo needs three scoped conventions: testing rules for all tests (named *.test.ts and *.test.tsx, nested throughout the tree), API rules for handlers under any routers/ directory, and infrastructure rules for files under infra/. A teammate's first draft uses paths: '*.test.ts' for tests, paths: '**/*' for the API rule, and paths: 'infra/main.tf' for infrastructure. Fix and finalise the rule set.

Work through each glob against the file set it must cover. The test glob "*.test.ts" is too narrow on two counts: it omits the leading **/, so it only matches the project root, and it ignores .tsx. The tests live nested beside components and come in both extensions, so the pattern misses almost all of them. Replace it with "**/*.test.{ts,tsx}", which recurses into every directory and uses brace expansion to catch both extensions in one line.

The API glob "**/*" is the opposite failure. It matches every file in the repo, so the API conventions would load while Claude edits CSS, tests, or Terraform, polluting unrelated sessions. The handlers are identifiable by their directory segment, so scope to that: "**/routers/**". Now the rule loads only when Claude reads something inside a routers/ directory, which is exactly the intended set.

The infrastructure glob "infra/main.tf" is too narrow in a third way: it pins a single file. Any other file under infra/, a module, a variables file, a nested stack, escapes the convention. Broaden it to the whole tree with "infra/**/*", so every infrastructure file is covered.

The finished rule set is three files, each with a calibrated, quoted glob: testing.md with "**/*.test.{ts,tsx}", api-design.md with "**/routers/**", and infra.md with "infra/**/*". Each convention now reaches all of its target files and none of anyone else's, which is the whole objective of designing a rule set: precise coverage with no spillover. The judgement you applied at every step was the same, picture the exact files, then write the narrowest glob that covers them.

Common design mistakes to avoid

These two slips are responsible for most rules that "look right" but behave wrong in practice.

Misconception

Using paths: '**/*' for a rule is a safe default, because it guarantees the rule is always available when needed.

What's actually true

A **/* glob matches every file, so the rule loads in every session and reintroduces the context noise path scoping is meant to remove. That is over-reach, not safety. Scope the glob to the files the convention actually governs, by extension, directory, or brace-expanded type set.

Misconception

A pattern like *.test.ts will match all my test files because tests always end in .test.ts.

What's actually true

Without a leading **/, the pattern matches only test files in the project root, so nested tests never trigger the rule. Recursive coverage needs **/, and matching multiple extensions needs brace expansion, for example '**/*.test.{ts,tsx}'.

A glob is a contract with your file layout

It is worth recognising that every glob you write encodes an assumption about how the project is organised. A pattern like "**/routers/**" quietly asserts that API handlers live in directories named routers; "infra/**/*" asserts that all infrastructure sits under a top-level infra/ folder. Those assumptions are usually true the day you write the rule, which is exactly why a too-clever glob can fail later: rename routers to endpoints, or move infrastructure under platform/infra, and the rule keeps parsing happily while silently matching nothing. The glob did not break in any visible way; the layout moved out from under it.

This is the deeper reason to prefer the narrowest pattern that covers the intended files rather than the cleverest one. A glob keyed to a stable, intentional convention, a test-file suffix the team will not casually change, a directory segment that is part of the architecture, ages well. A glob that depends on an incidental folder name is fragile. When you design a rule set, treat each pattern as a small contract: write it against the conventions you actually intend to keep, and when you do reorganise the tree, add "update the affected globs" to the same change. A rule that no longer matches is not a loud failure, so the discipline of keeping globs in step with the layout is what stops a carefully designed set from quietly decaying into rules that never fire.

Naming and organising the rule files

The glob gets the attention, but the file around it matters too, because a rule set is only as maintainable as it is navigable. Keep one convention per file and give each a descriptive name that announces its topic, testing.md, api-design.md, infra.md, so a reviewer can tell what a rule governs without opening it. Claude discovers every .md file under .claude/rules/ recursively, which means you can nest a larger rule set into subfolders such as frontend/ and backend/ and still have all of it found. That structure pays off as the set grows: a flat directory of thirty rule files is harder to reason about than the same rules grouped by area.

Be deliberate, too, about where a rule lives. A convention the whole team should follow belongs in the project's .claude/rules/, committed to version control so everyone and every CI run gets it. A purely personal preference, your own commit-message habit, say, belongs in ~/.claude/rules/ instead, where it applies across your projects without imposing itself on teammates. Designing a rule set is therefore not only writing globs; it is placing each rule at the scope whose audience matches the convention.

When a rule is the wrong tool: hooks and skills

Part of designing a rule set well is recognising the conventions that should not be a rule at all. A rule is context-loading: when its glob matches, Claude is given instructions to follow as it works. It is not an event trigger and it cannot guarantee timing. So if a requirement has to fire at a specific execution point, before every commit, after each file edit, on session start, a rule is the wrong mechanism and a hook is the right one, because a hook runs as a deterministic script wired to that lifecycle event regardless of what the model decides. "Validate before commit" is a hook; "API handlers should validate input" is a rule.

There is a neighbouring distinction worth keeping straight, because skills also accept a paths field and can look like rules. A skill loads under skill-activation behaviour, with its name and description visible up front and its body pulled in only when the task is relevant, and it is built for task-specific procedures rather than always-on project memory. So the same instinct that separates a standing convention from a workflow separates a path-scoped rule from a path-aware skill: reach for a rule when Claude should apply a convention automatically while editing matching files, and for a skill when you are packaging a procedure to invoke. Designing a rule set, then, includes the negative judgement of routing the would-be rules that are really hooks or skills to where they belong.

A checklist before you commit a rule

It is worth running a quick mental pass over any new rule before you commit it, because the failure modes are consistent. First, is every pattern quoted, so the YAML parses at all? Second, does each glob recurse with a leading **/ where the target files are nested? Third, is the pattern scoped tightly enough that it will not load during unrelated work, and broadly enough that it covers every intended file? Fourth, does the file cover a single topic, or has it quietly grown into two conventions that should be split? Fifth, for anything that must hold at file-creation time, have you considered dropping the paths field to make it unconditional, since scoped rules trigger on reads rather than on new-file creation? Run those checks and most of the way a rule set goes wrong is closed off before it ships. After committing, open a representative file and use /memory to confirm the rule actually loads, which converts the whole design from hopeful to verified.

How this shows up on the exam

Assessed at the apply level, this knowledge point gives you a convention and asks you to produce or critique a glob, or it shows a rule that is not behaving as intended and asks you to fix the pattern. The recurring discriminators are calibration and syntax: whether the glob recurses with **/ so it reaches nested files, whether it is scoped tightly enough not to load for unrelated work, whether brace expansion is used to cover related types compactly, and whether the pattern is quoted so the YAML parses at all. A confident answer does not just recognise a good glob; it can name why a draft is too broad or too narrow and rewrite it to match exactly the intended file set.

Check your understanding

You are writing a Claude Code rule that must apply React component conventions to every component file, which are named with .tsx and live nested throughout src/. Which paths frontmatter is the best-calibrated choice?

People also ask

What glob pattern matches all test files in Claude Code?
Use a recursive glob keyed to your naming scheme, such as "**/*.test.tsx" for React tests, or "**/*.{test,spec}.ts" to catch both .test.ts and .spec.ts. The leading **/ makes it match in every directory, and the pattern must be quoted because YAML reserves * and the brace.
Can a Claude Code rule match multiple file extensions?
Yes, with brace expansion. A single pattern like "src/**/*.{ts,tsx}" matches both .ts and .tsx, and "{src,lib}/**/*.ts" matches the same shape under two directories, keeping a rule compact when one convention covers related file types.
Why are my Claude Code glob patterns not matching?
Usually the pattern is unquoted, which is invalid YAML and fails to parse, or it is too narrow, such as omitting the leading **/ so it only matches the root. Quote every pattern and confirm the glob recurses far enough to cover all the files the convention should govern.

Watch and learn

Official Anthropic Academy lessons first, then hand-picked walkthroughs. Videos load only when you press play.

Tech With Tim

The Ultimate Claude Code Guide | MCP, Skills & More

Why watch: Covers building rules files and skills with path targeting, showing how to author glob patterns for test, API, and infrastructure files.

More videos for this concept

References & primary sources

Adaptive study

Master this concept with Archie

Practice it inside an adaptive study session. Archie, your Socratic AI tutor, tracks your mastery with Bayesian Knowledge Tracing and schedules the perfect next review.

Start studying