Home / Articles

Where Claude Code Instructions Belong: CLAUDE.md, Path Rules or Hooks

Learn why Claude Code treats CLAUDE.md as context, how to trim it, scope rules by path, move must-run steps into hooks, and verify what actually loaded.

Publisher: REACTAPP.TOP8 min read1844 words

This article is published in English.

Sources: 7 CLAUDE.md Patterns That Actually Change How Claude Writes Code

Most teams using Claude Code now keep a CLAUDE.md file, and few of them can say whether it is doing anything. A common pattern is a file that has grown to several hundred lines, with the model following some instructions and quietly skipping others. The fix is rarely a better template; it is understanding what the file actually is and routing each instruction to the mechanism that can carry it. This guide covers seven practical patterns, from trimming the file to scoping rules by path, moving hard requirements into hooks and checking what Claude really loaded.

If you are starting from a blank file, the practical playbook for writing an effective CLAUDE.md covers content and structure. The focus here is different: which instructions belong in CLAUDE.md at all, and where the rest should go.

CLAUDE.md is context, not configuration

Every other problem traces back to this misconception. Claude Code injects the file into the conversation as a message; it is not merged into the system prompt, and nothing in the runtime enforces it. The model reads it and tries to honour it. There is no guarantee beyond that, and the chances shrink further when the wording is fuzzy or two instructions pull in different directions.

A useful mental model is a handover memo for a skilled teammate who skims it over morning coffee and then disappears into the actual work. What survives that process is the material that was short, specific and consistent. That makes length, precision and internal consistency the only real levers you have, not matters of style.

Keep the root file under 200 lines

The current guidance is to stay below roughly 200 lines. Beyond that, the file consumes more of the context window and adherence gets worse rather than better.

This is counterintuitive: more instructions lead to fewer instructions being followed. Each line competes for the same limited attention as every other line and as the conversation itself. Consider a team whose file had reached 340 lines. Cutting it to about 120 made Claude follow it more reliably. None of the deleted lines were wrong; they were simply noise layered over the instructions that mattered.

There is also a hard ceiling, though you will not want to design against it: according to the docs at the time of writing, files larger than 4 MiB are skipped entirely. Adherence suffers long before a file gets anywhere near that size.

Delete what Claude can discover from the repo

The most effective editing rule is simple: remove anything Claude could figure out by reading the codebase. This lines up with the kind of trims Claude Code's own /doctor checkup suggests, which remove folder layouts, lists of dependencies and high-level architecture descriptions while keeping pitfalls, rationale and conventions that deviate from tool defaults. In other words, it inverts the usual contents of these files.

Things to remove:

  • The folder structure, since Claude can list directories itself.
  • The dependency list, which package.json already records.
  • A narrative overview of the architecture, which the code expresses more accurately.

Things to keep:

  • Code that looks like a mistake but is intentional.
  • The reason the obvious approach was rejected.
  • Any convention that contradicts the framework's documentation.
  • Commands that nobody would find on their own.

A good test: if a competent engineer with the repository open could learn it within ten minutes, leave it out. If they would only find out by breaking something, write it down.

Leave notes for humans at zero token cost

Block-level HTML comments are removed before the file's content reaches Claude's context. That lets you annotate the file for the people who maintain it without spending any of the model's budget, for example to record why a section moved:

<!-- Deleted the API section — moved to .claude/rules/api.md, Sep 2026 -->

Your teammates see the history; the model never pays for it.

@imports organize the file but do not save context

When a CLAUDE.md gets long, the reflex is to split it into several documents and import them:

@docs/architecture.md
@docs/api-conventions.md
@docs/testing.md

This looks like lazy loading, but it is not. Imported files are expanded and loaded into context at launch, together with the CLAUDE.md that references them. Splitting 340 lines into four neat files still loads the same 340 lines.

Imports do have legitimate uses. They help with organization, and they let you share a single canonical set of instructions between tools. If a repository already has an AGENTS.md, a single @AGENTS.md line in CLAUDE.md avoids maintaining two diverging copies. Just do not expect them to reduce context usage. For instructions that should load only some of the time, you need path-scoped rules.

Scope conditional rules with .claude/rules and paths

Files in .claude/rules/ can declare a paths field in their frontmatter. This is the feature that delivers what people expect from imports: a glob-scoped rule stays out of context until Claude reads or edits a matching file. The frontmatter of an API rules file might look like this:

---
paths:
  - "src/api/**/*.ts"
---

Below the frontmatter, the rule body holds the conventions that apply only to that part of the tree, such as input validation, the shared error envelope and where SQL is allowed:

# API rules- Every endpoint validates input before touching the database
- Errors use the standard envelope in `src/api/errors.ts`
- No direct SQL outside `src/api/repositories/`

The effect is that frontend work stops paying the token cost of API conventions, and API work stops paying for testing conventions.

In practice, this is the cure for an overgrown CLAUDE.md. Break the content up by topic, attach each topic to the directories it governs, and reserve the root file for guidance that is universal to the project. A rules file without a paths field loads in every session, so treat that as a deliberate choice rather than the default.

Globs support brace expansion, so one rule can cover several extensions and a separate test pattern:

---
paths:
  - "src/**/*.{ts,tsx}"
  - "tests/**/*.test.ts"
---

Must-happen steps belong in hooks

Lines like "lint before every commit", "do not push directly to main" or "format each file after editing" are common in CLAUDE.md. They are honoured on most occasions, the exceptions get noticed, and teams decide the model cannot be trusted.

Yet that is the documented behaviour: CLAUDE.md influences what Claude does without guaranteeing it. For a step that has to occur at a fixed moment in the session lifecycle, a hook runs a shell command at that moment, independent of the model's judgement. A PreToolUse hook can even veto a tool call entirely, something no bold or capitalized Markdown can accomplish.

A practical way to route each kind of instruction:

  • A convention Claude should generally follow goes in CLAUDE.md.
  • A rule for one area of the codebase goes in .claude/rules/ with paths.
  • A requirement with zero tolerance for exceptions becomes a hook.
  • A repeatable multi-step procedure becomes a skill.

Moving a handful of "always" rules into hooks has a double benefit: the requirements are now actually enforced, and the file sheds lines that could never succeed, leaving more attention for the instructions that can.

Verify what actually loaded

Run /context and inspect its memory files section, which reflects exactly what the running session has loaded. /memory complements it by listing the user-level and project-level files and letting you open them. Together they turn "is Claude ignoring this?" from guesswork into something you can check. It is surprisingly easy to spend time polishing the wording of a file that is not being loaded at all.

Contradictions across concatenated files

Nothing is overridden; everything is concatenated. Starting from the working directory, Claude Code climbs toward the filesystem root and collects each CLAUDE.md along the way, then orders them from the root down. At any level that also has a CLAUDE.local.md, that file follows its sibling CLAUDE.md. In a monorepo, two files can easily give opposite guidance. When that happens Claude may simply pick one, and nothing warns you about the conflict.

Ancestor files you did not ask for

If a CLAUDE.md in a parent directory is leaking into your sessions, the claudeMdExcludes setting in your local settings skips files by glob.

What survives compaction

The project-root CLAUDE.md is re-read from disk and injected again after /compact, so its instructions persist. Anything you only said in the conversation is lost. If you keep repeating the same correction after every compaction, that is a strong signal it belongs in the file.

A starting blueprint

If you were writing the setup from scratch, a reasonable target looks like this:

  • A root CLAUDE.md under about 120 lines, containing only what is true everywhere.
  • Conditional guidance living in .claude/rules/ with path globs.
  • Each non-negotiable "always" requirement implemented as a hook.
  • Nothing that someone could learn by reading the repository for ten minutes.
  • A quick /context check after every change.

The full reference, including features such as auto memory that deserve separate treatment, is in the Claude Code memory documentation. Behaviour and limits evolve, so check it when something does not match what you see.

Key takeaways

  • Write CLAUDE.md for a colleague who reads, not for a machine that executes: short, specific and free of contradictions.
  • Shorter files are followed more reliably; cut anything the codebase already tells Claude.
  • Imports reorganize content but load all of it; path-scoped rules are what actually defer loading.
  • Anything that must happen every time needs a hook, because context can only influence behaviour.
  • Treat /context as your source of truth before tuning wording.