Claude Rules vs CLAUDE.md: Pattern-Scoped Conventions Your Team Is Missing
I Missed This for Months
I have written about progressive disclosure for agent instructions before. Root CLAUDE.md for universal rules, task-specific skills loaded on demand, local overrides when a folder has unique constraints. That system works well.
What I missed entirely was .claude/rules/.
I found it while reading through the Claude Code memory documentation. It solves a real problem that CLAUDE.md files alone cannot solve, and it has been available since early 2026. The HumanLayer article on writing a good CLAUDE.md (published November 2025) does not mention it because rules shipped after that article was written.
This post covers what .claude/rules/ does, why it matters for monorepos, and how we adopted it alongside our existing CLAUDE.md files without replacing anything.
The Mental Model: Directory-Scoped vs. Pattern-Scoped
CLAUDE.md is directory-scoped. It loads when Claude works in that directory. You put a CLAUDE.md in apps/api/ and it activates when Claude reads or edits files there.
.claude/rules/ is pattern-scoped. Each rule file can include YAML frontmatter with glob patterns, and the rule loads when Claude touches files matching those patterns, regardless of which directory those files live in.
This distinction matters when your conventions follow file types, not directories.
Consider test files. In most modern projects, test files are co-located with source files throughout the entire tree. If you want Claude to follow specific testing conventions (naming patterns, assertion styles, mock strategies), you have two options with CLAUDE.md alone:
- Put the testing conventions in the root
CLAUDE.md, where they burn context on every session whether Claude is writing tests or not. - Duplicate the testing conventions into every subdirectory
CLAUDE.mdthat contains test files.
Neither scales. A glob-scoped rule like **/*.spec.ts fires exactly when Claude is working on test files. No duplication. No wasted context.
The same applies to any cross-cutting file type: database migrations, config files, API route definitions, component files that live across multiple apps in a monorepo.
Where CLAUDE.md Still Wins
CLAUDE.md is the right tool for:
- App-level architecture context. "This app uses NestJS with a modular service layer. The API gateway lives in
apps/api/." That context matters for every file in the directory, not just specific file types. - Orchestration instructions. "Run
nx affected:testbefore committing. Use the self-review-checklist skill before creating PRs." These are session-level directives. - Which skills to use and when. Skills are loaded on demand, but Claude needs to know they exist.
CLAUDE.mdis where you list them. - Build commands, environment setup, deployment notes. Universal context that applies regardless of what files Claude is editing.
If the instruction applies to everything in a directory or everything in the project, CLAUDE.md is still the correct place.
Where Rules Win
Rules shine for file-type conventions that span multiple directories:
- NestJS controller patterns that apply to every
*.controller.tsacross 5 apps - React component conventions that apply to every
*.tsxin bothapps/andlibs/ - Schema naming rules that apply to
*.schema.tsand**/migrations/**files - Route definition contracts that apply only to files in a specific library path
The key property: rules with paths frontmatter only load into context when Claude reads a matching file. If Claude never opens a controller file in a session, the controller rules never enter the context window. This keeps token costs low and instruction relevance high.
Rules without paths frontmatter load unconditionally at startup, same priority as .claude/CLAUDE.md. Use those sparingly for conventions that genuinely apply everywhere.
How the Rules Format Works
Each rule is a markdown file in .claude/rules/ with optional YAML frontmatter:
---
paths:
- "**/*.service.ts"
---
# Backend Service Rules
- Never call external services inside a transaction.
- Use the request-scoped auth context for permission checks.
- Repository methods return domain types, not ORM entities.
That is the entire format. YAML frontmatter with a paths array, then markdown body with your conventions.
Glob patterns support standard syntax:
| Pattern | Matches |
|---|---|
**/*.ts | All TypeScript files in any directory |
apps/*/src/**/*.tsx | React components across all apps |
**/migrations/** | Migration files anywhere in the tree |
libs/routes/**/*.routes.ts | Route files in a specific library |
You can specify multiple patterns per rule, and brace expansion works:
---
paths:
- "**/*.schema.ts"
- "**/migrations/**"
---
The .claude/rules/ directory supports subdirectories and symlinks. You can organize rules into frontend/ and backend/ folders, or symlink shared rules from a central location across multiple projects.
User-level rules in ~/.claude/rules/ apply to every project on your machine. Project rules take higher priority.
Our Monorepo Migration
We run an Nx TypeScript monorepo with 5 apps and 10+ shared libraries. Before rules, we had 11 directory-scoped CLAUDE.md files and 19 agent guides loaded as skills.
The problem: conventions for NestJS controllers, React components, Drizzle schemas, and route definitions were locked behind skills that required explicit invocation or relied on Claude deciding they were relevant. When Claude edited a *.controller.ts file, the local CLAUDE.md said "read the backend authorization patterns guide." But the actual constraints were not in context until Claude manually loaded the guide. Sometimes it did. Sometimes it did not.
We created 7 glob-pattern rules in .claude/rules/:
| Rule file | Paths glob | What it covers |
|---|---|---|
backend-controllers.md | **/*.controller.ts | Route ownership, guard patterns, typed decorators |
backend-services.md | **/*.service.ts | Transaction safety, auth context, update patterns |
backend-modules.md | **/*.module.ts | DI encapsulation, provider resolution, .forRoot() rules |
drizzle-schema.md | **/*.schema.ts, **/migrations/** | Column naming, index conventions, type derivation |
react-patterns.md | apps/*/src/**/*.tsx, libs/*/src/**/*.tsx | Effect anti-patterns, API call patterns, permissions |
route-definitions.md | libs/routes/**/*.routes.ts | Naming, type sourcing, contract rules |
nextjs-pages.md | **/page.tsx, **/layout.tsx | Metadata, layout components, import aliases |
Every rule is under 250 words. Ultra-concise bullet lists with a pointer to the full skill guide for details. Total context cost when all 7 fire: ~1K tokens. In practice, a typical session only triggers 2 or 3 of them.
The important part: we kept all 11 existing CLAUDE.md files unchanged. Rules are additive. We did not have to restructure anything.
The Three-Layer System and Practical Guidance
After this migration, our instruction architecture has three layers:
- CLAUDE.md (directory context). App-level architecture, build commands, orchestration instructions, skill references. Loads when Claude works in that directory.
.claude/rules/(pattern conventions). File-type conventions that span directories. Loads only when Claude touches matching files. Deterministic, no invocation required.- Skills (task-specific workflows). Multi-step procedures, complex guides, reference documentation. Loaded on demand when invoked or when Claude determines relevance.
Sizing guidance: We target under 250 words per rule. Each rule that triggers adds to the context window, so brevity matters. If a convention needs a full page of explanation, put the details in a skill and use the rule as a concise summary with a pointer.
When to use a rule vs. a skill: If Claude should always know the convention when touching that file type, use a rule. If it is a procedure that Claude runs occasionally (like a deployment checklist or a PR review workflow), use a skill.
When to use a rule vs. CLAUDE.md: If the convention follows a directory boundary, use CLAUDE.md. If it follows a file-type pattern across directories, use a rule.
Rules without paths: Use these for conventions that genuinely apply to all files (like "never use em dashes in content" or "always use single quotes"). They load unconditionally, so keep them short.
A Note on Portability
.claude/rules/ is specific to Claude Code. Other agentic coding tools have their own rule mechanisms. Cursor has .cursor/rules, and there are similar concepts elsewhere. I do not believe these are cross-compatible enough to share via symlinks, but please reach out if you know otherwise.
If you work across multiple tools, you will likely need separate rule files for each. That is a real cost. For teams standardized on Claude Code, .claude/rules/ is a significant improvement over CLAUDE.md alone for pattern-scoped conventions.
Start Here
If you are already using CLAUDE.md files, you do not need to change anything to start using rules.
- Create
.claude/rules/in your project root. - Identify one file-type convention that currently lives in a
CLAUDE.mdor a skill (controller patterns, component rules, test conventions). - Write a rule file: YAML frontmatter with the glob, then a concise markdown body.
- Commit it. Your existing
CLAUDE.mdfiles continue working exactly as before.
The official documentation covers the full specification, including user-level rules, symlink sharing, and the claudeMdExcludes setting for large monorepos.
If you have questions or want to share your own rules setup, find me on LinkedIn.