Path-scoped rules (.claude/rules/*.md) silently dropped when matching set exceeds an undocumented size budget

Resolved 💬 2 comments Opened Jun 26, 2026 by rosskevin Closed Jun 30, 2026

Type: bug + feature request
Component: project rules / context injection (.claude/rules/ with paths: frontmatter)
Version: Claude Code 2.1.193
Platform: macOS (Darwin 25.5)

Summary

.claude/rules/*.md files with paths: frontmatter are auto-injected as <system-reminder>s for
files whose path matches the globs. There is an undocumented total-size budget on what gets
injected for a single edited file. When the set of matching rules exceeds it, the harness drops
the largest rules first, silently
— no warning, no indicator, no log. The dropped rule's
conventions then simply don't apply for that edit, and it is nearly impossible to notice.

This makes a documented, version-controlled team convention silently inert exactly when a rule
grows large enough to matter.

What I observed

  • For a single file, a ~24KB matching rule was silently not injected while a ~22KB matching

rule for the same file was — i.e. eviction is largest-first against a shared total, not per-rule.

  • The drop is invisible from inside a session: there is no surfaced list of which rules were injected

vs. dropped, so the only symptom is "the model didn't follow a rule that should have applied."

  • The budget is a total across all matching rules, including the always-on global

~/.claude/rules/*.md set. On a real monorepo, a .tsx edit already carries ~16KB of global-rule
overhead (comments, react, typescript, biome, env-vars) before any project rule loads.

Scale, on a real repo

Reproducing the matching arithmetic across our rule set (byte sizes as a proxy for the token budget):

| Edited file | Matching rules | Total size |
|---|---|---|
| apps/app/**/*.tsx | 18 | ~101KB |
| packages/ui/**/*.tsx | 17 | ~88KB |
| apps/app/src/proxy.ts | 11 | ~62KB |
| apps/api/app/models/user.rb | 6 | ~46KB |

Whatever the exact threshold, the largest several rules in these domains are being evicted on every
edit, and nothing tells the author.

Why this is hard to detect

  1. No surfaced indicator of injected-vs-dropped for the current file.
  2. Largest-first eviction punishes the most important rule — your big, carefully-written rule is

exactly the one dropped; a pile of small ones survives.

  1. The threshold is undocumented, so authors have no size target to stay under.
  2. The recursive scan defeats the obvious workaround — moving a rule into a subdirectory of

.claude/rules/ does not exempt it; it still gets scanned and injected.

Requests

  1. Document the budget. Publish the limit (size or tokens), whether it's per-file-total or

global, and the eviction order, so authors can size rules deliberately.

  1. Surface injected vs. dropped. A visible indicator or --debug/verbose output listing, for a

given edited file, which rules matched, which were injected, and which were dropped for budget.
Even a one-line N rules dropped for budget on <file> warning would make this detectable.

  1. Add a non-injecting / read-on-demand frontmatter flag. e.g. inject: false (or

mode: on-demand) to mark a rule as a linkable reference doc that is not auto-injected and does
not count against the budget. Today the only workarounds are a never-matching paths: sentinel
(e.g. - "__never-auto-inject__/**") or moving the file out of .claude/rules/ entirely — both
are hacks, and the sentinel is non-obvious to anyone reading the rule later.

Current workarounds

To keep important rules from being silently evicted we split each large rule into:

  • <name>.md — the lean "always / never" core, kept small, with its real paths: (stays injected).
  • <name>-reference.md — cheat-sheets / recipes / edge-cases, marked non-injecting via the

__never-auto-inject__ sentinel, linked from <name>.md as "read on demand."

We also wrote an author-time detector that reproduces the matching arithmetic (matching rules sorted
largest-first, running total, flagged drops) so silent drops are at least catchable in review/CI —
but this only exists because the harness surfaces nothing. A first-party version of #2 would make it
unnecessary.

Suggested acceptance

  • Docs page stating the budget, scope, and eviction order.
  • A verbose/debug surface (or a soft warning) showing injected vs. dropped rules per file.
  • A frontmatter flag to opt a rule out of injection while keeping it a linkable reference.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗