rules-doctor
A check-up for your CLAUDE.md / AGENTS.md rule files. It statically simulates
how Claude Code loads project rules and reports the silent failures that waste
your context window:
- Dead
@imports — an@importwritten inside a fenced code block is rendered as literal text and never expanded. Neither is one pointing at a file that doesn't exist. - Shadowed files — when
CLAUDE.mdandAGENTS.mdsit in the same directory, onlyCLAUDE.mdis loaded. YourAGENTS.mdis silently ignored. - Instruction bloat — past ~150 instruction lines, models start dropping or deprioritizing rules. rules-doctor tells you when you've crossed the line.
- v0.3 reliability lint — contradictory directives ("always X" vs "never X"), missing scope boundaries (the static proxy for scope creep), weasel phrasing models ignore mid-task ("as needed", "remember to"), and missing Architecture Decision Records in non-trivial projects.
Zero dependencies. Pure standard library.
Install
pip install rules-doctor
Usage
# Check the current project
rules-doctor
# Check another directory
rules-doctor ~/my-project
# CI mode: exit 1 if any errors (or warnings) are found
rules-doctor --fail-on error
# Compact output
rules-doctor --quiet
Example output:
rules-doctor report: /home/hao/my-project
Score: 70/100 (C)
Rule files found (2, 1 loaded):
- CLAUDE.md [project root] -- PRIMARY -- loaded by Claude Code
- AGENTS.md [project root] -- fallback -- loaded only if no CLAUDE.md nearby
Issues (2):
[ERROR] SHADOWED_AGENTS_MD -- AGENTS.md
(project root): AGENTS.md is shadowed by CLAUDE.md -- when both exist,
only CLAUDE.md is loaded and AGENTS.md is silently ignored.
Fix: Keep a single source of truth: merge the AGENTS.md rules into
CLAUDE.md (or vice versa) and delete the other file.
[WARN] DEAD_IMPORT -- CLAUDE.md
Dead @import at CLAUDE.md:42: '@rules/deploy.md' sits inside a fenced
code block, so it is rendered as literal text and never expanded.
Fix: Move the import out of the code fence onto its own line, e.g.
`@rules/deploy.md` with no surrounding backticks.
What it checks
| Check | Severity | What it means |
|---|---|---|
SHADOWED_AGENTS_MD |
error | AGENTS.md next to a CLAUDE.md is never loaded |
BROKEN_IMPORT |
error | @import points to a missing file or a directory |
IMPORT_TOO_DEEP |
error | Import chain nested deeper than 4 hops (deeper ones are dropped) |
CIRCULAR_IMPORT |
error | Import chain loops back on itself |
DEAD_IMPORT |
warning | @import inside a fenced code block — silently ignored |
IMPORT_ESCAPES_ROOT |
warning | @import with .. leaves the project |
BLOATED_FILE |
warning | More than ~150 instruction lines in one file |
BLOATED_TOTAL |
warning | All loaded rules exceed ~8000 estimated tokens |
STRAY_CLAUDE_MD / STRAY_AGENTS_MD |
warning | Nested rule file outside the project root |
CONTRADICTORY_RULES |
error | Two directives in one file say opposite things — one will be dropped mid-task |
SCOPE_BOUNDARY_MISSING |
warning | No explicit scope: the file never says which files/dirs the agent may touch |
VAGUE_DIRECTIVE |
warning | Weasel phrasing ("as needed", "remember to") models ignore mid-task |
ADR_MISSING |
warning | Non-trivial project with no Architecture Decision Records |
INLINE_IMPORT_UNCERTAIN |
info | Mid-line @mention may not expand like a directive line |
LOCAL_OVERRIDES |
info | CLAUDE.local.md personal overrides noted |
NO_RULE_FILES |
info | No rule files found at all |
Scoring: start at 100, −15 per error, −5 per warning, floor of 0. Grades: A ≥ 90, B ≥ 75, C ≥ 60, D ≥ 40, F < 40.
How it differs from cost-focused doc tools
tillmeier/claude-code-guardrails
ships a /cleanup-docs skill that audits docs by cost: measure → verify →
cut, token-greps every fact before removing text, reports in bytes. That tells
you how expensive your rules are.
rules-doctor checks quality: whether the rules are worth loading at all. A cheap rule file that contradicts itself, never declares a scope boundary, or leans on weasel phrasing will still fail you mid-task — it just fails cheaply. The two are complementary: run rules-doctor first to make your rules trustworthy, then a cost audit to make them cheap.
Honest limitations
This tool is a static heuristic simulation, not the Claude Code loader. Anthropic does not publish the exact rule-loading algorithm, and it changes between versions. Concretely, this means:
- The shadowing model is inferred from observed behavior (e.g. reports
that Claude Code ignores
AGENTS.mdwhenCLAUDE.mdexists), not from official documentation. If Anthropic changes precedence, reports can be wrong in either direction — false alarms or missed shadows. @importsemantics are approximated. The 4-hop nesting limit, fence handling, and inline-mention behavior are best-effort guesses. Edge cases (quoted paths, fragments like@file.md#section, symlinks) may be misclassified.- Token counts are
len(text) // 4, a rough rule of thumb for English prose. Code, URLs, and CJK text tokenize very differently. - The ~150 instruction-line limit is a heuristic, not a measured cliff. Model attention degrades gradually; your mileage varies by model version.
- Only Markdown-style rule files are understood.
.claude/project config (settings, hooks, skills) is noted but not validated. - v0.3 checks are text heuristics, not a model. Contradiction detection
matches opposite-polarity directives on overlapping topics — it can miss
subtle conflicts ("use pnpm" vs "use npm") and can misfire on quoted
examples. Scope-boundary detection looks for explicit scope language; an
unconventional-but-clear scope section may not match. ADR detection treats
5 source files (or a conventional
src/-style dir) as "non-trivial".
When a finding looks suspicious, verify against the real Claude Code
(--debug shows what was actually loaded). Bug reports with a minimal
repro are welcome — that's how the heuristics get better.
Development
pip install pytest
python -m pytest tests/ -q
License
MIT — see LICENSE.
Metadata
Release files for rules-doctor 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rules_doctor-0.3.0.tar.gz | 27.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rules_doctor-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 51.2 kB
Release files / rules_doctor-0.3.0.tar.gz
| Download URL | rules_doctor-0.3.0.tar.gz |
|---|---|
| Size | 27.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d6ee579696d6dac45a4f6dd166b9d15c2f8280bf351ce2b3f520a4fcecc14163
|
|
BLAKE2b-256 checksum How to use checksums |
135af29e0b1acaab287851d4c8ed638fb56aa4fca685e9ecf6190de3b5548e75
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / rules_doctor-0.3.0-py3-none-any.whl
| Download URL | rules_doctor-0.3.0-py3-none-any.whl |
|---|---|
| Size | 24.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5389e7eb7408688abb423beaf6af48fab150cd79c7670eeb9e93117d14ce6acf
|
|
BLAKE2b-256 checksum How to use checksums |
78177d6b68d6d1701f901a8fb46f32be80cce30dfce0e17b1755dbb9a02b5532
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|