Understanding how Claude Code loads memory files is critical for large projects.
When you start Claude Code, it walks UP from your current directory to the root, loading every CLAUDE.md it finds.
/ ← loaded (if exists)
├── CLAUDE.md ← loaded at startup
├── packages/
│ ├── CLAUDE.md ← loaded at startup (you're deeper)
│ ├── api/
│ │ ├── CLAUDE.md ← loaded at startup (you started here)
│ │ └── src/
│ └── web/
│ ├── CLAUDE.md ← NOT loaded (sibling)
│ └── src/
Running from packages/api/: loads root, packages, and api CLAUDE.md files.
Running from packages/web/: loads root, packages, and web CLAUDE.md files.
Siblings never load each other.
When Claude reads or edits a file in a subdirectory, it lazy-loads that directory's CLAUDE.md.
# You start at root. Claude reads packages/web/src/app.tsx
# → packages/web/CLAUDE.md gets lazy-loaded into contextThis happens automatically. You don't control it.
monorepo/
├── CLAUDE.md # Shared: repo conventions, build commands
├── packages/
│ ├── api/
│ │ ├── CLAUDE.md # API-specific: endpoints, auth patterns
│ │ └── src/
│ ├── web/
│ │ ├── CLAUDE.md # Frontend-specific: component patterns
│ │ └── src/
│ └── shared/
│ ├── CLAUDE.md # Shared library conventions
│ └── src/
Keep it lean. This loads every session regardless of where you work.
# MyProject
## Build
pnpm build # Build all packages
pnpm test # Run all tests
pnpm lint # Lint everything
## Conventions
- TypeScript strict mode
- snake_case for database, camelCase for code
- All API responses follow RFC 7807 for errors
## Packages
- `packages/api` - Express REST API
- `packages/web` - Next.js frontend
- `packages/shared` - Shared types and utilsDetailed, package-specific context. Only loads when working in that package.
# API Package
## Run
pnpm dev # Start with hot reload on :3001
pnpm test # Jest with --coverage
## Architecture
- Express + Prisma + PostgreSQL
- Auth: JWT with refresh tokens in httpOnly cookies
- Rate limiting: Redis sliding window
## Gotchas
- Prisma client must be regenerated after schema changes: pnpm prisma generate
- Test database is SQLite (different from prod PostgreSQL)For personal preferences. Gitignored.
# My Preferences (not committed)
- I prefer verbose test output
- Always show file paths in suggestions
- My editor is NeovimSkills do NOT follow ancestor/descendant loading. They have fixed discovery locations:
1. Enterprise policies (managed)
2. ~/.claude/skills/ (user-global)
3. .claude/skills/ (project)
4. Plugins
Skills from nested .claude/skills/ directories ARE discovered automatically when Claude accesses files in those directories.
Key difference: skill descriptions are always in context (for the / menu), but full skill content is only loaded on invocation. This keeps context lean.
If you have many skills, they share a character budget for descriptions. Set SLASH_COMMAND_TOOL_CHAR_BUDGET env var to increase the limit if needed.
Agents with memory: user get their own MEMORY.md:
~/.claude/agent-memory/<agent-name>/MEMORY.md
- First 200 lines injected at agent startup
- Agent auto-curates: creates topic files, links from MEMORY.md
- Three scopes:
user(global),project(per-project),local(per-directory)
This is different from CLAUDE.md — it's agent-specific and self-managed.
| System | Scope | Managed By | When Loaded |
|---|---|---|---|
| CLAUDE.md | Project | You | Every session (ancestors), lazy (descendants) |
| CLAUDE.local.md | Personal | You | Every session (gitignored) |
| Auto Memory | User | Claude | Session start (first 200 lines) |
| Agent Memory | Per-agent | Agent | Agent invocation |
/memory command |
User | You | On demand |
| Pro-Workflow DB | User | Hooks | Session start (via SessionStart hook) |
These systems are complementary. Use CLAUDE.md for project conventions, auto memory for personal patterns, and agent memory for specialized agent knowledge.