Claude Code starts every session knowing nothing about your project. It knows TypeScript, it knows React, it knows Next.js — but it does not know that your team banned useEffect for data fetching, that your monorepo uses pnpm not npm, that your API routes always return a typed ApiResponse<T> wrapper, or that you migrated from Pages Router six months ago and any Pages Router patterns are wrong.
Without that context, Claude fills the gaps with defaults. The defaults are generic — correct for some average project, wrong for yours.
CLAUDE.md is the mechanism that fixes this. One file in your repo root, read automatically at the start of every Claude Code session. But most CLAUDE.md files developers write are nearly useless — full of lines Claude already knows that add no signal at all.
This post shows the exact difference between a generic CLAUDE.md (that does nothing) and a specific one (that eliminates generic answers), with before/after examples of how Claude actually responds differently.
Why Claude Code gives generic answers
Claude Code's context window resets every session. The model has no memory of what you worked on yesterday, what correction you made last week, or what convention you explained three sessions ago. It walks into your project cold every time.
When Claude does not know something about your project, it does not ask — it assumes. And those assumptions come from training: the most common patterns in the open-source code it was trained on. The most common test runner. The most common HTTP client. The most common folder structure.
That is why the generic answers feel like boilerplate. They are. Claude is returning the statistical average of its training data applied to your question, because it does not know what your specific project actually looks like.
CLAUDE.md changes this by giving Claude project-specific facts before it starts answering. The key word is specific. Generic facts about programming do not help. Project-specific facts about your codebase, your decisions, and your constraints do.
Claude for Work
Use Claude as a thought partner for writing, research & decisions — no coding required. 2 live sessions with Yash Thakker.
Claude for Work is a 2-day live workshop on using Claude to supercharge your daily work — writing, research, analysis, and decision-making — without any coding required. Learn how to set up Claude Projects with custom instructions, run deep-research sprints, co-write documents that sound like you, and build repeatable prompt systems for your team. August 1–2, 2026. Hosted by Yash Thakker, founder of AISOLO Technologies, instructor to 350,000+ students.
Includes 1-year access to all session recordings, a personal prompt library, Discord community access, and a certificate of completion. No coding or technical background required. Designed for managers, marketers, founders, and writers.
The specificity test
Before writing any line in your CLAUDE.md, ask one question:
Would removing this line cause Claude to make a specific, identifiable mistake in this project?
If yes: keep it. This line is doing real work.
If no or maybe: delete it. This line is noise that competes with your signal.
Here is the test applied to real examples:
| Line | Passes? | Why |
|---|---|---|
This is a Next.js app with TypeScript. | ❌ | Claude can read package.json. This is inferrable. |
We use Next.js App Router. Never suggest Pages Router patterns. | ✅ | Claude would otherwise suggest both. This prevents a class of wrong answers. |
Write clean, readable code. | ❌ | Claude already tries to do this. This instruction changes nothing. |
All API responses must use the ApiResponse<T> wrapper in lib/api.ts. | ✅ | Claude will not infer this wrapper from the codebase unless you tell it. |
Use pnpm. Never suggest npm or yarn commands. | ✅ | Claude defaults to npm. This prevents wrong install commands every time. |
Think step by step before answering. | ❌ | Generic instruction that does not change measurable behavior. |
We ban useEffect for data fetching — use React Query instead. | ✅ | Claude will suggest useEffect by default. This prevents a common wrong pattern. |
Every line in your CLAUDE.md competes for attention in a context window. The lines that tell Claude things it can infer from the code are wasting budget that should go to things it cannot.
Before and after: what actually changes
Here is the same question asked with a generic CLAUDE.md versus a specific one.
Question asked: "I need to fetch the user profile when this component mounts."
With a generic CLAUDE.md:
# Project
This is a Next.js TypeScript app. Write clean, readable code.
Follow React best practices.
Claude's answer:
import { useEffect, useState } from 'react';
export function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(setUser);
}, [userId]);
// ...
}
That is the statistical average answer. It will work. It is also wrong for a codebase that bans useEffect for data fetching and uses React Query.
With a specific CLAUDE.md:
# Stack
- Next.js 15 App Router (never Pages Router)
- TypeScript strict mode
- pnpm workspace
# Data fetching rules
- NO useEffect for data fetching, ever. Ban enforced by ESLint.
- Use React Query for all client-side fetching. Query client is in providers/QueryClientProvider.tsx.
- API responses always use the ApiResponse<T> wrapper from lib/api.ts — never assume raw JSON shape.
# Commands
- pnpm dev — start dev server
- pnpm test — vitest
- pnpm lint — ESLint + TypeScript check
Claude's answer:
import { useQuery } from '@tanstack/react-query';
import { getUserProfile } from '@/lib/api';
export function UserProfile({ userId }: { userId: string }) {
const { data: user, isLoading, error } = useQuery({
queryKey: ['user', userId],
queryFn: () => getUserProfile(userId),
});
// ...
}
Same question. Different answer. The second one fits your codebase. The first does not.
The anatomy of a CLAUDE.md that eliminates generic answers
1. Commands (highest ROI section)
The single highest-value section in any CLAUDE.md is the exact commands that work in this specific repository. Not "run tests" — the actual command string.
## Commands
- pnpm dev — start the dev server on :3000
- pnpm test — vitest (unit and integration)
- pnpm test:e2e — Playwright (requires dev server running)
- pnpm lint — ESLint + tsc --noEmit
- pnpm db:migrate — runs Prisma migrations
- pnpm db:studio — opens Prisma Studio
Without this, Claude will suggest npm run test, npm start, or guess at script names. With it, Claude suggests the right command every time because you told it exactly what to run.
2. Stack and version constraints
List only the things that would cause wrong suggestions if Claude assumed the default:
## Stack
- Next.js 15, App Router only — never suggest Pages Router
- React 19
- TypeScript 5.x with strict: true
- Tailwind CSS 4 — utility-first, no CSS modules
- Prisma + PostgreSQL (Neon serverless)
- pnpm (not npm, not yarn)
- Vitest for unit tests, Playwright for e2e
Notice: no "we use JavaScript" or "this is a web app." Claude does not need to be told things it can read from package.json. Only include things that make Claude choose differently.
3. Banned patterns (with reasons)
This is where most CLAUDE.md files fail. Developers list what is banned but not why, or they list bans Claude would already follow. The reason matters because it lets Claude apply the constraint correctly to edge cases:
## Patterns we don't use
- NO useEffect for data fetching — ESLint rule enforces this. Use React Query.
- NO default exports except for Next.js pages/layouts — named exports everywhere else. Reason: tree-shaking and import refactoring.
- NO inline styles — Tailwind only. Exception: dynamic values that can't be expressed as Tailwind classes use CSS variables.
- NO fetch() directly in components — always use the typed wrappers in lib/api.ts.
- NO console.log in committed code — use the logger in lib/logger.ts (structured JSON).
4. Architecture decisions
The most underused section. The things Claude cannot infer from code because they are about why things are structured the way they are:
## Architecture
- Auth lives entirely in middleware.ts — never add auth checks inside individual route handlers.
- All server-side database calls go through lib/db.ts — never import PrismaClient directly in components or routes.
- Email sending is async via a queue (Bull + Redis) — never send email synchronously in a request handler.
- The /api/admin/* routes require the admin role checked by the middleware, not inline.
Each of these prevents a category of wrong architecture suggestions. Without them, Claude will make architecturally inconsistent choices that pass TypeScript checks but violate your design contracts.
5. Test strategy
## Testing
- Unit tests: colocated with source files as *.test.ts
- Integration tests: tests/integration/ — test actual database, no mocks
- E2E: tests/e2e/ — Playwright, runs against localhost:3000
- Never mock the database in integration tests — we got burned by mock/prod divergence.
- Test file naming: describe('ComponentName', () => ...) matching the exported name.
The "never mock the database" line is a real example. Without it, Claude will reach for Jest's database mock helpers by default. With it, Claude writes integration tests against the real connection string.
What to cut from your CLAUDE.md
Most developers over-fill their CLAUDE.md with things Claude already knows or things a linter enforces deterministically. These lines consume context budget without adding signal:
Cut these:
- "Write clean, maintainable code"
- "Follow the single responsibility principle"
- "Add comments to complex logic"
- "Use TypeScript types everywhere" (if you have
strict: true, the compiler handles this) - "Prefer const over let" (your linter does this)
- Anything that applies to any project in your language
- Long code snippets — reference the file path instead
Keep these:
- Commands that only work in this repo
- Version constraints where the wrong version changes the API
- Banned patterns that would pass type checking
- Architecture rules that span multiple files
- Business domain terms and their meaning
Length matters more than most developers think
Research across frontier models shows accuracy degrades as input grows. CLAUDE.md files over roughly 200 lines are not just not-helpful — they actively hurt quality because the high-signal lines get diluted.
The practical implication: if your CLAUDE.md is getting long, run the specificity test on every line and delete everything that fails. A 40-line specific CLAUDE.md outperforms a 300-line generic one.
If you have genuinely large reference material (API contracts, database schema, detailed architecture diagrams), do not paste it into CLAUDE.md. Reference it:
## Key files to understand first
- @/prisma/schema.prisma — full database schema
- @/lib/api.ts — typed API wrappers and ApiResponse<T> type
- @/middleware.ts — auth and routing logic
Claude Code will read those files when the context is relevant, without loading them on every session start.
How to get started: /init then iterate
Run /init in Claude Code. It will scan your project structure, package.json, config files, and README and generate a starter CLAUDE.md. That file will be about 70% generic boilerplate.
Then apply the specificity test to every line it generated:
- Keep lines about your specific commands
- Delete lines that describe general best practices
- Add your banned patterns with reasons
- Add your architectural constraints
- Add anything that caused a wrong suggestion in the last week of use
CLAUDE.md is a living document. When Claude gives you a wrong answer — suggests the wrong pattern, the wrong command, the wrong architecture — that is a gap in your CLAUDE.md. Add the specific rule that would have prevented it.
Within a few weeks of iterating, your CLAUDE.md will encode all the project-specific knowledge that a new engineer joining your team would need a week of onboarding to learn. Claude walks into every session with that knowledge already loaded.
The compound effect across a team
A committed CLAUDE.md is not just your personal context — it is shared project knowledge. Every team member running Claude Code gets the same project-specific answers. Junior engineers get the same architecture guidance as seniors. Claude's suggestions stay consistent across the team rather than varying based on how much context each person remembers to re-explain.
If your team is using Claude Code without a shared, committed CLAUDE.md in version control, you are each re-teaching Claude your project conventions in every session, independently, and getting inconsistent results. The fix is a single file push away.
The one-line summary
Every line in your CLAUDE.md should answer one question: does removing this line cause Claude to make a specific mistake in my project? If yes, it belongs. If not, it does not. That test turns a useless CLAUDE.md into one that actually eliminates generic answers — because it replaces Claude's statistical defaults with your actual project's constraints.
Want to generate a CLAUDE.md for your project? Use the free CLAUDE.md builder on explainx.ai to scaffold one based on your stack and conventions.