CLAUDE.md, Cursor rules, mem0: three ways to give an agent a memory

Two of these are prompt prefixes. One is actual memory. If you've been treating CLAUDE.md and .cursorrules as "agent memory", you've been feeding the model the same notes every turn and calling it recall.

The split people miss

CLAUDE.md and .cursorrules are static text files. They get loaded into the model's context at the start of a session and re-read on every turn. Nothing about them changes based on what happened yesterday.

mem0 is different. It's a library your app calls. It extracts facts from messages, stores them in a vector database, and retrieves by relevance. That is storage. The first two are prompt engineering with a filename.

This distinction matters because the failure modes are not the same. A prompt prefix that grows past 200 lines starts getting ignored by the model. A memory store that grows past 200 facts still works, it just costs more to query.

What CLAUDE.md really does

CLAUDE.md is a plain markdown file Claude Code reads at session start. It has three scopes:

  • ./CLAUDE.md in a project directory (project rules)
  • ~/.claude/CLAUDE.md (user-wide rules)
  • Enterprise-level files for teams on managed setups

Claude Code also has an auto-memory feature that appends notes to files under ~/.claude/ when you correct the model. That's the closest CLAUDE.md gets to "learning". It's append-only and you edit it by hand.

The ceiling

The file is a prompt prefix. Every instruction in it costs tokens every turn. Once you pass around 200 lines, the model starts missing rules lower in the file, and you pay for those tokens whether the rule is relevant to this turn or not.

There's no conditional loading. No retrieval. No "load this rule only when editing Python". You either include it every turn or you don't.

Where .cursorrules is the same (and where it isn't)

Cursor's .cursorrules file (project scope) and its Rules for AI panel (user scope) are the same shape as CLAUDE.md. Plain text, re-read every turn, no state. Same ceiling. Same auto-memory gap.

Two real differences:

  • Sync requires a Cursor account. If you want your user-level rules on a second machine, you sign in. CLAUDE.md is just a file in your home directory, so you sync it with git or Dropbox or whatever you already use.
  • Cursor's rules file sits in the IDE. CLAUDE.md can live anywhere Claude Code runs (CLI, subagents, scripts). If you're only in the editor, that difference is invisible. If you're running headless agents, it's the whole point.

Neither is a memory. Both solve "give the agent instructions I don't want to retype". That's a useful job. It's not the same job as "remember what the user told you last week".

Where mem0 earns its keep

mem0 (github.com/mem0ai/mem0, Apache 2.0) is a library. You call it from your app code. On each user message, it runs an LLM fact-extractor over the conversation, pulls out structured facts ("user prefers pnpm", "user's stack is Next.js 16"), and writes them to a vector store. On retrieval, it searches by relevance to the current query.

You can self-host the OSS version or use the managed SaaS. Either way, the model is: facts go in, facts come out, and the store persists across sessions.

What it costs

The fact extraction runs an LLM call per turn. That's a real cost, and it's why you don't want mem0 for things that fit in a prompt prefix. Use it for user facts that accumulate over weeks: project names, preferences, past decisions, people they work with.

It also introduces a retrieval quality problem. If your vector search returns the wrong three facts, the model acts on stale context. That's a class of bug CLAUDE.md can't produce because CLAUDE.md doesn't retrieve anything.

How to combine them

In practice most people end up running two at once. Here's the split that works:

  • CLAUDE.md for rules. Things that should apply to every turn. Coding conventions, directory layout, "always use pnpm not npm". Keep it under 200 lines. Re-read it every month and delete what's stale.
  • mem0 for user facts. Things that change over time or are specific to a person's history. What they're building, who their users are, what they tried and rejected.
  • Cursor rules if you're in Cursor. Same content as CLAUDE.md, different file. Don't maintain both unless you have to.

There's a fourth option worth mentioning: Munin, a local Rust binary (not a library) that watches for corrections and promotes them into rule files with freshness, stability, and confidence scoring. It's an observation-to-rule pipeline, not a retrieval store. Different category again. If you're hitting correction fatigue (telling the agent the same thing three times a week), that's what it's for.

Pick by what you're hitting

Three decisions, by symptom:

  • If CLAUDE.md exceeds 200 lines and you still feel unheard, the prompt prefix has hit its ceiling. Go mem0. Move the per-user stuff out of the file and into a store that retrieves on demand.
  • If the agent keeps making the same kind of mistake, that's a different problem. You don't need more context, you need the corrections to stick. That's Munin's shape: observe the correction, promote it to a rule, surface it next time the same pattern comes up.
  • If you just want settings sync across machines, accept the Cursor account and move on. Or commit your CLAUDE.md to a dotfiles repo. This is not the problem you think it is.

The real trap is using a prompt prefix to solve a storage problem, or a storage library to solve a rules problem. Pick the one that matches the shape of what's going wrong, and leave the other two alone until it's their turn.

Try Munin.

A local Rust binary. Four commands. No SaaS, no account, no telemetry.