Issue 07 | Writing CLAUDE.md: A Persistence Layer Project Brief for AI

Updated on 4/5/2026

🎯 Learning Objectives

By the end of this issue, you will master:

  1. The working principles and file loading mechanism of CLAUDE.md
  2. How to write effective project instructions
  3. Configuration and management of the Auto Memory feature
  4. Organizing rules in directories with .claude/rules/

📖 Core Concepts Explained

7.1 Why is CLAUDE.md needed?

Every time you start a new Claude Code session, it knows nothing about your project. It will explore via Glob and Read, but this is time-consuming and imprecise.

CLAUDE.md is your project brief for Claude—it's automatically loaded into the context at the start of each session, allowing Claude to know from the first second:

  • What this project is
  • What tech stack is used
  • What are the strict rules
  • What are the common commands

7.2 CLAUDE.md Placement and Priority

File Location                          Scope          Load Time
──────────────────────────────   ──────────     ──────────
/Library/Application Support/    System-level   Always loaded (admin configured)
  ClaudeCode/CLAUDE.md

~/.claude/CLAUDE.md              User-level     Always loaded (personal preference)

./CLAUDE.md                      Project-level  Loaded when entering project directory
./.claude/CLAUDE.md              Project-level (alternative) Same as above

./src/billing/CLAUDE.md          Subdirectory-level Loaded when Claude accesses this directory

📚 Official Documentation Reference: How Claude remembers your project

7.3 Referencing Other Files (@import)

CLAUDE.md supports using @ syntax to include other files as context:

# Project Brief

See @README.md for project overview
See @package.json for available npm commands

## Git Workflow
- Follow @docs/git-instructions.md

## Personal Preferences
- @~/.claude/my-personal-style.md

7.4 Auto Memory

In addition to manually writing CLAUDE.md, Claude Code also has an Auto Memory feature—it automatically saves your corrected preferences during a session:

Scenario Example:
You: Don't use semicolons
Claude: Okay, I won't add semicolons in the future
→ Automatically saved to ~/.claude/memory.json:
  "Do not use JavaScript semicolons in this project"

💻 Simulating Claude TUI Interaction

Scenario 1: Initializing CLAUDE.md

$ cd ~/my-project
$ claude

> /init

╭─ Claude ─────────────────────────────────────────────╮
│                                                      │
│  🔍 Tool: Read (package.json)                        │
│  🔍 Tool: Glob (**/*.{ts,tsx,js,jsx})                │
│  🔍 Tool: Read (tsconfig.json)                       │
│  🔍 Tool: Read (.eslintrc.json)                      │
│  🔍 Tool: Glob (**/Dockerfile)                       │
│  🔍 Tool: Read (.github/workflows/*.yml)             │
│                                                      │
│  I have analyzed your project structure and generated the following CLAUDE.md: │
│                                                      │
│  ⚙️ Tool: Write → CLAUDE.md                          │
│  ╭─ NEW FILE ──────────────────────────────────╮     │
│  │ # Project: my-project                       │     │
│  │                                              │     │
│  │ ## Overview                                  │     │
│  │ E-commerce platform built with Next.js 14   │     │
│  │ and Express API, deployed on Vercel +        │     │
│  │ Railway.                                     │     │
│  │                                              │     │
│  │ ## Tech Stack                                │     │
│  │ - Frontend: Next.js 14 (App Router) + React │     │
│  │ - Backend: Express + Prisma + PostgreSQL    │     │
│  │ - Styling: Tailwind CSS                      │     │
│  │ - Testing: Vitest + Playwright              │     │
│  │                                              │     │
│  │ ## Commands                                  │     │
│  │ - `pnpm dev` — start dev servers            │     │
│  │ - `pnpm test` — run unit tests              │     │
│  │ - `pnpm build` — production build           │     │
│  │ - `pnpm db:push` — push schema changes      │     │
│  │                                              │     │
│  │ ## Rules                                     │     │
│  │ - Use TypeScript strict mode                 │     │
│  │ - 2-space indentation                        │     │
│  │ - No default exports (use named exports)     │     │
│  │ - Commit messages follow Conventional        │     │
│  │   Commits format                             │     │
│  ╰──────────────────────────────────────────────╯     │
│                                                      │
│  ✅ CLAUDE.md created!                                │
│  You can edit and supplement it as needed.           │
│                                                      │
╰──────────────────────────────────────────────────────╯

Scenario 2: CLAUDE.md in Effect

> Create a new API route to handle user profile updates

╭─ Claude ─────────────────────────────────────────────╮
│                                                      │
│  📝 Loaded context from CLAUDE.md:                   │
│  • TypeScript strict mode ✓                          │
│  • Named exports ✓                                   │
│  • Conventional Commits ✓                            │
│                                                      │
│  ⚙️ Tool: Write → src/routes/profile.ts              │
│  ╭─ NEW FILE ──────────────────────────────────╮     │
│  │ import { Router, Request, Response }         │     │
│  │   from 'express';                            │     │
│  │ import { z } from 'zod';                     │     │
│  │ import { prisma }                            │     │
│  │   from '@my-project/db';                     │     │
│  │ import { authMiddleware }                    │     │
│  │   from '../middleware/auth';                  │     │
│  │                                              │     │
│  │ // ✅ Named export (no default)              │     │
│  │ export const profileRouter = Router();       │     │
│  │                                              │     │
│  │ const updateSchema = z.object({              │     │
│  │   name: z.string().min(1).max(100),          │     │
│  │   bio: z.string().max(500).optional(),       │     │
│  │ });                                          │     │
│  │                                              │     │
│  │ // ✅ 2-space indentation                    │     │
│  │ profileRouter.patch(                         │     │
│  │   '/profile',                                │     │
│  │   authMiddleware,                            │     │
│  │   async (req: Request, res: Response) => {   │     │
│  │     const data = updateSchema.parse(         │     │
│  │       req.body                               │     │
│  │     );                                       │     │
│  │     const user = await prisma.user.update({  │     │
│  │       where: { id: req.userId },             │     │
│  │       data,                                  │     │
│  │     });                                      │     │
│  │     res.json({ ok: true, user });            │     │
│  │   }                                          │     │
│  │ );                                           │     │
│  ╰──────────────────────────────────────────────╯     │
│                                                      │
│  Note: I followed the rules in CLAUDE.md:            │
│  ✅ TypeScript strict mode                            │
│  ✅ Named export (no default export)                  │
│  ✅ 2-space indentation                               │
│  ✅ Used existing prisma + zod dependencies in the project │
│                                                      │
╰──────────────────────────────────────────────────────╯

Scenario 3: Managing Auto Memory

> /memory

╭─ Auto Memory ────────────────────────────────────────╮
│                                                      │
│  📁 Storage: ~/.claude/memory.json                   │
│                                                      │
│  Saved memories for this project:                    │
│  1. "Do not use semicolons (no semicolons)"          │
│  2. "API return format is uniformly { ok: boolean, data: T }" │
│  3. "Error handling uses custom AppError class"      │
│  4. "Database queries are placed in the services/ directory" │
│                                                      │
│  [e] Edit  [d] Delete  [q] Quit                      │
│                                                      │
╰──────────────────────────────────────────────────────╯

💻 Code Demo: Advanced CLAUDE.md Template

# My SaaS Project

## Overview
B2B SaaS platform for HR management.
50K MAU, multi-tenant architecture.

## Tech Stack
- Frontend: Next.js 14 (App Router) + React 19
- Backend: tRPC + Prisma + PostgreSQL
- Auth: Clerk
- Payments: Stripe
- Deployment: Vercel + Supabase

## Commands
- `pnpm dev` — start all services
- `pnpm test` — run Vitest
- `pnpm test:e2e` — run Playwright
- `pnpm db:push` — push schema changes
- `pnpm db:seed` — seed test data

## Architecture Rules
- Use Server Components by default, 'use client' only when needed
- All API routes go through tRPC procedures
- Database queries MUST go through service layer (src/services/)
- Never import from `@prisma/client` directly, use `@/lib/db`

## Code Style
- 2-space indentation
- No semicolons
- Named exports only (no default exports)
- Use `type` imports: `import type { User } from '@/types'`
- Error messages in English, UI text supports i18n

## Git Workflow
- Branch naming: `feat/`, `fix/`, `chore/`
- Commit messages: Conventional Commits
- Always create PR, never push to main directly

## Testing
- Unit tests: colocate with source (*.test.ts)
- E2E tests: tests/e2e/
- Minimum 80% coverage for new code

## Important Context
- @README.md for project overview
- @docs/api-design.md for API conventions
- @.env.example for required environment variables

🔧 Tools / Commands Involved

Tool/Command Function
/init Automatically generates CLAUDE.md
/memory View/Edit Auto Memory
@path/to/file Includes other files in CLAUDE.md
.claude/rules/*.md Directory-based rules (split by function)
~/.claude/CLAUDE.md Global personal preferences
CLAUDE.md Project-level instructions

📝 Key Takeaways from This Issue

  1. CLAUDE.md is the project's persistent context, automatically loaded in each session
  2. The /init command can one-click generate an initial version
  3. Using @filepath can include additional files as context
  4. Auto Memory automatically saves your corrected preferences
  5. A good CLAUDE.md should be specific and clear: use "2-space indentation" instead of "format properly"

🔗 References