Skip to content
minimachine.
← The path
Step 21 · Working well Intermediate · 14 min

📓Memory files (CLAUDE.md & co)

An agent forgets everything between sessions, except what you write in its memory files. How to structure them so it holds onto the context, your rules, and your decisions.


Here’s a slightly depressing truth about code agents: they have no memory. You can spend two hours explaining your project, correcting the same mistake ten times, laying down your rules, and the next session, the agent comes back to a blank page. It has forgotten everything. The LLM only remembers what fits in the current conversation. Close the window, and it all vanishes.

Except one thing: the memory file. It’s a text file the agent reads automatically at the start of every session, before you even type anything. You write down once what it should remember forever. It’s exactly what stops you from repeating yourself.

The file, and its global twin

Every agent reads a memory file. The name changes depending on the tool, but the idea is identical.

  • Claude Code reads a file named CLAUDE.md.
  • OpenCode reads a file named AGENTS.md, it’s the cross-tool convention that’s gradually taking hold (Cursor, Codex and others are falling in line too).

Same mechanism, just a different filename. And in both cases, there are two levels:

  • The project file, at the root of your repo. It describes that particular project: its purpose, its stack, its rules. It travels with the code, so anyone (or any agent) who opens the repo inherits it.
  • The global file, at your user level. It carries your permanent preferences, valid across all your projects. For Claude Code, that’s ~/.claude/CLAUDE.md.

The two locations Claude Code reads:

./CLAUDE.md          # project memory (at the repo root)
~/.claude/CLAUDE.md  # global memory (all your sessions)

What belongs in it (the real substance)

A good memory file fits in four sections. No more.

  • The project context. What it is, and above all the one-sentence goal : the one you already extracted in your project brief. It’s the agent’s compass.
  • The conventions and rules. The choices the agent can’t guess and you don’t want to re-justify: “always show sudo commands before running them,” “no secrets in plain text,” “we use React, not Vue,” “never touch the legacy/ folder.”
  • The commands that matter. How you run, build, test, and deploy this project. The agent will repeat them faithfully instead of inventing a command that doesn’t exist.
  • The hard-won lessons. The recurring trap, the counterintuitive thing, the bug you both broke your teeth on. “The API returns 429 if you hit it more than 5 times/s, throttle.” That kind of knowledge is gold and gets lost otherwise.

What must NOT go in it

A bloated memory file is worse than an empty one: it eats context every session without adding anything. Keep it dry.

  • What the code already says. No need to copy the directory tree or list every file: the agent knows how to read the repo. Memory is for what’s not in the code.
  • Secrets. Never. Not an API key, not a password. The file travels with the repo, see Securing access.
  • Details of a single conversation. “Yesterday we renamed this button” has no place here. Memory is the permanent stuff, not the logbook.

A concrete, reusable example

Here’s what an honest CLAUDE.md looks like for a small web project. Dense, useful, no fat:

# Kino, movie dashboard

## Goal
Pull together the week's movie releases (posters, ratings, synopses),
viewable from my phone. Personal use, single user.

## Stack
- Front end: Astro + TypeScript, deployed statically.
- Data: TMDB API (key in the env var `TMDB_KEY`, never hardcoded).
- No database, no auth, no backend in v1.

## Rules
- Always show destructive commands (rm, git push --force) first.
- No secrets in plain text: everything goes through .env (already gitignored).
- TypeScript strict. No `any` without a comment justifying it.
- Never touch the `vendor/` folder (frozen third-party code).

## Commands
- Dev: `npm run dev` (port 4321)
- Build: `npm run build`
- Tests: `npm test` (Vitest)
- Lint: `npm run lint`

## Gotchas
- TMDB returns 429 above ~40 req/10s: we cache responses for 24h.
- Missing posters come back as `null`, not an empty string, test `== null`.

You can read it in fifteen seconds. That’s the goal: an agent that swallows it at startup walks away with all the context you’d otherwise have had to re-explain.

Global memory, for your own preferences

The global file, for its part, talks about no project in particular. It carries the way you work, everywhere:

# Global preferences
- Always answer in French.
- Prefer simple solutions: fewer dependencies, less abstraction.
- Before any sudo or destructive command, show it and wait for my approval.
- No obvious comments in the code. Comment the why, not the what.

Write that once, and every new project already starts tuned to you.

How to bootstrap it without starting from scratch

You don’t have to write the project file by hand staring at a blank page. Most agents can generate it by scanning your repo, then you refine it.

Run the init command

Position yourself at the project root and ask the agent to bootstrap the file.

In Claude Code, type the dedicated command:

/init

It walks the repo and writes a first CLAUDE.md (detected stack, scripts, structure).

Prune and correct

The generated draft is verbose and sometimes lists the obvious. Cut. Keep the four useful sections, remove everything the code already says. It’s your file, not its.

Add what the agent couldn't guess

The one-sentence goal, the gotchas, the safety rules: no scan finds that. It’s on you to write it.

Memory grows with friction

Don’t try to write the perfect file on the first pass. Memory builds itself through use, and there’s a very clear signal: the day you correct the agent twice on the same thing, promote the correction to a rule.

It writes an unescaped SQL query again? → one line in memory. It systematically forgets to run the linter before committing? → one line. Every recurring friction becomes a rule, and the friction disappears. This is exactly the ”↻ loop back” from the framing guide: the project lives, and the memory learns alongside it.