[FEATURE] Path-scoped rules and skills have no exclude field, so node_modules matches every extension glob

Status Open
Reported on v2.1.267
Maintainer reply None cached
Activity 0 comments · opened Sep 10, 2026

Preflight Checklist

  • [x] I have searched existing requests and this feature hasn't been requested yet
  • [x] This is a single feature request (not multiple features)

Problem Statement

paths: frontmatter accepts glob patterns and nothing else. There is no exclude
field and no negation pattern. The documented syntax covers brace expansion,
bracket expressions and the expansion budget, and describes no way to say "these
files, except those".

The consequence is that a rule scoped by extension matches dependencies and
generated output.

---
paths: ["**/*.ts"]
---

That matches node_modules/**/*.d.ts. Claude reads into node_modules regularly to
check a library's types, and every one of those reads loads my house style rules
for code I will never write a line of. The same happens for dist/, build/ and
vendor/, and in my case for a gitignored directory of other people's cloned
repositories that I read for reference and never edit.

claudeMdExcludes does not cover this. It skips an entire CLAUDE.md or rules
file by absolute path, which turns the rule off everywhere. I want the rule on,
and not triggered by files it has no authority over.

Proposed Solution

An exclude: field beside paths:, taking the same glob syntax and evaluated
after paths:, so a matching exclusion means the rule does not load.

---
paths: ["**/*.ts"]
exclude: ["node_modules/", "dist/", "vendor/**"]
---

The same field on a skill's paths: frontmatter, which the skills documentation
says uses the same format as path-specific rules.

A default of excluding gitignored paths is worth considering, but I would rather
have the explicit field first. A silent default is harder to debug than a line I
wrote myself.

Alternative Solutions

Enumerate the directories I do want instead of excluding the ones I don't. That
turns "**/*.ts" into a hand-maintained list that breaks every time a top-level
directory is added, and it cannot express "everywhere except one subtree".

Negation inside paths: with a "!" prefix, gitignore style. Not documented as
supported. I would prefer a separate field anyway: order-dependent negation
inside one list reads worse than two labelled lists.

claudeMdExcludes in settings. Wrong granularity, as described above. It removes
the whole file rather than narrowing one rule's trigger.

Priority

Medium - Would be very helpful

Feature Category

Configuration and settings

Use Case Example

  1. I keep a rules file scoped to "**/*.{ts,tsx}" describing how comments are

written in my own TypeScript.

  1. Claude needs a library's type signature and reads

node_modules/@types/node/fs.d.ts.

  1. The glob matches, so my comment rules load, for a file I will never edit.

The rule is now in context for the rest of the session having taught nothing.

  1. With exclude: ["node_modules/**"] the read matches nothing and the rule

stays out until I actually work on my own code.

Additional Context

Claude Code 2.1.267.

Documented paths: syntax, which describes no exclusion mechanism:
https://code.claude.com/docs/en/memory#path-specific-rules

Related: https://github.com/anthropics/claude-code/issues/93248. If
path-scoped rules start triggering on writes as well as reads, this matters
more rather than less, because build output and generated files get written.

View original on GitHub ↗