CLAUDE.md & Project Memory
CLAUDE.md gives Claude Code project-specific instructions that persist across sessions. Combined with rules, user memory, and auto-memory, it creates a layered instruction system for consistent agent behavior.
CLAUDE.md & Project Memory
Why Project Instructions Matter
Every time Claude Code starts a new session, it has zero memory of your project. It does not know your stack, your conventions, your file structure, or the architectural decisions you spent weeks debating. It does not know that you use kebab-case for agent IDs, that all timestamps are Unix milliseconds, or that you never send an email without an unsubscribe link. Without instructions, it will make reasonable guesses. Reasonable guesses are not good enough for production systems.
You will notice this immediately. On the first run, Claude Code might restructure a file in a way that contradicts your existing patterns. It might use a library you deliberately avoid. It might name things in a convention that clashes with everything else in the codebase. None of these are mistakes, exactly -- the agent is doing its best with zero context. But you will burn time correcting it, and the corrections will not carry over to the next session.
CLAUDE.md solves this. It is a markdown file you place at the root of your project. Claude Code reads it automatically at the start of every session. Think of it as the project's constitution -- the ground rules every session must follow. You write it once, update it as your project evolves, and every future interaction with Claude Code starts from a position of understanding rather than guessing.
This is not optional for serious work. If you are building anything beyond a toy project, you need a CLAUDE.md.
What Goes in CLAUDE.md
A good CLAUDE.md is specific, concrete, and organized. Here is what belongs in it.
Project Overview
Start with what the project is and what technologies it uses. This orients the agent immediately and prevents it from making wrong assumptions about your stack.
Architecture Decisions
Document the "why" behind your choices. "We use JSON flat files instead of a database because the data volume is low and we want zero infrastructure dependencies." Without this, the agent might helpfully suggest migrating to Postgres -- solving a problem you do not have while creating ones you do.
Conventions
Naming patterns, file organization, import styles, error handling approaches. Anything where you have a preference that differs from the general default. If your agent IDs are kebab-case, say so. If you use atomic writes for data stores, say so. The agent will follow whatever conventions it sees in your existing code, but explicit instructions are faster and more reliable than implicit pattern matching.
Do's and Don'ts
Hard rules that should never be violated. These are your guardrails -- the things that cause real damage if the agent gets them wrong. "Never send an email without an unsubscribe link." "Always validate email addresses before sending." "Discount codes must be between 5% and 25%." The more specific you are, the better.
Tool Usage
If you use MCP tools or have a custom tool server, explain which tools to prefer and how to use them correctly. "Check shouldAgentRun() before expensive operations." "Log all tool calls to the activity log." This prevents the agent from using tools in ways that bypass your safeguards.
Agent-Specific Guidance
If you run multiple agents, include role descriptions and key responsibilities. Each agent should understand its lane and stay in it.
Here is an example of a well-structured CLAUDE.md:
# AI University Growth System
## Stack
- Next.js 14 + TypeScript + Tailwind
- Data: JSON flat files in /data (no database)
- Agents: 15 autonomous agents via claude -p
- Tools: 52 MCP tools via custom MCP server
## Key Rules
- NEVER send an email without an unsubscribe link
- ALWAYS validate email addresses before sending
- Discount codes must be 5-25% (guardrail enforced)
- Check shouldAgentRun() before expensive operations
- Log all tool calls to activity log
## Conventions
- Agent IDs are kebab-case: "outreach", "reply-handler"
- Data stores use atomic writes (import from atomic-write.ts)
- All timestamps are Unix ms (Date.now())
- File paths relative to project root
## Architecture
- MCP server wraps all tools: src/mcp-server.ts
- Orchestrator spawns agents: src/lib/agent-sdk/orchestrator.ts
- Each agent gets context-injected prompts via --append-system-prompt
- Agents coordinate through shared data stores, not direct communication
This is twenty lines. It takes five minutes to write. It saves hours of corrections across every future session.
The Memory Hierarchy
CLAUDE.md is not the only way to give Claude Code instructions. There are four layers that compose together, from highest to lowest priority.
1. CLAUDE.md (Project Root)
This is the project-wide instruction file. It sits at the root of your repository and is read at the start of every Claude Code session in that project. Everything in CLAUDE.md applies to every interaction within that project.
This is where your most important rules live. Stack definition, key conventions, hard guardrails, architecture decisions. If a rule applies to the entire project regardless of what file you are working on, it goes in CLAUDE.md.
You can also place CLAUDE.md files in subdirectories. A CLAUDE.md in src/lib/agents/ would apply additional instructions when Claude Code is working on files in that directory. This is useful for large projects with distinct subsystems that have their own conventions.
2. .claude/rules/ (Scoped Rules)
The .claude/rules/ directory contains markdown files that Claude Code loads contextually. Each file describes when it should apply, and Claude Code loads the relevant ones based on what you are working on. If you are editing an agent file, agent-related rules get loaded. If you are editing email-sending code, email safety rules get loaded.
This keeps CLAUDE.md lean. Instead of stuffing every domain-specific guideline into one file, you split them into scoped rules that only appear when relevant. More on this in the next section.
3. User Memory (~/.claude/)
Your personal preferences live in ~/.claude/ in your home directory. These follow you across every project. If you always want TypeScript strict mode, or you prefer a particular code style, or you have default behaviors you want everywhere -- user memory is where those go.
User memory is lower priority than project instructions. If your personal preference says "always use tabs" but the project's CLAUDE.md says "use 2-space indent," the CLAUDE.md wins. This is the right behavior -- project conventions should override personal preferences when you are working in someone else's codebase.
4. Auto-Memory (.claude/projects/)
Claude Code automatically remembers things across sessions. When you correct it ("no, we use X pattern here, not Y"), it can store that correction in .claude/projects/ so it does not make the same mistake next session. This is automatic -- you do not need to manage it directly.
Auto-memory is the lowest priority layer. It captures corrections and preferences that emerge during normal work, filling gaps that your explicit instructions did not cover. Over time, it builds up a layer of project-specific knowledge that supplements your CLAUDE.md.
How They Compose
The layers stack. When Claude Code starts a session, it assembles instructions from all four layers. Higher layers override lower ones when there is a conflict. In practice, this means:
- CLAUDE.md has final say on project-level decisions
- Scoped rules add context-specific guidance without conflicting
- User memory applies your personal defaults where the project has no opinion
- Auto-memory fills in gaps from past corrections
This layering is what makes the system practical. You do not need to anticipate every possible instruction in CLAUDE.md. You set the critical rules explicitly, let scoped rules handle domain-specific guidance, and auto-memory catches everything else.
Scoped Rules with .claude/rules/
As your project grows, putting everything in CLAUDE.md becomes unwieldy. A 500-line instruction file is hard to maintain and wastes context tokens on rules that are irrelevant to the current task. Scoped rules solve this.
The .claude/rules/ directory contains markdown files, each focused on a specific domain. Claude Code loads them contextually -- only the rules relevant to what you are currently doing get included in the context.
Here is an example rule file:
<!-- .claude/rules/email-safety.md -->
# Email Safety Rules
When working with email-sending tools (send_email, save_outreach):
- ALWAYS include an unsubscribe link (use get_unsubscribe_link tool)
- Validate email format before sending
- Never send more than 50 emails in a single agent run
- Log every send attempt to the activity log
And another:
<!-- .claude/rules/data-stores.md -->
# Data Store Conventions
When reading or writing to JSON data stores:
- ALWAYS use atomicWrite() from src/lib/atomic-write.ts
- Never use fs.writeFileSync directly on data files
- Read the full store, modify in memory, write back atomically
- Include a version field in every store schema
The benefits are clear. Each rule file is focused and short. Rules only load when they are relevant, keeping the context window lean. Adding a new domain of rules does not bloat the main CLAUDE.md. And each file is independently maintainable -- you can update email rules without touching anything else.
A good rule of thumb: if a rule applies everywhere, put it in CLAUDE.md. If it applies only in specific contexts, put it in .claude/rules/.
Case Study: AI University's Instruction Architecture
The AI University runs 15 autonomous agents that handle outreach, content creation, lead scoring, competitor tracking, and more. Each agent runs as a claude -p subprocess, spawned by an orchestrator. The instruction architecture has three layers that work together.
Layer 1: Shared Rules (CLAUDE.md)
One CLAUDE.md at the project root contains rules that all agents follow. Stack definition, data conventions, guardrails, tool usage patterns. Every agent reads this because every agent spawns in the same project directory.
Layer 2: Agent-Specific Instructions (Orchestrator-Injected)
Each agent gets a personalized system prompt injected at runtime via --append-system-prompt. This is not part of CLAUDE.md -- it is built dynamically by the orchestrator's prompt pipeline. It includes the agent's role, personality, specific responsibilities, and contextual information about the current state of the system.
Here is how the orchestrator assembles each agent's full prompt:
// How agent instructions are assembled -- orchestrator.ts
const awareness = buildAwarenessIndex();
const ctx = buildAgentContext(agentId, awareness);
const systemPrompt = getAgentPrompt(
agentId,
awareness,
ctx.memory, // lessons, goals, strengths, weaknesses
ctx.skills, // available skills catalog
ctx.talkspace, // recent messages from channels
ctx.performanceDigest // how well you've been doing
);
This single function call assembles everything the agent needs to know. But look at what goes into it -- each parameter represents a distinct layer of context.
Layer 3: Dynamic Context (Context Builder)
The buildAgentContext function does the heavy lifting. It pulls together multiple streams of information that are specific to this agent, at this moment in time:
Role and personality. Each agent has a defined role ("You are the outreach sequencing agent") and behavioral guidelines ("Be concise in email copy, focus on value propositions, never use generic templates").
Awareness index. System health, recent conversions, which other agents have run recently and what they accomplished. The context builder filters this -- each agent only sees the status of its collaborators, not the entire 15-agent roster. The outreach agent sees the lead scorer's status. It does not see the SEO agent.
Memory. Lessons the agent has learned from past runs, active goals, known strengths and weaknesses. If the outreach agent learned that "technical founders respond better to integration-specific pitches," that lesson is injected into every future run.
Skills catalog. What computational skills are available -- lead scoring models, churn prediction, A/B test analysis. The agent knows what tools it can use and what they do, without needing to discover them.
Talkspace digest. Recent messages from the agent's communication channels. If another agent posted a finding in a shared channel ("competitor X just launched a new feature"), that shows up in the digest.
Performance digest. Success rates, feedback from recent runs, areas for improvement. An agent that has been underperforming on email open rates sees that data and can adjust its approach.
The result is that each agent starts every run with a complete, focused picture of its world. It knows who it is, what it should do, what has happened recently, what it has learned, and how well it has been performing. All of this is assembled programmatically -- no manual prompt editing required.
// What the final prompt structure looks like (simplified)
const systemPrompt = `
${roleAndPersonality}
## SYSTEM AWARENESS
${buildSmartAwareness(agentId, awareness)}
## YOUR MEMORY
${ctx.memory}
## AVAILABLE SKILLS
${ctx.skills}
## RECENT MESSAGES
${ctx.talkspace}
## YOUR PERFORMANCE
${ctx.performanceDigest}
`;
This architecture separates the stable (CLAUDE.md, role definitions) from the dynamic (awareness, memory, performance). CLAUDE.md changes rarely. The dynamic context changes every run. By layering them, you get consistency in core rules and adaptability in execution context.
Best Practices
Here are the practices that matter most, based on running this system in production.
Keep CLAUDE.md Under 500 Lines
Agents have limited context windows. A massive instruction file means less room for actual work. If your CLAUDE.md is growing past 500 lines, you almost certainly have domain-specific rules that should be in .claude/rules/ instead. Be ruthless about what earns a spot in the main file.
Put the Most Important Rules First
Language models pay more attention to content that appears early in the context. Your hardest guardrails -- the rules where violations cause real damage -- should be near the top of CLAUDE.md. "Never send an email without an unsubscribe link" should come before "use kebab-case for file names." Both matter, but one has legal consequences and the other does not.
Use Concrete Examples, Not Abstract Principles
"Follow good coding practices" is useless. "Use atomicWrite() from src/lib/atomic-write.ts for all data store writes" is actionable. The agent cannot interpret vague instructions consistently. Give it specific patterns, specific file paths, specific function names. If you find yourself writing a rule that could apply to any project, it is too abstract.
Update CLAUDE.md When Conventions Change
Stale instructions cause bugs. If you migrate from one pattern to another but forget to update CLAUDE.md, the agent will follow the old instructions and produce code that contradicts your current codebase. Treat CLAUDE.md as living documentation -- it is part of your project's source of truth and should be updated in the same PR that changes the convention.
Use .claude/rules/ for Domain-Specific Guidance
Email rules, data store conventions, API design patterns, testing requirements -- these are all candidates for scoped rule files. Each file should be focused on one domain and short enough to read in thirty seconds. If you are adding a rule, ask yourself: "Does every session need this, or only sessions working in this area?" The answer tells you where it belongs.
Test Your Instructions
After writing or updating instructions, run an agent and check if it follows them. This sounds obvious but is frequently skipped. The feedback loop is fast -- run the agent, review its output, tighten the instructions where it deviated. Two or three iterations usually get you to a stable set of rules that the agent follows reliably.
Version Control Your Instructions
CLAUDE.md and .claude/rules/ should be committed to your repository. They are part of your project's configuration, and the same versioning discipline applies. When you review a PR that changes a convention, check whether the instruction files were updated too. If they were not, the instructions are now stale and the next agent run will conflict with the new code.
Key Takeaways
CLAUDE.md is the single most impactful thing you can do to improve your experience with Claude Code. Five minutes of writing instructions saves hours of corrections across every future session.
The memory hierarchy -- CLAUDE.md, scoped rules, user memory, auto-memory -- gives you layered control. Project rules override personal preferences. Scoped rules keep the main file lean. Auto-memory catches the gaps.
For multi-agent systems, the instruction architecture matters even more. Shared rules in CLAUDE.md keep agents consistent. Dynamic context injection keeps them informed. The combination of stable rules and dynamic context is what lets a 15-agent system run without agents contradicting each other or duplicating work.
Start simple. Write a CLAUDE.md with your stack, your top five rules, and your key conventions. Commit it. Run an agent and see if it follows the instructions. Iterate from there. You can always add scoped rules and more sophisticated context injection later -- but even a basic CLAUDE.md is dramatically better than no instructions at all.