[Bug] A path-scoped rule file is never registered, while a byte-identical copy at any other path loads

Status Fixed / completed
Reported on v2.1.267
Maintainer reply None cached
Activity 1 comment · opened Sep 10, 2026 · closed Sep 20, 2026

Summary

One path-scoped rule file is never registered. Reading a file its paths: globs match loads nothing from it, while four sibling rule files in the same directory load normally. A byte-identical copy of the same file at any other path loads correctly, so the content, the frontmatter, and the globs are all fine. The only discriminator I could find is the exact path, and I could not determine what property of that path causes the skip.

I could not reduce this to a fresh repo, so I am reporting the bisection instead of a minimal repro. Everything below was run against the real case.

Environment

  • Claude Code 2.1.267
  • macOS 26.6.2 (darwin 25.6.0), arm64
  • Node v22.23.1
  • Project rules live in .claude/rules/house/*.md, five files, each with a paths: frontmatter list

Expected

Reading a file matched by a rule's paths: glob loads that rule.

Observed

.claude/rules/house/github.md declares:

---
paths:
  - .github/**
  - .githooks/**
  - .env.example
---

All three match tracked files in the repo. Reading any of them loads nothing from this rule. Its four siblings (claude-code.md, docs.md, engineering.md, testing.md) load normally on their own globs.

How it was observed

An InstructionsLoaded hook appends one JSON line per load event (file_path, load_reason, session_id, timestamp). The log carries zero events for this file across every session in it, spanning several days, while recording loads for all four siblings.

Bisection

I copied the file verbatim and read a matching file after each step, checking the log each time.

| Path | Content | Loads |
|---|---|---|
| .claude/rules/house/github.md | original | no |
| .claude/rules/house/github2.md | byte-identical copy | yes |
| .claude/rules/probe/github.md | byte-identical copy, same basename | yes |
| .claude/rules/zz-probe4.md | byte-identical copy | yes |

So it is not the content, not the frontmatter, not the basename, and not the directory.

A throwaway rule file carrying only .github/** also loaded on the same read that the original ignored, so the glob itself matches. ** does cross directory boundaries here: .claude/** reaches a file two directories down.

New rule files are picked up mid-session, so this is not a session-start scan artifact.

Ruled out

  • Frontmatter encoding. Byte-clean, verified with sed -n l: no BOM, no CRLF, no tabs. Structurally identical to the siblings that work.
  • Extended attributes. xattr -l returns com.apple.provenance and nothing else, matching all four siblings.
  • Git state. Tracked, and git check-ignore exits 1 for it.
  • Settings. Nothing at user or project scope excludes it. No rule-exclusion setting is present in either file.
  • Stale file cache. Rebuilding the file with a fresh inode and mtime (copy out, delete, copy back, content unchanged) changes nothing.
  • Competition between rules. With every probe removed, reading a .github/** file that had never been opened before still loaded nothing from it. No other rule matched that read.
  • A dedupe on already-loaded content. The failure predates every copy I made; the log shows zero events for it going back through the whole file.

Impact

The rule is advisory text that no session has ever loaded, and nothing surfaces that. A rule whose glob never matches and a rule that is silently skipped look identical from inside a session, which is why this went unnoticed for days. /context not listing path-scoped rules after they load mid-session (#93094) makes it harder to spot from the other direction too.

Happy to run any diagnostic that would help narrow it.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗