·14 min read

CLAUDE.md Is the Most Important File in Your Repo

claude-codetutorialopinion

The difference between a productive Claude Code session and a frustrating one usually comes down to a single file. Not your package.json. Not your tsconfig. A markdown file called CLAUDE.md that most developers either don't know about or don't take seriously.

I've been using Claude Code as my primary development tool for months now, as I described in the series introduction. Early on, every session started with the same ritual: re-explaining my stack, reminding Claude not to use default exports, telling it where my config files live, correcting the same mistakes I corrected yesterday. It felt like onboarding a new contractor every morning who had amnesia about everything we discussed the day before.

Then I wrote a proper CLAUDE.md, and the experience changed completely. Claude stopped guessing. It knew my conventions. It knew my stack. It knew the specific, weird things about my project that would trip up any developer seeing the codebase for the first time. That file became the single highest-leverage thing I've done to improve my AI-assisted workflow.

What CLAUDE.md Actually Is

CLAUDE.md is a markdown file that Claude Code automatically loads into context at the start of every session. You put it at the root of your repo, and Claude reads it before it reads anything else. It's not documentation for humans. It's not a README. It's an instruction manual for Claude.

Think of it as onboarding a new developer to your project, except this developer reads the onboarding doc every single time they sit down to work. Humans skim onboarding docs once and forget half of it. Claude reads yours completely, every session, and follows it. That changes what you should put in it.

A README tells someone what your project is. A CLAUDE.md tells Claude how to work on it. The distinction matters. You're not explaining concepts. You're giving directives. "Use named exports." "Run npm run build to verify changes." "Don't create new files unless explicitly asked." Direct, imperative instructions that shape behavior.

The Hierarchy

One of the most underappreciated features of CLAUDE.md is that it's not a single file. It's a hierarchy. Claude loads CLAUDE.md files from multiple levels, and they stack on top of each other.

CLAUDE.md file hierarchy: more specific files override more general ones. Claude loads all applicable levels.

~/.claude/CLAUDE.md is your global file. It applies to every project you work on with Claude Code. This is where your personal preferences go. Things like your coding style, how you want commit messages formatted, whether you want verbose explanations or terse responses. These are preferences that follow you regardless of which project you're in.

~/project/CLAUDE.md is your project root file. This is the workhorse. It defines your tech stack, your conventions, your build commands, your code style rules. Everything Claude needs to know to be productive in this specific codebase.

~/project/src/app/CLAUDE.md is a subdirectory file. When Claude is working in that directory, it loads this file on top of everything else. This is where you put context that's specific to a subsystem, a module, or a particular area of the codebase.

More specific overrides more general. You can have a global rule that says "prefer functional components" and a project-specific rule that says "this legacy module uses class components, don't refactor them." Claude respects both, applying the more specific instruction when it's relevant.

This hierarchy is powerful because it lets you be precise without being verbose. Your root CLAUDE.md doesn't need to explain every subdirectory's conventions. Each subdirectory can carry its own context. The root file stays lean. The details live where they're relevant.

What to Put in It

This is where most people go wrong. They either put too little ("this is a React app") or too much (a 500-line document that wastes half of Claude's context window on information it doesn't need). The sweet spot is specific, actionable instructions organized by priority.

I think about it as WHY, WHAT, HOW -- in that order.

Project Description

One paragraph. What is this project? What does it do? This gives Claude the mental model it needs to make sensible decisions.

## Project Description
 
A personal portfolio site built as a macOS desktop simulator.
The entire UI is a fake operating system with draggable windows,
a dock, a menubar, and apps that showcase projects and blog posts.

That's it. Claude now understands why there are components called Window and Dock and MenuBar. It won't try to refactor your desktop metaphor into a standard SPA layout because it understands the premise.

Tech Stack and Conventions

Be explicit. Don't assume Claude will infer your stack from your dependencies. State it directly.

## Tech Stack
 
- Next.js 15 (App Router)
- TypeScript (strict mode)
- Tailwind CSS (no CSS modules, no styled-components)
- Zustand for state management
- MDX for blog posts via next-mdx-remote

The parenthetical notes are important. "No CSS modules, no styled-components" is a negative constraint that prevents Claude from reaching for those tools. Without it, Claude might suggest a CSS module when Tailwind would be the right answer for your project.

Build and Test Commands

Claude needs to know how to verify its work. Give it the commands.

## Commands
 
- `npm run dev` -- start dev server
- `npm run build` -- production build (run this to verify changes)
- `npm run lint` -- run ESLint

This seems trivial, but it matters. When Claude knows the build command, it can verify that the code it wrote actually compiles. When it doesn't know, it guesses, or worse, it skips verification entirely.

Code Style Rules

These are the high-value instructions. Every codebase has conventions that aren't enforced by a linter. Things that a new developer would get wrong on their first PR. Write them down.

## Code Style
 
- Use named exports, not default exports
- Prefer `interface` over `type` for object shapes
- Colocate component styles with components
- No inline styles -- use Tailwind classes
- Prefer early returns over nested conditionals

What NOT to Do

Negative constraints are some of the most valuable instructions you can give. They prevent entire categories of mistakes.

## Do NOT
 
- Don't add comments to code you didn't write or change
- Don't create new files unless explicitly necessary
- Don't refactor existing code unless asked to
- Don't add dependencies without asking first
- Don't use `any` type in TypeScript

These rules come from experience. Every one of them addresses a real behavior pattern where Claude, left to its own judgment, will occasionally do the wrong thing. The "don't add comments" rule exists because Claude sometimes helpfully adds JSDoc comments to functions you didn't ask it to touch. The "don't create new files" rule exists because Claude's default instinct is to create a new utility file rather than add a function to an existing one.

File Structure

If your project structure is non-obvious, give Claude a map. You don't need to list every file. Just the top-level organization.

## File Structure
 
- `src/app/` -- Next.js app router pages
- `src/components/os/` -- macOS desktop simulator components
- `src/components/apps/` -- individual "app" windows
- `src/stores/` -- Zustand stores
- `src/hooks/` -- custom React hooks
- `content/blog/` -- MDX blog posts

This saves Claude from running a bunch of ls and find commands at the start of every session to orient itself.

A Real Example

Here is the actual CLAUDE.md from the repository that powers this portfolio site. It's not long. It doesn't need to be.

# Project Instructions
 
## MDX Blog Post Rules
 
- **No curly braces in prose text.** MDX interprets curly braces
  as JSX expressions, which breaks the build. Use square brackets
  or backtick-escape them in inline code instead.
- **No bare angle brackets in prose.** Angle-bracket words are
  parsed as JSX tags. Use backticks or rephrase.
- **Code blocks are safe.** Fenced code blocks handle curly braces
  and angle brackets fine.
- **Always run `npx next build`** after writing new .mdx files to
  catch MDX compilation errors before pushing.
- Blog posts use `remark-gfm` via `next-mdx-remote` for GFM
  features (tables, strikethrough, autolinks).
 
## Design System Rules
 
- **Single source of truth**: All design attributes (colors, fonts,
  spacing, shadows, radii, breakpoints, animations) must be defined
  in ONE place only -- the global CSS / Tailwind config. No
  hardcoded values in components.
- Components must reference design tokens/CSS variables, never raw
  hex codes or pixel values.
- If a new design attribute is needed, add it to the global config
  first, then use it.

Every rule in there came from a real mistake.

The "no curly braces in prose" rule exists because MDX treats curly braces as JSX expression delimiters. I wrote a blog post that mentioned JavaScript objects in prose, used curly braces casually, and the build exploded with a cryptic JSX parsing error. That mistake became a rule. Now Claude never makes it.

The "no bare angle brackets" rule is the same story. I wrote something like "use a tag to wrap the content" and MDX tried to parse it as an actual HTML tag. Another build failure, another rule.

The "always run npx next build" rule is there because MDX errors don't show up in the dev server. This is the kind of project-specific gotcha that claude-mem would also surface from past sessions, but CLAUDE.md ensures it's present from the very first session. You can write a broken MDX file, see it render fine in dev mode, push it, and then your production build fails. Telling Claude to run the build command after writing MDX files catches these errors before they become problems.

The design system rules prevent a different kind of drift. Without them, Claude will occasionally hardcode a hex color or a pixel value directly in a component. That works in the moment, but it means your colors are now defined in two places -- your Tailwind config and some random component file. The rule ensures Claude always goes through the design system.

This is what a good CLAUDE.md looks like. It's short. Every line is there for a reason. Every rule prevents a specific, real problem.

Common Mistakes

I've iterated on my CLAUDE.md files enough to know where people go wrong.

Making it too long. Anything over 150 lines starts to be counterproductive. CLAUDE.md consumes context window space, and context is finite. A 500-line CLAUDE.md filled with explanations and examples is eating into the space Claude needs for your actual code. Be terse. Use bullet points. State rules, don't explain them.

Being too vague. "Write good code" is not an instruction. "Follow clean code practices" is not actionable. Compare: "Use early returns instead of nested if-else blocks." That's specific. Claude can follow it. Vague instructions get vague results.

Not updating it. Your CLAUDE.md should evolve with your project. When you catch Claude making a mistake, ask yourself: could a rule have prevented this? If yes, add the rule. When you change your stack or conventions, update the file. A stale CLAUDE.md is worse than no CLAUDE.md, because it gives Claude confidently wrong instructions.

Putting documentation in it. CLAUDE.md is not your project wiki. It's not where you explain how your authentication system works or document your API endpoints. It's a set of instructions for how to write code in this project. If Claude needs to understand your auth system, it can read the code. What it can't infer from code is your preferences, your conventions, and your constraints.

Duplicating linter rules. If ESLint already enforces something, you don't need to put it in CLAUDE.md. Claude will see the linting errors and correct itself. Focus on the rules that aren't machine-enforced -- the conventions that live in your team's heads and in PR review comments.

Nested CLAUDE.md in Practice

My portfolio repo has CLAUDE.md files in src/app/, src/components/os/, src/hooks/, and src/stores/. Each one gives Claude directory-specific context without bloating the root file.

Why bother with this level of granularity? Because different parts of a codebase have different conventions. The components in src/components/os/ are the macOS desktop simulator -- they have specific patterns for window management, drag behavior, and z-index handling that don't apply anywhere else in the project. The stores in src/stores/ use Zustand with a particular slice pattern. The hooks have their own naming and return-type conventions.

If I put all of this in the root CLAUDE.md, it would be enormous. And most of the instructions would be irrelevant most of the time. If Claude is editing a blog post, it doesn't need to know about window z-index conventions. If it's working on a Zustand store, it doesn't need MDX blog post rules.

Nested CLAUDE.md files solve this naturally. Claude only loads the ones that are relevant to the directory it's working in. The context stays lean and focused. You get specificity without bloat.

The pattern I use is simple. The root CLAUDE.md has project-wide rules that always apply. Each subdirectory CLAUDE.md has rules that only matter when working in that part of the codebase. There's no duplication between them.

How to Start

If you don't have a CLAUDE.md yet, here's how I'd approach writing one.

Start a Claude Code session without one. Work normally for a while. Every time you have to correct Claude, every time it makes a wrong assumption, every time it reaches for the wrong tool or the wrong pattern -- write it down. Those corrections are your rules.

After a few sessions, you'll have a list of ten to twenty things Claude keeps getting wrong. That list is your first CLAUDE.md. Format it as bullet points under a few headers. Keep it under 100 lines. Commit it to your repo.

Then iterate. Every few sessions, review the file. Are there rules Claude never violates? Those can probably be removed; they might be things Claude already knows from the codebase structure. Are there new mistakes that keep happening? Add rules for those. Your CLAUDE.md should converge toward the minimal set of instructions that prevent the maximum number of mistakes.

The Compounding Effect

Here is why I think CLAUDE.md is the most important file in your repo, at least if you use Claude Code regularly.

Every other improvement to your AI-assisted workflow is per-session. Writing a better prompt is a one-time benefit. Structuring your request more clearly helps for that one request. But CLAUDE.md compounds. Every rule you add prevents that mistake in every future session. The better your CLAUDE.md gets, the fewer corrections you need to make, the fewer cycles you waste, the more you can trust Claude's output without babysitting it.

It's the closest thing to "training" Claude Code on your codebase without actually fine-tuning a model. You're not changing the weights. You're changing the context. And because Claude reads the context fresh every session, your instructions never decay. They're always there, always applied, always shaping the output.

I've gone from spending the first five minutes of every session re-establishing context to just starting work immediately. Combined with plan mode for complex tasks, Claude already knows the project. It already knows my preferences. It already knows the traps. That five minutes saved per session adds up to hours per week. And the quality of Claude's initial output is dramatically higher, which means fewer review cycles, fewer corrections, fewer "no, I meant the other thing" moments.

A well-written CLAUDE.md is a one-time investment that pays dividends every time you open your terminal. Write one. Keep it short. Keep it specific. Update it when your project changes. It's the highest-leverage thing you can do to make Claude Code actually useful.