# How to Write a Good CLAUDE.md File (With Real Examples) > **Quick answer:** A good CLAUDE.md file stays under 200 lines, states build commands, code style, and repo conventions Claude can't infer from the code, and uses imperative language like "Use 2-space indentation" instead of vague preferences. Skip anything a linter already enforces. Run /init for a draft, then prune it whenever Claude ignores a rule or asks something the file should answer. *Published by [TryUncle](https://tryuncle.com) — the on-screen assistant that teaches DaVinci Resolve on your own screen.* *Updated 2026-07-30 · Claude Code documentation, memory and best-practices pages (July 2026) · Canonical: https://tryuncle.com/learn/claude-code/how-to-write-a-good-claude-md-file* Most people write a CLAUDE.md file once, when a project starts, and never touch it again. That's the mistake. A CLAUDE.md file is not a one-time setup step you check off. It's a document you edit the same way you'd edit code, and the projects where Claude Code performs best are the ones where somebody keeps pruning it. Inside our 100,000+ member DaVinci Resolve editing community, more editors are picking up Claude Code to write Fusion scripts and connect Resolve to MCP bridges, and a badly written CLAUDE.md is one of the first things that trips them up. This guide covers what actually goes in one, where it lives, how long it should be, and what changes if you're pointing Claude Code at a video editing project instead of a typical web app. ## What is a CLAUDE.md file, and why does Claude Code read it automatically? CLAUDE.md is a plain markdown file that Claude Code reads at the start of every session in a project, without you asking it to. It exists to hand Claude context it has no other way of getting: your build commands, your code style where it departs from a language's defaults, your testing preferences, and the quirks of your specific repo that aren't visible from reading the code alone. **A CLAUDE.md file is not documentation. It's a prompt that runs before every single message you send.** There's no required schema, no YAML frontmatter, and nothing to validate it against. Anthropic's own documentation says exactly that: there's no required format for CLAUDE.md files, but keep it short and human-readable, and shows a two-line example covering ES modules and a testing reminder as a complete, valid file. A CLAUDE.md with three good lines beats one with thirty vague ones. It's worth being precise about what "reads automatically" means, because it changes how you write the file. CLAUDE.md content is delivered as a user message after the system prompt, not baked into the system prompt itself. Claude reads it and tries to follow it, the same way it would follow an instruction you typed, but there's no hard enforcement layer behind it. If you need a rule that must apply with zero exceptions, like blocking writes to a migrations folder, that's a job for a hook, not a CLAUDE.md line. CLAUDE.md shapes behavior. Hooks and settings enforce it. ## Where should you put your CLAUDE.md file? Claude Code checks several locations, and the location determines who sees the instructions and when they load. The table below lists them from broadest scope to most specific, in the order Anthropic's docs describe them loading into context, which means a project instruction effectively gets read after a user instruction. | Scope | Location | Who it's for | Shared with | | --- | --- | --- | --- | | Managed policy | macOS: `/Library/Application Support/ClaudeCode/CLAUDE.md` · Linux/WSL: `/etc/claude-code/CLAUDE.md` · Windows: `C:\Program Files\ClaudeCode\CLAUDE.md` | Org-wide standards set by IT/DevOps | Every user on the machine, can't be excluded | | User | `~/.claude/CLAUDE.md` | Your personal preferences across all projects | Just you | | Project | `./CLAUDE.md` or `./.claude/CLAUDE.md` | Team-shared project conventions | Team members via git | | Local | `./CLAUDE.local.md` | Your personal notes for this one project | Just you, gitignored | Most people only ever need the project-level file. Put it at your repo root, check it into git, and everyone who clones the project gets the same instructions Claude follows. If you're working across a monorepo, Claude Code walks up the directory tree from wherever you launched it, so running Claude inside `packages/api/` loads `packages/api/CLAUDE.md`, the root `CLAUDE.md`, and any `CLAUDE.local.md` files alongside them, all concatenated into context rather than one overriding another. Two placement details trip people up. First, CLAUDE.md files sitting in subdirectories below your working directory aren't loaded at launch. They load on demand, the moment Claude actually reads a file in that subdirectory, which keeps a huge monorepo from front-loading every team's conventions into every session. Second, if a top-level parent CLAUDE.md belongs to a different team and just adds noise to your work, the `claudeMdExcludes` setting lets you skip specific files by path or glob pattern without asking anyone to delete them. `CLAUDE.local.md` deserves a specific warning if you use git worktrees. Because it's gitignored, a `CLAUDE.local.md` you create in one worktree doesn't exist in your other worktrees of the same repo. If you want personal preferences to follow you across worktrees, import a file from your home directory instead, with a line like `@~/.claude/my-project-instructions.md` in your project CLAUDE.md. ## What should actually go inside a CLAUDE.md file? This is where most CLAUDE.md files go wrong. People write down what they'd tell a new hire on day one, and half of that is stuff Claude already knows or can figure out by reading the code for ten seconds. The useful content is narrower than most people assume. Anthropic's own best-practices documentation lays out the split directly: | Include | Exclude | | --- | --- | | Bash commands Claude can't guess | Anything Claude can figure out by reading code | | Code style rules that differ from defaults | Standard language conventions Claude already knows | | Testing instructions and preferred test runners | Detailed API documentation (link to docs instead) | | Repository etiquette (branch naming, PR conventions) | Information that changes frequently | | Architectural decisions specific to your project | Long explanations or tutorials | | Developer environment quirks (required env vars) | File-by-file descriptions of the codebase | | Common gotchas or non-obvious behaviors | Self-evident practices like "write clean code" | Kyle, writing on the HumanLayer engineering blog, puts the underlying principle bluntly: "Less (instructions) is more. While you shouldn't omit necessary instructions, you should include as few instructions as reasonably possible in the file." His second rule is just as direct: "Claude is not a linter. Use linters and code formatters, and use other features like Hooks and Slash Commands as necessary." That second line matters more than it sounds like it should. A CLAUDE.md line that says "always use 2-space indentation" is redundant the moment your project has Prettier configured, because Prettier already enforces it deterministically. The CLAUDE.md line is advisory. The formatter is not. Spend your 200 lines on things nothing else in your toolchain already guarantees. **A CLAUDE.md file that tells Claude to write clean code is a CLAUDE.md file that tells Claude nothing.** Here's a working test for any line you're about to add: would removing it cause Claude to actually make a mistake? If the answer is no, cut it. Anthropic's own guidance phrases the test the same way, and it's the single fastest way to catch bloat before it accumulates. A rule like "Use Pest" is concrete and testable. A rule like "we generally prefer to use good testing practices" gives Claude nothing to act on differently than it would without the line at all. A short, real example, close to what Anthropic's own docs show as a complete file: ```markdown # Code style - Use ES modules (import/export), not CommonJS (require) - Destructure imports when possible (eg. import { foo } from 'bar') # Workflow - Run `npm run typecheck` after a series of code changes - Prefer running a single test file over the whole suite for speed # Gotchas - The staging API silently truncates responses over 1MB; paginate anything that could exceed it ``` Four lines of workflow and gotchas do more work than forty lines of tutorial-style prose ever would, because every line here is something Claude genuinely can't derive from reading the repository. ## How long should a CLAUDE.md file be? Target under 200 lines. That's not an arbitrary style preference, it's Anthropic's own stated recommendation, repeated across both the best-practices guide and the memory documentation, and it's tied to a real mechanical cost: CLAUDE.md loads into your context window at the start of every session, whether or not that particular session ever touches the part of the codebase your rules cover. Anthropic's own interactive context-window walkthrough, which it publishes as part of the Claude Code docs, puts specific illustrative numbers on this. Before you type a single word, a fresh session has already spent roughly 4,200 tokens on the system prompt, about 1,800 tokens on a project CLAUDE.md, and around 680 tokens on auto memory. **Every line in a CLAUDE.md file is context Claude pays for on every session, whether or not that session ever needs it.** A 1,800-token file that covers three genuinely useful rules is a good trade. A 1,800-token file padded with restated language defaults is a tax with no return. There's a behavioral cost that matters more than the token cost, though. Past a certain length, Claude starts missing instructions, not because it ran out of room, but because important rules get diluted by unimportant ones. Anthropic's documentation names this directly as "the over-specified CLAUDE.md," describing it as a common failure pattern: if your CLAUDE.md is too long, Claude ignores half of it because important rules get lost in the noise. The fix given is blunt: ruthlessly prune, and if Claude already does something correctly without the instruction, delete it or convert it to a hook. **The best CLAUDE.md files get shorter over time, not longer.** If your file keeps growing past 200 lines because your project genuinely has that much project-specific nuance, that's a signal to restructure, not to keep appending. Two mechanisms exist specifically for this: path-scoped rules under `.claude/rules/`, which only load when Claude touches matching files, and skills, which load on demand instead of every session. Both are covered below. Neither one reduces your total instruction count, but both stop irrelevant instructions from eating context on sessions that never need them. As of Claude Code v2.1.206, there's also a built-in check for this. Running `/doctor` proposes trims for a checked-in CLAUDE.md, cutting content Claude can derive from the codebase on its own, like directory layouts, dependency lists, and architecture overviews, while keeping pitfalls, rationale, and conventions that differ from tool defaults. It's worth running periodically the same way you'd run a linter, since a file nobody prunes just accumulates dead weight. ## How do you generate a starter CLAUDE.md with /init? You don't have to start from a blank file. Running `/init` inside a Claude Code session tells Claude to scan your codebase, detect your build system and test framework, and write a first draft of CLAUDE.md based on what it finds. If a CLAUDE.md already exists in the project, `/init` suggests improvements instead of blindly overwriting your work. `/init` typically produces sections covering build and test commands, an architecture summary, code style conventions it picked up from existing files, and workflow notes. It's a genuinely useful starting point, especially on a codebase you didn't write yourself. But it's a draft, not a finished product. Anthropic's own documentation is explicit that you shouldn't fully trust what it comes up with: some of the generated content can be wrong, or it can miss standard terminal commands your project actually needs, and you should verify and edit before treating the file as done. Two details are worth knowing if you're running a recent version of Claude Code. Setting the environment variable `CLAUDE_CODE_NEW_INIT=1` before running `/init` enables an interactive, multi-phase flow: it asks which artifacts you want, CLAUDE.md files, skills, hooks, then explores your codebase with a subagent, asks follow-up questions to fill gaps, and shows you a reviewable proposal before writing anything. With that flag set, `/init` also reads existing rule files from other tools, including `AGENTS.md`, `.devin/rules/`, `.windsurf/rules/` or `.windsurfrules`, and `.clinerules`, and folds relevant parts into the generated CLAUDE.md instead of ignoring them. Without the flag, the standard `/init` still reads Cursor rules and GitHub Copilot instructions and incorporates what's relevant. `/init` is also the fastest way to check whether your project even needs the level of detail you were about to write by hand. If the generated file already covers most of what you were going to type, that's a sign the missing 20 percent, the genuinely non-obvious stuff, is the only part worth adding manually. ## How do you write instructions Claude actually follows? Two CLAUDE.md files can contain the same underlying idea and get followed at wildly different rates, depending entirely on how the sentence is phrased. Anthropic's memory documentation gives three direct before-and-after pairs worth internalizing: - "Use 2-space indentation" instead of "Format code properly" - "Run `npm test` before committing" instead of "Test your changes" - "API handlers live in `src/api/handlers/`" instead of "Keep files organized" The pattern across all three: the good version names a specific, checkable action. The weak version names a vague goal that could mean five different things depending on who's reading it. Claude doesn't get to ask a clarifying question mid-session the way a human teammate would; it interprets the sentence and moves on. Ambiguity in a CLAUDE.md line doesn't get resolved, it gets guessed at. You're also allowed to add emphasis where it matters. Anthropic's documentation notes you can tune instruction adherence by adding words like "IMPORTANT" or "YOU MUST" for the rules that genuinely can't be skipped. Overusing this dilutes it fast, the same way an email where every sentence is bold stops emphasizing anything, so save it for the two or three rules where a miss actually breaks something, not for stylistic preferences. Structure matters almost as much as wording. Use markdown headers and bullets to group related instructions instead of writing dense paragraphs. Claude scans structure the same way a human reader does, and a wall of unstructured prose buries the specific, checkable rules inside sentences that read more like a memo than an instruction set. There's a second-order symptom worth watching for. If Claude keeps asking you questions that are already answered somewhere in your CLAUDE.md, that's not Claude being careless, it's usually a sign the phrasing is ambiguous enough that Claude genuinely can't tell what you meant. Treat a repeated question as a prompt to rewrite the line, not just to answer it again in chat. If you want the deeper mechanics of prompting Claude well beyond just CLAUDE.md, including how to give it a way to verify its own work, see [how to prompt Claude for better code output](https://tryuncle.com/learn/claude-code/how-to-prompt-claude-for-better-code-output). The same specificity principle that makes a CLAUDE.md rule stick is the one that makes a single prompt land on the first try. ## What's the difference between CLAUDE.md and Claude Code's auto memory? Claude Code actually runs two separate, complementary memory systems, and conflating them is a common source of confusion. You write CLAUDE.md. Claude writes auto memory. | | CLAUDE.md | Auto memory | | --- | --- | --- | | Who writes it | You | Claude | | What it contains | Instructions and rules | Learnings and patterns | | Loaded into | Every session, in full | Every session, first 200 lines or 25KB of the index | | Best for | Coding standards, workflows, architecture | Build commands Claude discovered, debugging insights, preferences it picked up | Auto memory is on by default and stores its notes at `~/.claude/projects//memory/`, structured as a `MEMORY.md` index plus optional topic files like `debugging.md` or `api-conventions.md`. Only the index loads automatically at session start, and only up to a hard limit of 200 lines or 25KB, whichever comes first; the topic files load on demand when Claude actually needs them. That hard limit is specific to auto memory. CLAUDE.md itself has no equivalent hard cutoff, it loads in full regardless of length, which is exactly why the 200-line recommendation for CLAUDE.md is a best practice about adherence, not a technical ceiling like auto memory's. The practical difference in how you'd use each: if you already know a rule matters before Claude ever encounters the problem, write it in CLAUDE.md. If Claude discovers something through trial and error during a session, like a flaky test that needs a specific flag, or your preference for one library over another after you corrected it twice, that's exactly the kind of thing auto memory is built to catch without you having to remember to write it down yourself. You can review or edit anything auto memory saved at any time by running `/memory` inside a session, since the files are just plain markdown. One nuance worth knowing if you're debugging why a subagent seems to have forgotten something: the main conversation's auto memory isn't loaded into subagents by default, since each subagent runs in its own separate context. If a subagent needs its own persistent memory across runs, that's a separate, explicit configuration, not something that inherits automatically. For more on how subagents manage context, see [what happens when Claude Code runs out of context mid-session](https://tryuncle.com/learn/claude-code/claude-code-running-out-of-context-mid-session). ## How do imports and the @path syntax work in CLAUDE.md? CLAUDE.md files can pull in content from other files using `@path/to/file` syntax, which keeps a project's instructions organized without forcing everything into one giant document. A common pattern: ```markdown See @README for project overview and @package.json for available npm commands. # Additional Instructions - Git workflow: @docs/git-instructions.md - Personal overrides: @~/.claude/my-project-instructions.md ``` Both relative and absolute paths work. Relative paths resolve against the location of the file doing the importing, not your current working directory, which matters if you're importing from a nested folder. Imported files can themselves import other files, recursively, up to a maximum depth of four hops, after which Claude Code stops following the chain. One thing this syntax doesn't do is reduce your context cost. Imported files are expanded and loaded into context at launch right alongside the CLAUDE.md that references them. Splitting content into imports helps with organization and keeping related instructions in logical files, but it doesn't shrink what actually loads into the session. If your goal is genuinely reducing what loads on every session, you want path-scoped rules or skills instead, covered next. There's a security-relevant detail worth knowing before you rely on imports. If a project-level CLAUDE.md imports a file whose path resolves outside your working directory, like the home-directory example above, Claude Code treats that as an external import and shows you an approval dialog the first time it's encountered, listing exactly which files it wants to load. This exists specifically to protect you from an import someone else committed to a shared project pointing somewhere you didn't expect. If you decline, the import stays disabled and the dialog won't reappear for that same reference. Imports inside your own personal `~/.claude/CLAUDE.md` skip this dialog entirely, since they're files you wrote yourself and already trust. If you're generally curious about what else can go wrong when AI tools pull in content you didn't fully vet, [our vibe coding security checklist](https://tryuncle.com/learn/vibe-coding/vibe-coding-security-vulnerabilities-checklist) covers the broader pattern. One syntax quirk to know: import parsing skips markdown code spans and fenced code blocks. If you want to mention a path in your CLAUDE.md without triggering an import, wrap it in backticks, like `` `@README` ``. Written outside backticks, that same string imports the file. ## How do you organize a large CLAUDE.md with .claude/rules/? Once a project's genuine instruction set outgrows a single readable file, `.claude/rules/` gives you a way to split it up without losing the ability to scope instructions to only the parts of the codebase where they apply. Instead of one CLAUDE.md carrying every rule for every part of a monorepo, you place topic-specific markdown files in `.claude/rules/`: ```text your-project/ ├── .claude/ │ ├── CLAUDE.md # Main project instructions │ └── rules/ │ ├── code-style.md # Code style guidelines │ ├── testing.md # Testing conventions │ └── security.md # Security requirements ``` Rules without any special frontmatter load at launch with the same priority as your main CLAUDE.md. The real advantage shows up once you add `paths` frontmatter, which scopes a rule to only load into context when Claude is actually working with matching files: ```markdown --- paths: - "src/api/**/*.ts" --- # API Development Rules - All API endpoints must include input validation - Use the standard error response format - Include OpenAPI documentation comments ``` That rule stays completely out of context on any session that never touches `src/api/`, but shows up automatically the moment Claude reads a matching file. This is the mechanism that solves the tension between "our project genuinely needs 400 lines of conventions" and "CLAUDE.md should stay under 200 lines." You're not cutting content, you're making sure content only loads when it's relevant. Glob patterns support brace expansion for matching multiple extensions in one line, like `src/**/*.{ts,tsx}`. Be aware there's a shared budget of 1,000 expanded patterns and 4MB per rule's `paths` list, since each brace group multiplies the number of patterns Claude Code has to check; a pattern that would exceed that budget gets used unexpanded instead, so its literal braces won't match real files. In practice this only becomes a concern if you're writing unusually elaborate glob patterns, not for a normal handful of extensions. `.claude/rules/` also supports symlinks, which means a team can maintain one shared set of rules in a central location and link them into multiple repositories: ```bash ln -s ~/shared-claude-rules .claude/rules/shared ``` For instructions that aren't about code conventions at all but describe an entire repeatable workflow, like "fix a GitHub issue end to end," a rule is the wrong tool. That's what skills are for, since skills load on demand when invoked rather than sitting in context every session. The line between the two: rules are conditional facts Claude should know while touching certain files, skills are procedures Claude runs when you or the task explicitly calls for them. ## Should you use AGENTS.md instead of CLAUDE.md? This is the question that trips up teams already using more than one AI coding tool, and the honest answer is: it depends on whether you're standardizing on one tool or several. **Claude Code reads CLAUDE.md, not AGENTS.md, so a repo with only an AGENTS.md is invisible to it unless one file imports the other.** AGENTS.md is a genuinely open, tool-agnostic standard: over 60,000 open-source repos use it, and it's read natively by OpenAI's Codex, Google's Jules and Gemini CLI, Cognition's Devin and Windsurf, JetBrains Junie, GitHub Copilot, Cursor, Aider, and more than 20 other coding agents, according to the standard's own site. It's now stewarded under the Linux Foundation's Agentic AI Foundation rather than owned by a single company. If your team already runs a mix of Codex, Cursor, and Claude Code across different projects or different developers, AGENTS.md is the file that keeps you from writing the same conventions four times in four dialects. Here's how the major tools actually handle their own instruction files, based on each tool's own documentation: | Tool | File it reads | Format | Also reads AGENTS.md? | | --- | --- | --- | --- | | Claude Code | `CLAUDE.md` | Plain markdown, no frontmatter | No, needs an import or symlink | | Codex (OpenAI) | `AGENTS.md` | Plain markdown, no frontmatter | Native | | Cursor | `.cursor/rules/*.mdc` | Markdown with YAML frontmatter (description, globs, alwaysApply) | Yes, per the AGENTS.md standard's supporter list | | GitHub Copilot | `.github/copilot-instructions.md` | Plain markdown | Partial, incorporated via Claude Code's `/init` when relevant | | Windsurf | `.windsurf/rules/` or `.windsurfrules` | Markdown | Yes | Claude Code's own documentation is unambiguous about the fix if you already have an AGENTS.md and don't want two files drifting out of sync: create a CLAUDE.md that imports it. ```markdown @AGENTS.md ## Claude Code Use plan mode for changes under `src/billing/`. ``` Claude loads the imported file at session start, then reads whatever Claude-specific instructions you add below the import. On macOS and Linux, a symlink accomplishes the same thing if you don't need any Claude-specific additions: `ln -s AGENTS.md CLAUDE.md`. On Windows, creating a symlink needs Administrator privileges or Developer Mode, so the `@AGENTS.md` import is the more practical route there regardless. Choose AGENTS.md as your source of truth if your team genuinely uses more than one AI coding tool day to day, and let CLAUDE.md be a thin import on top of it for anything Claude-specific. Choose CLAUDE.md alone if Claude Code is the only agent touching the repo, since a direct file avoids an extra layer of indirection for the one tool you actually use. ## What are the most common CLAUDE.md mistakes? A handful of failure patterns show up over and over, and Anthropic's own best-practices documentation names several of them directly, alongside the fix. **The over-specified file.** A CLAUDE.md that grew past 200 lines without anyone pruning it. Symptom: Claude ignores half of what's written because the important rules are buried under restated defaults. Fix: ruthlessly cut anything Claude already does correctly on its own, and delete or convert to a hook anything that isn't holding. **Restating what a linter already enforces.** As Kyle at HumanLayer put it, Claude is not a linter. A CLAUDE.md rule about spacing or quote style is redundant the second your project has Prettier or ESLint configured, and it just burns context for zero behavioral gain. **Vague goals instead of checkable rules.** "Write clean code" and "keep files organized" tell Claude nothing it can act on differently. Replace every vague line with a specific one it can actually verify against: a command, a path, a concrete convention. **Information that changes weekly.** A CLAUDE.md line describing this sprint's current feature branch or a temporary workaround goes stale within days and then actively misleads Claude in every future session until someone remembers to remove it. That kind of transient state belongs in a ticket or a commit message, not in a file loaded on every session indefinitely. **Conflicting instructions across files.** If your root CLAUDE.md says one thing and a nested subdirectory's CLAUDE.md says something else for overlapping cases, Claude may pick one arbitrarily rather than reconciling them for you. Review your CLAUDE.md files and `.claude/rules/` periodically for contradictions the same way you'd review code for logic errors. **Treating CLAUDE.md as enforcement.** CLAUDE.md is advisory context, not a hard gate. If a rule genuinely can't be skipped, like never pushing directly to main or always running a specific check before commit, write it as a hook instead, since hooks execute as deterministic shell commands regardless of what Claude decides in the moment. ## Which mechanism should you actually use: CLAUDE.md, a rule, a skill, a hook, or settings.json? By this point you've got five different places Claude Code lets you put an instruction, and picking the wrong one is its own category of mistake. Here's how to sort a new instruction the moment you think of it. | If the instruction is... | Put it in... | Because... | | --- | --- | --- | | True for every session, short, and can't be derived from code | CLAUDE.md | It's the one thing guaranteed to load every time, in full | | Only relevant when Claude touches a specific folder or file type | A rule under `.claude/rules/` with `paths` frontmatter | It stays out of context on sessions that never need it | | A multi-step procedure you invoke by name, not a fact Claude should always know | A skill | Skills load on demand instead of sitting in context every session | | Something that must never be skipped, no matter how the session is going | A hook | Hooks execute as shell commands at fixed lifecycle events regardless of what Claude decides | | A hard boundary on what tools or commands Claude is even allowed to run | `settings.json` permissions | Deny rules block a matching tool call outright; allow rules skip the approval prompt | | Something Claude discovered on its own mid-session that you didn't think to write down | Nothing, let auto memory handle it | Claude saves it for you without being asked | The distinction between a hook and a `settings.json` deny rule trips people up, since both feel like enforcement. A deny rule blocks a tool call before it ever reaches Claude's reasoning, the way a firewall blocks a port. A hook is more flexible: it runs your own script at a lifecycle event, and that script decides whether to allow, block, or modify what happens next. If you just want to permanently forbid a destructive command or block writes to a `.env` file, a deny rule is the simpler tool. If you want custom logic, like scanning a diff for anything that looks like a secret before it's written, that calls for a hook. Anthropic's own agent SDK documentation spells out the evaluation order: hooks run first, and a hook that returns "allow" still doesn't skip the deny and ask rules evaluated after it (see [Configure permissions](https://code.claude.com/docs/en/agent-sdk/permissions)). **CLAUDE.md is the only one of the five that Claude reads as a suggestion rather than a rule it must obey.** That single fact should decide most of your placement questions. If getting it wrong once would be a genuine problem, and not just an annoyance, it doesn't belong in CLAUDE.md at all. ## A worked example: writing a CLAUDE.md from scratch Theory is easier to apply with two concrete examples side by side: a minimal file for a small project, and a fuller one for something with more moving parts. A minimal CLAUDE.md, appropriate for a small script-heavy project or a personal tool: ```markdown # Build & test - `npm run build` compiles TypeScript to dist/ - `npm test` runs the full suite; `npm test -- path/to/file` runs one file # Conventions - Use named exports only, no default exports - Error messages are user-facing; write them in plain language, not stack traces # Gotchas - The dev server needs `LOCAL_API_KEY` set in .env.local or auth silently no-ops ``` That's eleven lines and covers three things Claude genuinely can't infer: a project-specific build split, a style choice that isn't a language default, and an environment quirk that would otherwise cause a confusing silent failure. Nothing here restates what a linter or the codebase itself already makes obvious. A fuller CLAUDE.md, appropriate for a multi-service project with a real team: ```markdown # Architecture - Monorepo: `packages/api` (Node/Express), `packages/web` (React), `packages/shared` - API and web share types via `packages/shared`; never duplicate a type definition # Build & test - `pnpm build` builds all packages; `pnpm --filter api build` builds one - Run `pnpm typecheck` after any change touching `packages/shared` - Prefer running a single test file over the full suite during iteration # Code style - API: async/await only, no raw Promise chains - Web: functional components only, no class components - Both: 2-space indentation (enforced by Prettier, don't restate elsewhere) # Workflow - Branch names: `/`, e.g. `jm/fix-oauth-refresh` - PRs require a passing `pnpm test` and at least one review before merge # Gotchas - Staging DB resets nightly at 2am UTC; don't rely on staging data persisting - The webhook handler in `packages/api/src/webhooks/` is idempotent by design; don't add dedup logic elsewhere, it'll double-process legitimate retries ``` Notice what's absent as much as what's present. There's no file-by-file description of the codebase, no restated JavaScript conventions Claude already knows, and no tutorial on how React works. Every section answers a question a new engineer would actually have to ask a teammate on day one, which is the real bar for what belongs in the file. ## How do you audit and shrink a CLAUDE.md that's already gotten too long? Most CLAUDE.md files don't start bloated. They get there one reasonable-sounding addition at a time, usually right after a frustrating session where Claude did something wrong and someone typed a new rule into the file to make sure it never happens again. Nobody goes back and removes the rule once the underlying problem gets fixed a different way. Here's a short, illustrative excerpt of the kind of file that pattern produces, with a verdict on each line: ```markdown # Project rules - This is a Next.js project using TypeScript - We use React for the frontend - Always write clean, readable code - Use 2-space indentation for all files - Follow best practices for testing - Run `npm run build` to build the project (only works from the root directory, not from inside packages/web, this tripped someone up in March) - Never commit directly to main, always use a PR - The staging database is at db-staging.internal.example.com - API_SECRET_KEY=sk-abc123... (needed for local testing against staging) - We generally prefer functional components - Don't use `any` in TypeScript, we had a bad incident with this - Remember that Jake prefers tabs but the team uses spaces, just use spaces - The onboarding flow is currently being redesigned, don't touch src/onboarding/ until the redesign PR merges ``` Line by line, here's the audit: - **"This is a Next.js project using TypeScript"**: keep, but only if it's not already obvious from `package.json`. If it's a normal setup, cut it. Claude reads the codebase before it reads your opinion of it. - **"We use React for the frontend"**: cut. Redundant with the line above and with every `.tsx` file in the repo. - **"Always write clean, readable code"**: cut. This is the textbook example of a goal with nothing checkable behind it. - **"Use 2-space indentation for all files"**: cut if Prettier or an `.editorconfig` already enforces it. Keep only if no formatter exists yet. - **"Follow best practices for testing"**: cut. Replace with the actual command and the actual test runner if there's something specific to say. - **"Run `npm run build`..."**: keep. It's specific, it names a real gotcha, and it would take a new contributor a wasted ten minutes to discover on their own. - **"Never commit directly to main, always use a PR"**: a candidate for a hook, not a CLAUDE.md line, since it's a rule that genuinely should never be broken. A pre-push hook or branch protection on the remote enforces it; CLAUDE.md just asks nicely. - **"The staging database is at db-staging.internal.example.com"**: keep if it's genuinely useful and not sensitive. Borderline: if this URL is meant to be non-public, it shouldn't be sitting in a file that's checked into git and sent to a model on every session. - **"API_SECRET_KEY=sk-abc123..."**: delete this immediately and rotate the key. A committed secret in CLAUDE.md is a committed secret in git history, full stop, and it's now also part of the context Claude Code loads and reasons over every session. - **"We generally prefer functional components"**: keep only if the codebase has a real mix of both patterns and Claude might otherwise pick the wrong one. If it's a modern codebase with zero class components, cut it, the code already answers the question. - **"Don't use `any` in TypeScript, we had a bad incident with this"**: keep the rule, cut the backstory. "Don't use `any`; use `unknown` and narrow it" is the same instruction without the anecdote, and it's a rule a linter's no-explicit-any check can also enforce directly if you want it to stop being advisory. - **"Remember that Jake prefers tabs but the team uses spaces, just use spaces"**: cut. This is two sentences of context to deliver one word of instruction: spaces. Jake's preference is now a permanent fixture of a file every future contributor reads, long after Jake has moved teams. - **"The onboarding flow is currently being redesigned..."**: cut from CLAUDE.md, but don't just delete the information. This is transient project state, exactly the kind of thing that goes stale within weeks and then actively misleads Claude once the redesign ships. It belongs in the PR description or a tracking ticket, not a file loaded on every session indefinitely. Run that same audit against your own file with one question per line: **would deleting this line cause Claude to make a mistake it wouldn't otherwise make?** If the honest answer is no, or if the line only protects against something a linter, a hook, or a `.gitignore` entry already prevents, it goes. What's left after an audit like this is usually half the original file, sometimes less, and every remaining line is doing real work instead of just taking up space. ## How do you write a CLAUDE.md for a DaVinci Resolve or Fusion scripting project? If you're pointing Claude Code at DaVinci Resolve automation, whether that's a Fusion script, a batch export tool, or a bridge that connects Claude to Resolve's own scripting API, the same rules apply with one addition: Resolve's API surface isn't something Claude already knows the way it knows Express or React, so your CLAUDE.md needs to close that gap explicitly. Start by naming what you're actually targeting. DaVinci Resolve's Python scripting API, connected through community tools like [samuelgursky/davinci-resolve-mcp](https://github.com/samuelgursky/davinci-resolve-mcp), bridges Claude Code to Resolve so it can run Python commands against your open project. That bridge requires DaVinci Resolve Studio, since the free edition doesn't support external scripting. If your CLAUDE.md doesn't say which edition you're running, Claude has no way to know whether a given approach is even possible in your setup, and it'll happily write code against an API that isn't available to you. A CLAUDE.md for this kind of project might look like: ```markdown # Environment - DaVinci Resolve Studio (not the free edition) with external scripting enabled - MCP bridge: samuelgursky/davinci-resolve-mcp, connects to the open project # API notes - Use the official Resolve Python API objects (Project, Timeline, MediaPool) - Never assume a method exists; check against the API docs before calling it - Fusion node scripting uses a separate API surface from the Edit/Color page API # Workflow - Test scripts against a scratch project first, never the live client project - Log every mutating call (append, delete, render) before it runs ``` The specific line worth calling out is "never assume a method exists." Claude is a strong general-purpose coder, but Resolve's scripting API is a narrow, less-documented surface compared to something like a REST framework, and a model without a CLAUDE.md pointing it at the real API will sometimes generate plausible-looking method names that don't actually exist on the object. Naming the API explicitly and asking Claude to verify rather than assume closes most of that gap. TryUncle is the on-screen assistant for DaVinci Resolve on macOS. Ask in plain words and Uncle points at the exact control on your screen. That's a different problem than a CLAUDE.md solves. A CLAUDE.md file makes Claude Code better at writing Resolve automation scripts for you. Uncle helps inside the actual Resolve interface while you're editing by hand, pointing at the button or panel you're looking for instead of generating code. If your work is split between scripting Resolve and manually editing in it, the two aren't competing tools, they're solving different halves of the same afternoon. ## What edge cases actually break a typical CLAUDE.md? Most CLAUDE.md advice assumes a single-language repo with one team and one environment. Real projects are messier than that, and a few specific situations deserve their own answer instead of a general rule. **Never put secrets, API keys, or credentials in CLAUDE.md.** This deserves to be said plainly and separately from the general "keep it short" advice, because the failure mode is worse than a wasted line. CLAUDE.md is a file that gets checked into git, which means a committed key lives in your repository's history forever, even after you delete it in a later commit. It's also a file Claude Code loads into context and reasons over every session, meaning the secret gets sent to the model repeatedly for no benefit. Use environment variables and a gitignored `.env` file instead, and if a rule needs to reference that a variable exists, name the variable, not its value: "requires `STAGING_API_KEY` in `.env.local`" is a fine CLAUDE.md line; the actual key never should be. **Multi-language monorepos need per-package CLAUDE.md files, not one file trying to cover everything.** A repo with a Python backend, a TypeScript frontend, and a Go worker service has three different sets of conventions, and cramming all three into one root-level file means every session pays the context cost of two languages it isn't touching. Since Claude Code walks up the directory tree and concatenates every CLAUDE.md it finds, the better structure is a thin root file covering only what's shared, plus a `CLAUDE.md` inside each package covering that package's specific conventions. **A public, open source repo needs to treat its CLAUDE.md as public documentation, not internal notes.** Anything in a committed CLAUDE.md is visible to anyone who clones the repo, including competitors, security researchers, and anyone doing due diligence before a job interview. Internal-only details, like which staging environment is flaky or which client's requirements shaped a weird workaround, belong in `CLAUDE.local.md` or a private wiki instead, not in the file every contributor pulls down. **Running multiple Claude Code sessions against the same repo at once doesn't cause CLAUDE.md conflicts, but it can cause confusing behavior if the file changes mid-session.** Each session reads CLAUDE.md at launch and re-reads the project-root file after `/compact`, but it doesn't watch the file for live edits the way an IDE would. If a teammate updates CLAUDE.md while your session is already running, you won't see the update until your next session, or your next compaction. If you're debugging why Claude seems to be ignoring a rule you just added, check whether the session predates the edit. **CI and other non-interactive automation still reads CLAUDE.md, but can't generate it.** A pipeline running `claude -p "fix the failing test"` picks up the same CLAUDE.md a human's interactive session would, since the file loading isn't an interactive-mode feature, only `/init`'s generation step is. If you're setting up Claude Code in CI for the first time, write the file by hand or run `/init` once locally and commit the result, rather than expecting the pipeline to bootstrap it. **Devcontainers and other reproducible environments should have their quirks written down explicitly, since Claude can't inspect a container spec the way it reads source files.** If your project only builds correctly inside a specific Docker image, or requires a devcontainer extension to run tests, that's exactly the kind of non-obvious, code-can't-tell-you-this fact CLAUDE.md exists for. State the container name and the one command that starts it, not a tutorial on Docker. ## Is a good CLAUDE.md a substitute for good prompting, or do you still need both? You need both, and they solve different problems. CLAUDE.md handles what's true every single session: your build commands, your conventions, your architecture. A well-written prompt handles what's true for this specific task: which file, which edge case, what "done" looks like this time. Anthropic's own research on real Claude Code sessions, covering agentic coding and persistent returns to expertise, found that domain expertise predicted success far more than general coding background did. Sessions rated novice reached verified success only 15 percent of the time, against 28 to 33 percent for intermediate and expert-rated sessions, and when a session hit trouble, experts recovered from it at roughly triple the rate novices did. A CLAUDE.md file is one of the few tools that lets someone with less domain expertise close part of that gap in advance, since it hands Claude the project knowledge an expert would already carry into every prompt, without the person writing the prompt needing to restate it every time. Anthropic's applied AI team makes a related point in its piece on effective context engineering for agents: the context window is a finite resource, and what you choose to put in front of the model, and what you choose to leave out, has a direct, compounding effect on output quality across a long session. CLAUDE.md is the one piece of that budget you set once and pay for on every session. A vague prompt with a great CLAUDE.md behind it will usually outperform a great prompt against an empty or bloated CLAUDE.md, simply because the model has a stable base of true project facts to work from either way. If you want the deeper mechanics of what makes an individual prompt effective, the verification loop, scoping the task, referencing existing patterns, that's covered in full in [how to prompt Claude for better code output](https://tryuncle.com/learn/claude-code/how-to-prompt-claude-for-better-code-output). Think of CLAUDE.md as the thing you stop having to type, and a good prompt as everything that's actually specific to the task in front of you right now. ## How do you know if your CLAUDE.md is actually working? You can't tell just by reading it. A file can look reasonable on the page and still be silently ignored, either because it never loaded or because the wording is too vague to act on. A few concrete checks: **Confirm it loaded at all.** Run `/context` in a session and check the Memory files list. If your CLAUDE.md isn't there, Claude never saw it, and no amount of rewriting the content will help until the location problem is fixed. This is the single most common root cause behind "Claude keeps ignoring my rules," and it takes about five seconds to rule out. **Watch for repeated corrections on the same issue.** If you find yourself typing the same correction into chat two sessions in a row, that's a rule that belongs in CLAUDE.md but isn't there yet, or is there but phrased too vaguely to stick. Anthropic's own troubleshooting guidance treats this pattern as a direct signal: if Claude asks you questions that are already answered in CLAUDE.md, the phrasing is probably ambiguous, not the content wrong. **Check whether instructions survive compaction.** Project-root CLAUDE.md is re-injected from disk after `/compact`, so it should always be present in a long session. Nested CLAUDE.md files in subdirectories and path-scoped rules are not automatically re-injected; they only reload the next time Claude reads a matching file. If an instruction seems to have vanished mid-session specifically after a long conversation, check whether it lived in a nested file rather than the root one. For the full mechanics of what survives a long session running low on room, see [what to do when Claude Code runs out of context mid-session](https://tryuncle.com/learn/claude-code/claude-code-running-out-of-context-mid-session). **Look for conflicting instructions across files.** A root CLAUDE.md, a nested one, and a handful of `.claude/rules/` files can drift into contradiction without anyone noticing, especially on a team where different people add rules independently. Periodically read through all of them together, not just the one you're currently editing. If a specific instruction absolutely cannot be allowed to fail, stop trying to phrase it more emphatically in CLAUDE.md and write it as a hook instead. CLAUDE.md instructions are context Claude tries to follow. A hook is a script that runs regardless of what Claude decides, which is the right tool the moment "usually follows this" isn't good enough. ## How do you keep CLAUDE.md from drifting once more than one person edits it? A CLAUDE.md maintained by one person stays coherent because that person remembers why every line is there. The moment a second and third person start adding to it, usually mid-debugging, right after Claude did something annoying, the file starts accumulating rules nobody can explain anymore. A few practices keep that from happening. **Review changes to CLAUDE.md the same way you'd review a change to a config file that affects production**, because in a real sense it does affect every future session. A one-line addition someone typed in frustration at 11pm deserves the same five minutes of scrutiny as a one-line change to a deployment script: does this line actually belong here, is it phrased as a checkable instruction, and does it duplicate something already covered three sections up. **Name an owner, even informally.** It doesn't need to be a job title. It just needs to be someone who periodically reads the whole file top to bottom, not just the new line someone is proposing, and asks whether it's still under 200 lines and whether every section still earns its place. Without an owner, a CLAUDE.md only ever grows, since removing a line feels riskier than adding one and nobody wants to be the person who deletes a rule that turns out to matter. **Put a lightweight required-review rule on the file if your git host supports it.** Requiring at least one review on any PR that touches CLAUDE.md, `.claude/rules/`, or `.claude/settings.json` costs almost nothing and catches the two most common drift patterns: a rule that only makes sense for one person's workflow, and a rule that quietly contradicts one already in the file. **Schedule the prune, don't wait for a symptom.** Reactive pruning, where you only trim the file after noticing Claude ignoring instructions, works, but it means the file spends most of its life larger than it needs to be. Running `/doctor`'s trim proposal at a fixed cadence, monthly for an active project, quarterly for a stable one, catches bloat before it's bad enough to cause a visible problem. **Treat every addition as a hypothesis, not a permanent fact.** The healthiest pattern is adding a line, watching whether it actually changes Claude's behavior over the next several sessions, and removing it if it didn't. A CLAUDE.md that's never had anything removed from it almost certainly has dead weight in it. Nobody writes a perfect instruction set the first time; the file just doesn't tell you which lines stopped earning their keep. | Team size | Suggested review cadence | Who owns it | | --- | --- | --- | | Solo project | Whenever you notice friction | You | | Small team, one repo | Monthly, or after each `/doctor` run | Whoever touches Claude Code most | | Multiple teams, one monorepo | Per-package files reviewed by that package's team; root file reviewed quarterly by a rotating owner | One owner per package, one for the shared root | | Open source project | Any PR touching CLAUDE.md gets a maintainer review, same bar as a docs PR | A maintainer, not a first-time contributor | ## Does CLAUDE.md work the same way across Claude.ai, the API, and other tools? No, and this is a common point of confusion for people moving between Anthropic's products. CLAUDE.md is a Claude Code-specific mechanism. Claude.ai's web chat interface doesn't read a CLAUDE.md file from your filesystem, since it has no filesystem access to a local project in the first place. The Claude API doesn't read one either; if you're calling the API directly, the equivalent is whatever you pass as a system prompt yourself, constructed however your own application chooses to build it. Within the Claude Code ecosystem specifically, there's also a distinction worth knowing between interactive and non-interactive use. `/init`, the command that auto-generates a starting CLAUDE.md, only works inside Claude Code's interactive mode; you can't trigger it directly from a one-shot `claude -p` command in a script. If you're scripting Claude Code for CI or automation, you write the CLAUDE.md by hand ahead of time, the same file gets picked up either way once it exists, but the generation shortcut itself is an interactive-mode feature. Because Claude Code updates its own conventions fairly quickly, a fair amount of what's written online about CLAUDE.md content has already gone stale. Auto memory, `.claude/rules/` with path-scoped frontmatter, and the `/doctor` trim proposals covered in this guide are all mechanisms that didn't exist a year before this was written, and general advice from 2025 that only talks about a single flat file misses real capability that now exists to keep that file smaller. When you're reading advice on this topic anywhere, including here, it's worth checking it against Anthropic's current [best practices](https://code.claude.com/docs/en/best-practices) and [memory](https://code.claude.com/docs/en/memory) documentation directly, since those pages get updated as the product changes and a static blog post doesn't. ## The verdict A good CLAUDE.md file is boring. It's short, it says exactly what it means, and most of it is stuff you'd never think to explain to a human teammate because a human would just read the code. That's the whole point. Write down only what Claude genuinely can't infer, phrase every line so it's checkable, run `/init` to get started instead of staring at a blank file, and prune the thing every time you notice Claude either ignoring a rule or asking a question the file was supposed to have already answered. If you're building or scripting inside DaVinci Resolve specifically, name your Resolve edition and your scripting bridge explicitly, since that's the one part of a typical project Claude has the least built-in familiarity with. And if the work in front of you is manual editing rather than scripting, that's a different problem than a config file solves. That's exactly the kind of moment Uncle can step in for, pointing at the specific control on your screen while you're still inside your own project, instead of you pausing to go look it up. ## FAQ ### What is a CLAUDE.md file? A plain markdown file that Claude Code reads automatically at the start of every session in a project. It holds instructions Claude can't infer from the code itself, like build commands, code style rules that differ from language defaults, and repo etiquette. There's no required format and no schema to validate against, just markdown headers and bullets. ### Where do I put my CLAUDE.md file? Project instructions go in ./CLAUDE.md or ./.claude/CLAUDE.md at your project root, checked into git so your team shares them. Personal preferences that apply everywhere go in ~/.claude/CLAUDE.md. Personal notes for one project only, like local sandbox URLs, go in ./CLAUDE.local.md, added to .gitignore. Claude Code also loads a CLAUDE.md from every parent directory above your working directory, which matters in monorepos. ### How long should a CLAUDE.md file be? Anthropic's own documentation recommends staying under 200 lines. There's no hard cutoff that breaks the file at 201 lines, but longer files consume more of the context window on every session and, past a certain point, Claude starts ignoring instructions because they get lost in the noise. If you need more content than that, move it into a skill or a path-scoped rule instead of growing the main file. ### What's the difference between CLAUDE.md and AGENTS.md? AGENTS.md is an open, tool-agnostic format read natively by Codex, Cursor, Copilot, Gemini CLI, Windsurf, and more than 20 other coding agents. Claude Code reads CLAUDE.md specifically, not AGENTS.md, by default. If your repo already has an AGENTS.md, the fix is a one-line import, @AGENTS.md, at the top of your CLAUDE.md, or a symlink on macOS and Linux, so both tools read the same source without duplicated files drifting apart. ### How do I generate a CLAUDE.md automatically instead of writing one from scratch? Run /init inside a Claude Code session. It scans your codebase, detects your build system, test framework, and existing conventions, and writes a starting CLAUDE.md for you. If a CLAUDE.md already exists, /init suggests improvements instead of overwriting it. Treat the output as a rough draft, not a finished file. Anthropic's own docs are explicit that you should refine it, not trust it blindly. ### What's the difference between CLAUDE.md and Claude Code's auto memory? You write CLAUDE.md by hand and it holds rules and instructions. Claude writes auto memory itself, saving debugging insights and preferences it picks up from your corrections during a session, into a MEMORY.md and topic files at ~/.claude/projects//memory/. Use CLAUDE.md to tell Claude what you already know matters. Auto memory catches what neither of you thought to write down in advance. ### Why isn't Claude Code following the rules in my CLAUDE.md? Usually because the file is too long, too vague, or genuinely didn't load. Run /context and check the Memory files list to confirm it loaded at all. If it did, tighten the wording: "Use 2-space indentation" gets followed far more reliably than "format code properly." If Claude keeps breaking the same rule despite a clear instruction, the file is probably too long and that specific line is getting lost. Prune it, or turn the rule into a hook, which enforces the behavior instead of just suggesting it. ### Should I put secrets or API keys in my CLAUDE.md file? No, never. CLAUDE.md is typically committed to git, so a secret placed there lives permanently in your repository's history even after a later commit removes it, and Claude Code also loads the file into context and sends it to the model on every session. Use environment variables and a gitignored .env file instead, and if a CLAUDE.md line needs to reference one, name the variable, not its value. ### Does a good CLAUDE.md matter if I'm using Claude Code for DaVinci Resolve scripts instead of a normal app? Yes, and it matters more, not less, since Resolve's scripting API isn't something Claude already knows cold the way it knows a typical web framework. A CLAUDE.md that states you're targeting Resolve's Python API, names the MCP bridge you're using if any, and links the official scripting docs saves Claude from guessing at object names and methods it would otherwise hallucinate. ## Sources - [Best practices for Claude Code - Claude Code Docs](https://code.claude.com/docs/en/best-practices) - [How Claude remembers your project - Claude Code Docs](https://code.claude.com/docs/en/memory) - [Explore the context window - Claude Code Docs](https://code.claude.com/docs/en/context-window) - [Skills - Claude Code Docs](https://code.claude.com/docs/en/skills) - [Subagents - Claude Code Docs](https://code.claude.com/docs/en/sub-agents) - [Configure permissions - Claude Code Docs](https://code.claude.com/docs/en/agent-sdk/permissions) - [Writing a good CLAUDE.md - HumanLayer Blog (Kyle, @0xblacklight)](https://www.humanlayer.dev/blog/writing-a-good-claude-md) - [AGENTS.md](https://agents.md/) - [Anthropic: Agentic coding and persistent returns to expertise (Zoe Hitzig, Maxim Massenkoff, Eva Lyubich, Shaoyi Zhang, Ryan Heller, Peter McCrory)](https://www.anthropic.com/research/claude-code-expertise) - [Anthropic Engineering: Effective context engineering for AI agents (Prithvi Rajasekaran, Ethan Dixon, Carly Ryan, Jeremy Hadfield)](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents) - [Cursor Rules: How to Keep AI Aligned With Your Codebase - DataCamp](https://www.datacamp.com/tutorial/cursor-rules) - [GitHub - samuelgursky/davinci-resolve-mcp](https://github.com/samuelgursky/davinci-resolve-mcp) - [TryUncle](https://tryuncle.com)