The Complete Guide to CLAUDE.md — How to Unify Your Team's AI Coding Conventions in a Single File
Have you ever introduced an AI coding tool to your team, only to find that every team member gets completely different code styles from the AI? I started out optimistic, thinking "the AI will figure it out," but ended up making the same comments over and over in code reviews. Someone would use npm install, someone else would use .then() instead of async/await, and even the architecture layer separation was inconsistent. But after the entire team adopted a single CLAUDE.md file, those repetitive code review comments dropped noticeably. The problem wasn't that the AI was bad. Nobody had ever told the AI about the team's conventions.
The CLAUDE.md file that Claude Code automatically reads when starting a session is the answer to this problem. Instead of explaining "our project uses pnpm, business logic in NestJS must go only in the Service" at the start of every session, one well-crafted file unifies the entire team's AI collaboration. CLAUDE.md is not just a configuration file — it is a collaboration contract between your team and AI, a project constitution.
This article covers everything from the core principles of CLAUDE.md to monorepo layered configuration and the pitfalls most commonly encountered in practice, drawing from real field experience. By the end, you'll be ready to apply it to your team's repository today.
Core Concepts
The Fundamental Reason CLAUDE.md Is Necessary
LLMs fundamentally lose all memory when a conversation ends. Even if you tell the AI "our team uses pnpm" today, it won't know again when you open a new session tomorrow. CLAUDE.md is the structural solution to this forgetting problem.
Claude Code automatically merges and loads files from the following three locations at session start:
| Location | Example Path | Scope |
|---|---|---|
| Global | ~/.claude/CLAUDE.md |
Common to all projects |
| Project root | ./CLAUDE.md |
Shared across the team (git committed) |
| Subdirectory | ./packages/api/CLAUDE.md |
Limited to a specific module or package |
The global file is where you put personal preferences like "I always prefer 2-space indentation," while the project root file is the core that holds the rules the entire team has agreed on.
Three Axes the File Must Address
At first, I just listed commands one after another, and repeatedly ran into situations where the AI ignored rules on edge cases. That's when I realized context matters, not just commands. A well-crafted CLAUDE.md must balance three axes: WHAT, WHY, and HOW.
- WHAT: Tech stack, project structure, key file locations
- WHY: Background behind key design decisions ("why we use Zustand instead of Redux")
- HOW: Build and test commands, branch strategy, PR writing tips
WHY is the most commonly omitted part, and listing rules without background increases the likelihood that the AI will ignore them on edge cases. A single line like "we keep CommonJS for legacy compatibility" prevents the AI from arbitrarily migrating to ESM.
Context Engineering: A concept that goes beyond simple prompt engineering — systematically designing and managing the context that a team provides to AI. It has become a major DevEx discourse since 2025, and
CLAUDE.mdis regarded as a core implementation of this concept.
The Physical Limits of the Context Window
Let me clarify one term before moving on. A context window is the maximum length of text an LLM can process at once. Just as you can't read an entire book in one sitting, AI also has a physical limit on the amount of information it can process in a single session. Because CLAUDE.md occupies part of this precious space, size management is important.
Honestly, you'll be tempted to put everything into CLAUDE.md. But Claude Code's system prompt already pre-occupies a significant number of internal instructions, and from field experience, when rules pile up excessively, important instructions start getting quietly ignored. If the file exceeds 500 lines, critical rules can get diluted. Think of context space as operating like a limited set of "slots."
Caveats Worth Knowing Before the Examples
I'd love to show you only the good parts first, but it would be good to ask yourself these two questions before introducing it to your team:
- "Who will update this file?" — If the codebase changes but
CLAUDE.mdisn't updated, it can be worse than having no file at all. The AI treats outdated rules as truth. - "Will you just use the file auto-generated by
/init?" — A pattern confirmed across multiple cases: context files auto-generated by LLMs can actually lower task quality. Use auto-generation only as a draft, and be sure to have the team review it directly.
Practical Application
It helps to first identify which structure fits your situation.
| Situation | Recommended Approach |
|---|---|
| Small team or single-app project | Example 1 (monorepo layered configuration) |
A single CLAUDE.md has grown too large |
Example 2 (.claude/rules/ directory structure) |
| Want to separate team rules from personal preferences | Example 3 (CLAUDE.local.md) |
Example 1: Monorepo Layered Configuration
For a monorepo where a NestJS backend and Next.js frontend coexist, the following structure is effective. While this explanation uses NestJS and Next.js as examples, the principle of layer separation itself applies equally to any framework — Django, Spring, Rails, etc.
/
├── CLAUDE.md ← Project-wide rules
├── apps/
│ ├── api/
│ │ └── CLAUDE.md ← NestJS-specific rules
│ └── web/
│ └── CLAUDE.md ← Next.js-specific rules
└── packages/
└── shared/
└── CLAUDE.md ← Shared library rulesThe root CLAUDE.md contains only the minimum rules every team member needs to know, delegating the details to child files.
# Project-wide Rules (root CLAUDE.md)
## Tech Stack
- Node.js 20 LTS, TypeScript 5.x strict mode
- Package manager: pnpm (npm and yarn are prohibited)
- Monorepo management: Turborepo
## Build & Test
- Build: `pnpm build`
- Test: `pnpm test`
- Lint: `pnpm lint`
## Code Style
- 2-space indentation
- Use async/await (avoid .then() chaining)
- Explicit return type declarations required
## Git Workflow
- Branches: feature/*, fix/*, chore/*
- Commits: imperative mood in English or Korean
- PR merge: squash merge by default
## Detailed Rule References
- See apps/api/CLAUDE.md (NestJS detailed rules)
- See apps/web/CLAUDE.md (Next.js detailed rules)# NestJS-specific Rules (apps/api/CLAUDE.md)
## Architecture Layers
- Controller: handles request/response transformation only, no business logic
- Service: where all business logic lives
- Repository: abstracts DB access
## Input Validation
- All input must be validated via DTOs with class-validator decorators
- Direct use of primitive types in @Body(), @Param() is prohibited
## Exception Handling
- Use custom exception filter
(reference: src/common/filters/http-exception.filter.ts)
- Throw domain exceptions in the service layer; convert to HTTP status codes in the filter
## Why this approach?
When business logic leaks into Controllers, writing tests becomes difficult
and logic duplication arises when supporting multiple entry points
(REST, gRPC, CLI). The layer separation principle applies equally to any framework.| Section | Role | Location |
|---|---|---|
| Tech stack & commands | Mechanical rules for immediate reference | Root |
| Architecture decisions + WHY | Team philosophy and background explanation | Root or child |
| Per-module detailed rules | Scoped, saves context | Subdirectory |
Example 2: Managing with a .claude/rules/ Directory Structure
If a single file is becoming too large, you can distribute it into a .claude/rules/ directory. After our team adopted this structure, the confusion of "where should I add this rule?" dropped significantly.
.claude/
└── rules/
├── constitution.md ← Project-wide principles (non-negotiable)
├── api.md ← Rules applied to apps/api/**
├── database.md ← DB migration and query rules
├── testing.md ← Testing conventions
└── security.md ← Security guidelines (auth, authorization, input validation)# constitution.md — Project-wide Principles
## Tech Stack
- Node.js 20 LTS, TypeScript 5.x strict mode
- Package manager: pnpm (npm and yarn are prohibited)
## Absolute Principles (no exceptions)
### 1. Direct DB access must go through the Repository layer only
### 2. Environment variables must be accessed only through the config module (direct process.env access is prohibited)
### 3. External API calls must be abstracted into dedicated service classes
## Why these principles?
Early in the project, there was a deployment incident caused by direct environment variable access.
There was also a case where the production DB was accidentally accessed from a test environment.
These principles emerged from those experiences.# security.md — Security Guidelines
## Input Validation
- SQL queries must use only ORM (TypeORM) parameter binding
- Never insert user input directly into HTML (XSS prevention)
- File uploads: double validation with extension + MIME type
## Authentication & Authorization
- JWT token validation must happen only in AuthGuard
- Permission checks must occur before entering the service layer
## Sensitive Information
- Never output passwords, tokens, or personal information in logs
- Never expose internal stack traces in error messages (production)Example 3: Separating Personal Preferences with CLAUDE.local.md
When you want to separate team rules from personal preferences, CLAUDE.local.md is a good option. Add this file to .gitignore so it doesn't get pushed to the team repository.
# CLAUDE.local.md — My personal preferences (not git-tracked)
## Response Style
- When explaining code, always show the TypeScript type inference process
- Error messages should always be in Korean
## Working Style
- Before suggesting refactoring, always confirm the intent of the current code first
- If the scope of file changes exceeds 100 lines, ask before proceeding# Add to .gitignore
CLAUDE.local.mdPros and Cons Analysis
Before introducing it to your team, I hope the table below helps you judge "does our team actually need this right now?"
Advantages
| Item | Description |
|---|---|
| Team consistency | All team members automatically provide the same conventions to the AI — reduces code review burden |
| Version control | Committed to git, enabling iterative team improvement with history tracking |
| Hierarchical scoping | Root/subdirectory separation enables optimized rule application for monorepos |
| Local override | CLAUDE.local.md separates personal preferences from team rules |
| Immediate start | /init command analyzes existing project structure and auto-generates a draft |
| Cross-tool compatibility | Managing alongside AGENTS.md can also cover Copilot, Cursor, and other tools |
Disadvantages and Caveats
| Item | Description | Mitigation |
|---|---|---|
| Context drift | Content that was accurate when written can become misleading after codebase changes | Set quarterly review cycles, assign a maintenance owner |
| Size limit | Overly large files reduce adherence to important rules (500 lines feels like the inflection point) | Keep only essentials in root, distribute details to child files |
| LLM auto-generation trap | Files auto-generated by /init can actually reduce task completion rates |
Use auto-generation only as a draft; team must always review and edit |
| Token cost | Detailed files increase inference token usage | In API-billed environments, evaluate cost vs. benefit |
| Team alignment cost | Adding or changing rules requires team discussion | Manage the same way as PR review processes |
Context Drift: The phenomenon where, over time, a gap develops between the content of
CLAUDE.mdand the actual codebase. If you migrate your testing framework from Jest to Vitest but don't update the file, the AI will keep generating Jest-based code.
The Most Common Mistakes in Practice
These three mistakes are ones I've made myself and frequently observe in teams.
1. Pasting code snippets directly
If you put long code examples in the file saying "always write it like this," when that code gets refactored or deleted, the AI will follow the outdated pattern. It's much safer to point to a file path and reference location.
# Bad example — pasting code directly into the file
## Exception Handling
Always handle it like this:
throw new HttpException('Not found', HttpStatus.NOT_FOUND);
# Recommended example — referencing by file path
## Exception Handling
Use a custom exception filter.
Reference: src/common/filters/http-exception.filter.ts2. Over-specifying rules that linters and formatters can already handle
Duplicating rules that ESLint and Prettier already enforce in CLAUDE.md pushes the genuinely important architecture rules to the back.
# Bad example — duplicating rules the linter handles
- Indentation is 2 spaces
- Always include semicolons
- Use single quotes for strings
- Trailing commas required
# Recommended example — only mention that tools handle it
- Code style follows .eslintrc and .prettierrc settings
- CLAUDE.md only specifies architecture and domain rules that tools cannot check3. Leaving /init auto-generated files untouched long-term
/init is a tool for quickly establishing a starting point, not a finished product. Leaving an auto-generated file as-is for an extended period can actually hinder team collaboration. Right after auto-generation, the whole team must review the content and correct anything that doesn't match the actual project situation.
Closing Thoughts
CLAUDE.md is a living document where the habit of maintaining it matters more than the moment of writing it. There's no need to try to make it perfect from the start. Just as a constitution matures through amendments, this file should become more accurate and more substantial as the team's experience accumulates. The key is building a culture where every time the team collaborates with AI and thinks "the AI went astray because this rule wasn't here," the file gets updated.
Three steps you can start right now:
-
Auto-generate a draft: Open Claude Code in your project root terminal and run the
/initcommand. It will analyze the existing codebase and create aCLAUDE.mddraft. It's recommended to open that file and review it line by line to check for anything that doesn't match your team's actual situation. -
Fill in the core 3 sections first: Start with build and test commands (WHAT), the architecture rules most frequently violated along with their background (WHY), and branch and commit conventions (HOW). Starting within 200 lines is recommended.
-
Integrate into the team PR process: Try introducing a process where
CLAUDE.mdchanges go through the same review as regular code PRs. Adding a "context drift check" item to sprint planning for a full file review once a quarter can also be a great help.
Next article: AGENTS.md vs CLAUDE.md — I'll share a real case where conflicts arose while synchronizing the two files in a multi-agent environment, along with a method for managing cross-tool context files with a single source of truth.
References
Official Documentation
- Best Practices for Claude Code | Claude Code Docs
- Using CLAUDE.MD files: Customizing Claude Code for your codebase | Claude Blog
- How Anthropic teams use Claude Code (PDF)
Practical Guides
- Writing a good CLAUDE.md | HumanLayer Blog
- How to Write a Good CLAUDE.md File | Builder.io
- Writing the Best CLAUDE.md: A Complete Guide | DataCamp
- CLAUDE.md Best Practices: 10 Sections to Include | UX Planet
- Claude Code in a Monorepo: The Complete Setup Guide | The Prompt Shelf
- CLAUDE.md, AGENTS.md & Copilot Instructions: Configure Every AI Coding Assistant | DeployHQ
- AGENTS.md vs CLAUDE.md: What's the Difference and When to Use Each | The Prompt Shelf
- The Complete Guide to AI Agent Memory Files | Medium
- Mastering Project Context Files for AI Coding Agents | EclipseSource
- Context Engineering for Teams: A Practical Implementation Guide | Packmind
- rulesync: Unified rules management for Claude Code, Gemini CLI, and Cursor | DEV Community