I maintain CLAUDE.md files across four production applications: ResolveNXT (a DME ERP platform), Showcase (a youth athlete organizational tool), The Positivity App (a Christian news platform), and Jim Flynn (an AI agent framework). Every one of those files has been rewritten at least three times. The versions that work look nothing like the versions I started with.
The difference between a good CLAUDE.md and a bad one isn't length or detail—it's whether the file changes what Claude actually does. A good CLAUDE.md eliminates entire categories of review comments. A bad one gets ignored because it's either too vague to be actionable or so long that the important rules get buried in noise.
Here's what I've learned about building CLAUDE.md files that actually change outcomes.
What CLAUDE.md Actually Is (and Isn't)
CLAUDE.md is a markdown file that Claude reads at the start of every session. It lives in the root of your repository and gives Claude project-specific context—your stack, your conventions, your commands, your quirks. Think of it as onboarding documentation for an AI engineer who joins your team every morning with zero memory of yesterday.
What it is not: a replacement for good code, well-named functions, or clear architecture. If your codebase is a mess, CLAUDE.md won't save you. It amplifies what's already there. Clean conventions become consistently followed conventions. Sloppy patterns become consistently sloppy patterns. Fix the code first, then document the conventions.
There are three scope levels. A user-wide file at ~/.claude/CLAUDE.md that applies to every project you work on—good for personal preferences like commit message style or your preferred test runner. A project file at ./CLAUDE.md or./.claude/CLAUDE.md that's shared with your team via git. And a local file at CLAUDE.local.md for your personal project notes that stay out of version control.
The Three Sections That Matter: Why, What, How
After iterating on these files across four codebases, I've landed on a structure that works. Every effective CLAUDE.md answers three questions:
Why does this project exist? This is the section most people skip, and it's the most important one. When Claude knows that ResolveNXT is a DME ERP platform used by durable medical equipment companies to manage billing, inventory, and compliance, it makes fundamentally different decisions than when it thinks it's working on a generic CRUD app. Domain context shapes everything—variable names, error messages, validation rules, even which edge cases to handle.
What is the technical stack? List your framework, language version, key dependencies, and project structure. Be specific. Don't say “we use React.” Say “Next.js 14 App Router with TypeScript, Tailwind CSS, Prisma ORM with PostgreSQL, and NextAuth for authentication.” The more precise you are here, the fewer incorrect assumptions Claude makes about imports, file paths, and API patterns.
How should Claude work in this codebase? This is where you document conventions that Claude can't infer from the code alone. Your test command. Your lint configuration. Your branch naming convention. Your commit message format. Whether you prefer named exports or default exports. Whether errors should be thrown or returned. These are the rules that, when followed, make AI-generated code indistinguishable from human-written code.
The 60-Line Rule
Here's something most people learn the hard way: the longer your CLAUDE.md, the less of it Claude follows. This isn't a bug—it's how attention works. When you have 300 lines of instructions, important rules get lost in the noise. Claude doesn't intentionally ignore your instructions. The signal-to-noise ratio just drops below the threshold where every instruction gets equal weight.
I aim for under 60 lines per CLAUDE.md. If I can't fit everything in 60 lines, that's a signal that I'm over-specifying. The question I ask for every line: “Does Claude get this wrong without this instruction?” If Claude already follows a convention correctly—because it inferred it from your existing code or because it's a widely-adopted standard—delete that line. It's taking up space that could go to something Claude actually needs to be told.
For context that's important but not needed on every task, use progressive disclosure. Instead of putting your entire API schema in CLAUDE.md, write: “API routes follow the pattern in app/api/README.md—read it before modifying any endpoint.” Claude is good at following breadcrumbs. Let it pull context on demand instead of front-loading everything.
Real Examples from Our Codebases
Let me show you what actually goes into our CLAUDE.md files. These aren't hypothetical —they're patterns pulled from production.
ResolveNXT (DME ERP Platform): The CLAUDE.md specifies that all database queries must go through Prisma—no raw SQL. It documents the multi-tenant architecture pattern where every query must include an organizationId filter. It lists the test command (npm run test) and the lint command (npm run lint). It specifies that all API routes must include authentication middleware and rate limiting. Twenty-two lines. That's it.
Showcase (Youth Athlete Platform): The CLAUDE.md focuses on data privacy —every component that displays user data must check age verification status first. It specifies the image handling pipeline (all uploads go through a resize service before storage). It documents the role hierarchy: athlete, parent, coach, organization admin. Eighteen lines.
The Positivity App: The CLAUDE.md specifies content moderation rules —all user-submitted content must pass through a moderation queue. It documents the push notification pipeline and the content caching strategy. It notes that all scripture references must use a consistent citation format. Fifteen lines.
Jim Flynn (AI Agent Framework): This one's the longest at forty lines because it has the most non-obvious conventions. It documents the agent lifecycle (init, plan, execute, reflect), the message passing protocol between agents, and the plugin architecture. It specifies Google-style docstrings, PEP 484 type hints on every function, and 95% docstring coverage enforced via interrogate. Complex project, more instructions needed—but still well under 60 lines.
The Rules That Earn Their Place
Not every rule belongs in CLAUDE.md. Here's the filter I use: a rule earns its place only when Claude makes an actual mistake that the rule would have prevented. Not a hypothetical mistake. Not a “just in case” rule. A real incident where generated code was wrong and a specific instruction would have prevented it.
Every rule in our CLAUDE.md files traces back to a real PR comment. When I found myself writing the same review comment three times—“use the organizationIdfilter on every query”—that became a CLAUDE.md rule. When Claude kept generating default exports in a codebase that uses named exports, that became a rule. When it kept importing from @/lib/db instead of @/server/db, that became a rule.
This approach keeps the file lean and every line impactful. If you start with hypothetical rules, you end up with 200 lines and Claude follows maybe 60% of them. If you start with zero rules and add them reactively, you end up with 20 lines and Claude follows 95% of them.
Pair Prohibitions with Directions
One pattern I see constantly in bad CLAUDE.md files: negation-only rules. “Never use any types.” “Don't use --legacy-peer-deps.” “Never commit directly to main.”
The problem with telling Claude what not to do is that it doesn't know what to do instead. If you say “never use any types,” Claude might useunknown, might use a generic, might use a type assertion—and only one of those is what you actually want. Better: “Use explicit TypeScript types on all function parameters and return values. Prefer generics over any orunknown.” Now Claude knows exactly what to do, not just what to avoid.
Every prohibition in your CLAUDE.md should have a corresponding direction. “Don't use raw SQL” becomes “All database queries go through Prisma. Seelib/db.ts for the client setup.” “Don't useconsole.log” becomes “Use the structured logger at lib/logger.ts for all logging.”
CLAUDE.md vs. Hooks: Know the Difference
Claude Code introduced hooks—deterministic shell commands that run at specific events like pre-commit or post-push. Understanding when to use CLAUDE.md versus hooks is critical for a reliable workflow.
CLAUDE.md is for anything that requires judgment. “Prefer named exports” is a CLAUDE.md instruction because there are legitimate exceptions. “Run the full test suite before submitting a PR” is a CLAUDE.md instruction because Claude needs to understand when tests are relevant versus when it's making a documentation-only change.
Hooks are for anything that must happen every single time, no exceptions. Linting before commit. Type-checking before push. Formatting on save. These aren't judgment calls —they're mechanical verifications. Put them in hooks, not CLAUDE.md, and they'll execute regardless of what Claude decides.
The combination is powerful. CLAUDE.md handles the “how to think about this codebase” layer. Hooks handle the “this must pass before anything ships” layer. Together, they create a workflow where AI has the context to write good code and the guardrails to catch it when it doesn't.
Maintaining It Over Time
A CLAUDE.md file isn't a “set it and forget it” artifact. It needs maintenance, just like any other piece of your codebase. Here's what works for us:
Every few weeks, I ask Claude to review the CLAUDE.md itself. “Review this file and tell me which rules are redundant, which conflict with each other, and which you already follow without being told.” The answers are illuminating. Rules accumulate over time, and some become obsolete as the codebase evolves. A quarterly cleanup keeps the file effective.
When a new team member joins (human or AI session), pay attention to the first few PRs. If the same feedback keeps coming up, that's a missing CLAUDE.md rule. If a CLAUDE.md rule keeps getting ignored, it's either badly written or no longer relevant. Both situations are signals to update the file.
The /init command in Claude Code generates a starter CLAUDE.md based on your project structure. It's a reasonable starting point but treat it as a draft, not a finished product. The generated file captures obvious patterns but misses the non-obvious conventions that make your codebase yours.
Build Your CLAUDE.md Now
Use our interactive CLAUDE.md Builder to generate a production-ready file for your project. Answer a few questions about your stack, conventions, and workflow—get a file you can drop into your repo today.
Phillip Roberts
CEO of R Software & Consulting, fractional CTO at Resolve Systems, and CTO & co-founder of Project Ethos. He leads development across ResolveNXT, Showcase, The Positivity App, and the Jim Flynn AI framework.