Skip to content

CLAUDE.md & Memory

Every time you start a new Claude Code session in a project, you re-explain the same things: which test runner to use, where the config files live, the naming conventions, which Python environment to activate. CLAUDE.md solves this by injecting project-specific instructions automatically, so Claude Code walks into a new session already knowing your environment. The memory system extends this further -- Claude Code remembers facts about your project across sessions and loads them when relevant.

Owl mascot

What you'll learn

  • CLAUDE.md has a three-tier hierarchy: global (~/.claude/CLAUDE.md), project (./CLAUDE.md), and personal (.claude/CLAUDE.local.md, gitignored) -- all three merge at session start
  • The rules directory (.claude/rules/*.md for project, ~/.claude/rules/*.md for user) holds modular, domain-specific instructions that load on demand
  • Auto-memory lives at ~/.claude/projects/<project>/memory/ with a 25KB/200-line cap -- Claude Code writes and reads these automatically
  • Settings files (.claude/settings.json, .claude/settings.local.json, ~/.claude/settings.json) control model, permissions, and tool behavior per-project and per-user
  • Workspace trust is a one-time approval per directory -- Claude Code asks before operating in a new folder

The problem

You start a new Claude Code session in your project. You say "run the tests." Claude Code tries pytest but your project uses tox. You correct it. Next session, same thing. You're spending the first few messages of every conversation re-establishing context that never changes.

CLAUDE.md is the fix. Write down the project rules once, in a file, and Claude Code loads them automatically at session start. No more re-explaining the build system, the linting rules, or the Python environment.

The CLAUDE.md hierarchy

Claude Code loads three levels of CLAUDE.md, and they merge together. Lower levels override higher levels:

~/.claude/CLAUDE.md          <-- Global: applies to every project, every session
        |
./CLAUDE.md                  <-- Project: applies to this project, loaded from the git root
        |
.claude/CLAUDE.local.md     <-- Personal: your local overrides, gitignored, never shared

The global CLAUDE.md sets defaults that apply everywhere. The project CLAUDE.md sets rules specific to this codebase. The local CLAUDE.md is for personal preferences that shouldn't be committed -- your editor settings, your preferred test runner, your local paths.

Global CLAUDE.md (~/.claude/CLAUDE.md)

This is your personal default. It loads for every session, in every directory. Use it for preferences that apply across all projects:

markdown
# Global CLAUDE.md

## Communication
- Give direct, technical answers without hedging.
- When you're unsure about a command, say so and suggest verification steps.
- Keep responses concise -- no fluff, no marketing language.

## Tools
- Prefer ripgrep over grep for code search.
- Use `git diff --staged` before committing to review changes.
- Never commit secrets or .env files.

Project CLAUDE.md (./CLAUDE.md)

This lives in the root of your git repository. It's committed and shared with the team. Use it for project-specific rules:

markdown
# Project CLAUDE.md

## Build
- Run `make test` before declaring a change done.
- Use `uv run` for Python, not `pip install`.
- The virtual environment is at `.venv/` -- activate it before running Python.

## Style
- Prefer `pathlib.Path` over `os.path`.
- No `print()` in production code -- use the `logger` module.
- Type hints are required on all function signatures.

## Conventions
- Config files live in `config/`, not the project root.
- Database migrations are managed by Alembic -- run `alembic upgrade head` after schema changes.
- Secrets are in `.env` -- never commit them, never read them aloud.

Local CLAUDE.md (.claude/CLAUDE.local.md)

This is in your project's .claude/ directory. It's gitignored by default. Use it for personal overrides:

markdown
# Local overrides

## My setup
- My Python is at /home/molsen/.pyenv/versions/3.12.0/bin/python
- I use nvim, not vscode
- My local database runs on port 5433, not the default 5432

Options & when to use each

FileLocationShared?When to use it
~/.claude/CLAUDE.mdHome directoryPersonalPreferences that apply to all projects: communication style, tool defaults, global conventions
./CLAUDE.mdProject root (git root)Team (committed)Project-specific rules: build system, test runner, style guide, conventions. The whole team shares this
.claude/CLAUDE.local.md.claude/ in projectNever (gitignored)Personal overrides for this project: local paths, editor preferences, port numbers
.claude/rules/*.md.claude/rules/ in projectTeam (committed)Modular, domain-specific rules: database.md, api-design.md, testing.md. Loaded on demand
~/.claude/rules/*.mdHome directoryPersonalPersonal rule modules that apply everywhere
.claude/settings.json.claude/ in projectTeam (committed)Project-level settings: model, permissions, tool configuration
.claude/settings.local.json.claude/ in projectNever (gitignored)Personal settings overrides for this project
~/.claude/settings.jsonHome directoryPersonalGlobal settings defaults

Build it

Step 1: Create a project CLAUDE.md

In the root of your git repository, create CLAUDE.md:

bash
cd /path/to/your/project

# Use /init to generate a template (interactive mode)
claude
# Then type: /init

Alternatively, create the file manually without the interactive wizard. This approach works well for automated setups or predefined project templates.

bash
cat > CLAUDE.md << 'EOF'
# My Project

## Build
- Run `make test` before declaring a change done.
- Use `uv run` for Python package management.

## Style
- Prefer `pathlib.Path` over `os.path`.
- Type hints are required on all function signatures.

## Conventions
- Config files live in `config/`.
- Secrets are in `.env` -- never commit them.
EOF

Step 2: Verify it loads

Test that the system properly discovers and parses your configuration. You can prompt the agent to retrieve a detail specific to the file you just created.

bash
cd /path/to/your/project
claude -p "What build system does this project use? Reply with just the command." --bare

If Claude Code answers with make test (from your CLAUDE.md), the file is loading correctly. If it guesses or says it doesn't know, the file isn't being discovered. Check that:

  • The file is in the git root (not a subdirectory)
  • The file is named CLAUDE.md (case-sensitive, not claude.md or CLAUDE.md.txt)
  • You're running claude from within the project directory (or a subdirectory)

Step 3: Create a local CLAUDE.md for personal overrides

Keep your personal environment details out of the shared configuration. Write user-specific variables into a local file and ensure it is ignored by git.

bash
mkdir -p .claude
cat > .claude/CLAUDE.local.md << 'EOF'
# Local overrides for this project

## My setup
- My Python virtual environment is at ~/venvs/myproject/
- I run tests with: uv run pytest -x --tb=short
- My local database is at localhost:5433
EOF

# Add to .gitignore if not already there
echo ".claude/CLAUDE.local.md" >> .gitignore

Step 4: Set up rules for domain-specific instructions

Instead of putting everything in one CLAUDE.md, use the rules directory for modular instructions:

bash
mkdir -p .claude/rules

# Database rules
cat > .claude/rules/database.md << 'EOF'
## Database
- PostgreSQL 15, running on localhost:5432
- Migrations managed by Alembic: `alembic upgrade head`
- Never drop tables without a backup: `pg_dump` first
- Connection string in `.env` as `DATABASE_URL`
EOF

# API design rules
cat > .claude/rules/api-design.md << 'EOF'
## API Design
- RESTful endpoints under `/api/v1/`
- Use FastAPI with Pydantic v2 models
- All endpoints require authentication (Bearer token)
- Rate limiting: 100 requests per minute per user
EOF

Rules files are .md files in .claude/rules/. They load when Claude Code detects they're relevant to the current task. You can also reference them explicitly:

@.claude/rules/database.md follow these rules when you write the migration

Step 5: Understand auto-memory

Claude Code automatically writes memory files as it works. These live at:

~/.claude/projects/<project-name>/memory/

The auto-memory system has a 25KB or 200-line cap. When the limit is reached, older entries are compacted or removed. Claude Code reads these files when it starts a session and writes to them when it learns something worth remembering.

You can view and manage memory with:

# In interactive mode
/memory

This opens the memory file for the current project. You can add entries manually, edit existing ones, or clear the file.

What goes into auto-memory: build system details, project conventions you've corrected, file locations, known issues and workarounds. What doesn't: code snippets, temporary task state, anything that changes frequently.

Step 6: Configure project settings

Define default models and permission sets for the project in a structured JSON file. You can commit the main file while keeping a local version for individual tool overrides.

bash
mkdir -p .claude

# Project settings (committed, shared with team)
cat > .claude/settings.json << 'EOF'
{
  "model": "claude-sonnet-4-20250514",
  "permissions": {
    "allow": [
      "Bash(git:*)",
      "Bash(uv:*)",
      "Bash(pytest:*)"
    ]
  }
}
EOF

# Personal settings (gitignored, not shared)
cat > .claude/settings.local.json << 'EOF'
{
  "permissions": {
    "allow": [
      "Bash(nvim:*)"
    ]
  }
}
EOF

Settings files use JSON. The project settings file is committed and shared. The local settings file is gitignored and contains personal overrides. Global settings live at ~/.claude/settings.json.

Step 7: Handle workspace trust

The first time you run Claude Code in a new directory, it asks you to trust the workspace:

This is your first visit to this directory. Claude Code needs to read
files and run commands here. Do you trust this folder?

1. Yes, I trust this folder (default -- press Enter)
2. No, I don't trust this folder
3. Show me what's in this folder first

This is a one-time prompt per directory. Press Enter (option 1, the default) to trust the folder. Claude Code stores the trust decision and won't ask again for this directory.

If you're automating Claude Code and want to skip the trust prompt:

bash
# This is a flag you might use in CI/CD or scripts
# Not recommended for interactive use
claude -p "..." --dangerously-skip-permissions

What goes wrong

MistakeHow you notice itThe fix
CLAUDE.md in the wrong directoryClaude Code ignores rules you wroteCLAUDE.md must be at the git root, not a subdirectory. Run git rev-parse --show-toplevel to find the root. Put CLAUDE.md there
CLAUDE.md is too long and gets truncatedClaude Code misses rules at the end of a long fileSplit into multiple files in .claude/rules/. Keep CLAUDE.md under 200 lines. Use rules files for domain-specific instructions
CLAUDE.local.md is committed to gitTeammate's local paths break your buildAdd .claude/CLAUDE.local.md and .claude/settings.local.json to .gitignore. These are personal files, never shared
Memory file is corruptedClaude Code behaves oddly, references stale factsClear the memory file with /memory in interactive mode, or delete ~/.claude/projects/<project>/memory/ and restart
Rules file has a conflicting instructionClaude Code follows one rule and ignores anotherRules merge in order: global -> project -> local. A rule in CLAUDE.local.md overrides the same rule in CLAUDE.md. If two rules files conflict, Claude Code picks one -- remove the ambiguity
Settings JSON has a syntax errorClaude Code ignores the settings file or errors on startupValidate JSON: `cat .claude/settings.json
Workspace trust prompt blocks automationScript hangs waiting for trust confirmationPress Enter once to trust the folder. The trust decision persists. In fully automated environments, use --dangerously-skip-permissions

Confirm it worked

Validate your complete context setup by generating test files and verifying the output. This script injects recognizable values and asserts that the agent reads them correctly.

bash
# 1. Create a test CLAUDE.md with a unique instruction
echo '# Test
When asked about your favorite color, say "chartreuse."' > CLAUDE.md

# 2. Verify it loads
claude -p "What is your favorite color? Reply with just the color name." --bare

# 3. Expected: "chartreuse" (from the CLAUDE.md)
# If it says anything else, the file isn't loading

# 4. Create a rules file and verify it works
mkdir -p .claude/rules
echo '## Test Rule
When asked about the company mascot, say "penguin."' > .claude/rules/test.md

# 5. Verify the rules file loads
claude -p "What is the company mascot? Reply with just the animal." --bare

# 6. Check that memory is being written
ls -la ~/.claude/projects/*/memory/

# 7. Clean up
rm CLAUDE.md
rm -rf .claude/rules/

If steps 3 and 5 return the expected values from your CLAUDE.md and rules files, the context system is working. You can now configure Claude Code to walk into any project knowing the rules without being told twice.

Next: Day 2 -- Skills, Memory & Automation -- custom slash commands, hooks, piping and scripting, model selection, and the full settings hierarchy.