← /writing/learning·2026 · 05 · 06·8 min read

My agent remembers me across sessions. I'm not sure I want it to.

I deleted one memory file and the next session got better, not worse. That bothered me enough to write this.

Harness Engineering · Part 7 of 10. Previous: What does it mean for the harness to "trust" the model?. Next: Why Claude Code feels different from Cursor.

My agent remembers me across sessions. I'm not sure I want it to.

I deleted a memory file last Tuesday. Just opened ~/.claude/projects/<repo>/memory/MEMORY.md in my editor, read it for the first time in months, and yanked the whole thing. The line that did it: "User prefers TypeScript over JavaScript for new projects." True a year ago. Not true on the project I was in — a Gatsby site where I'd been writing plain JS for weeks and the agent kept gently nudging me to convert files. Below it: a stale note about a database I no longer used, a "preference" inferred from one frustrated message I'd typed during a bad debugging session, and a line about my "preferred testing framework" that named a framework I'd actively migrated away from.

I expected the next session to be worse. It was better.

What I tried first

The instinct, when I first got memory features, was to save everything. Auto memory was on. Anything that felt like a "preference" went in. Any correction I made, the agent dutifully noted: user wants snake_case here, user prefers explicit returns, user dislikes barrel files, user is working on the billing module, user mentioned they're learning Rust. I treated the memory file the way I treat localStorage — write-only, read-rarely, garbage-collect-never.

Sessions slowly got worse, but in a way that's hard to attribute. The first month was great: the agent started with useful priors, didn't ask me to re-explain my stack, named files the way I'd name them. The second month was fine. By month three I was noticing the agent making confident assertions about my project that were wrong — referencing a directory structure I'd refactored, defaulting to a library I'd ripped out, citing a "preference" I didn't remember stating.

The degradation gradient looked like this. First, low-grade friction: small wrong defaults I'd correct in passing and shrug off. Then load-bearing wrongness: the agent would start a task with a stale assumption, write thirty lines on top of it, and I'd have to unwind. Then the meta-failure: I'd correct the agent, it would update memory with the correction, but the original wrong note was still there, so now memory had two contradictory entries and the agent was picking between them at random.

The naive fix was to write more memories. The more I wrote, the worse it got.

What clicked

The reframe took me a while: memory is not context. Memory is policy.

Context is the working set — what's in the window for this task, right now. It turns over every session. Memory is the answer to a different question: what should the agent know about me by default, before any task starts? That's a much smaller, much sharper question, and it has a different failure mode. Bad context makes one session worse. Bad memory makes every session worse.

The test that helped me prune is one I stole from thinking about onboarding docs: the good memory is the one a stranger could read in five minutes and feel they knew you. A short, dense, opinionated description — what you build, how you write code, what you care about, what you've decided not to do. The bad memory is an accumulated stream of factoids: a preference inferred from one bad day, a project that ended six months ago, a framework you've since abandoned, a tone request from a context that no longer applies. A stranger reading the bad memory wouldn't know you. They'd know the trail you left, which is different and mostly noise.

When I went back through my auto memory with that test in mind, maybe a fifth of the entries survived. The rest were factoids: things that had been true at the moment they were written and were now wrong, contradictory, or context-dependent in ways the entry didn't capture.

The other shift was what kind of thing a memory should be. The factoids that aged badly were almost all of the form "user prefers X" or "user is working on Y." The entries that aged well were structured: a rule, a reason, and a way to apply it. Something like "prefer named exports over default exports — default exports break refactors and make grep-by-name unreliable; apply when reviewing or writing new modules." That third clause is what made it durable. With the why, the agent could decide when the rule didn't apply. Without the why, it applied the rule everywhere or nowhere, and either way it was wrong half the time.

The Claude Code docs make this distinction explicit: CLAUDE.md is for instructions you write — facts the agent should hold every session, the kind of thing a teammate would need to be productive. Auto memory is for things the agent picks up — corrections, preferences, build commands. They're different files because they have different decay rates. The hand-written one is policy and changes slowly. The auto one is observation and goes stale fast. Conflating them is what killed me.

The deletion experience confirmed the reframe. Every memory I removed was a constraint I didn't realize the agent had been carrying. Some of those constraints were load-bearing — and those I added back to CLAUDE.md as proper rules with reasons. Most weren't. Most were the agent making decisions on behalf of a version of me that no longer existed.

The harness wasn't remembering me. It was remembering a trail of me, and treating the trail as identity.

What I'd do differently next time

Three concrete moves, in order of impact.

Write fewer, sharper memories. Each entry gets the structure: rule, why, how to apply. If I can't write the why, the entry isn't ready to be a memory yet — it's a passing observation, and it goes in the conversation, not the file. This single rule cut my memory file by 70% and made the surviving entries actually useful.

Review every few weeks; treat outdated entries like dead code. I now block 15 minutes on a Friday to read MEMORY.md and CLAUDE.md end to end. Anything that's no longer true gets deleted, no ceremony. Anything I had to correct three times this week gets added. Memory hygiene is exactly the same shape as dead-code pruning: easy, low-stakes, compounds when you do it, awful when you don't.

Default to CLAUDE.md for anything load-bearing. Auto memory is fine for build commands and small workflow shortcuts. But anything that affects how the agent reasons about the codebase — architecture rules, naming, what not to touch — belongs in a hand-written file I can read in one screen. The discipline of writing it down forces the why out of me.

What I'm still unsure about

Should memories expire by default? My gut says yes — anything written more than three months ago should require a re-confirmation prompt. But that's annoying, and "annoying" is how features die. Maybe a softer version: a freshness score, surfaced when the agent uses a memory, so I see which old note drove a decision and can prune it in flight.

Should the agent prune its own memory? It can already, in principle — str_replace and delete are part of the memory tool surface. But asking the agent to evaluate whether its own past observations are still true feels like asking it to grade its own homework. Maybe pruning is the human's job and writing is the agent's, asymmetric on purpose. I haven't decided.

The last open question is whether the "stranger reads it in five minutes" test is the right one. It works for me because I think of my memory file as a description of me-as-an-engineer, not a log of past sessions. If you think of it as a log, you'll write different memories — and maybe correctly so. I don't know yet.

References

  • Anthropic, How Claude remembers your project — the official Claude Code docs on CLAUDE.md vs auto memory, with the line that finally made the distinction click for me: "CLAUDE.md is what you write; auto memory is what Claude writes." Different decay rates, different failure modes. https://code.claude.com/docs/en/memory
  • Anthropic, Memory tool — the Claude API memory tool spec. The "ASSUME INTERRUPTION" line in their default prompt is what reframed memory for me as a recovery mechanism, not a personalization layer. https://platform.claude.com/docs/en/agents-and-tools/tool-use/memory-tool
  • Anthropic, Effective context engineering for AI agents — the "structured note-taking" section is where I got the idea that what the agent writes down should be load-bearing scaffolding for future sessions, not a stream of observations. https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents
  • Charles Packer et al., MemGPT: Towards LLMs as Operating Systems — the original paper that named the problem: a tiered memory hierarchy, with the agent itself responsible for moving things between in-context and out-of-context storage. Reading this made it obvious that memory is a policy decision, not a data-store decision. https://arxiv.org/abs/2310.08560
  • Letta team, Memory Blocks: The Key to Agentic Context Management — the practitioner version of MemGPT. The framing that memory blocks are structured sections with specific purposes, not a free-form notepad, is what pushed me toward the rule/why/how-to-apply shape. https://www.letta.com/blog/memory-blocks
  • Drew Breunig, How to Fix Your Context — the section on context offloading and pruning applies almost word-for-word to memory hygiene. Pruning is not optional; it's the maintenance cost of having memory at all. https://www.dbreunig.com/2025/06/26/how-to-fix-your-context.html
  • Simon Willison, I really don't like ChatGPT's new memory dossier — Simon's critique that ChatGPT-style invisible memory is opaque in a way that makes it hard to predict what the model will do. The post made me appreciate Claude Code's design decision: the memory file is plain markdown I can open and read. Pollution is only a fixable problem if you can see it. https://simonwillison.net/2025/May/21/chatgpt-new-memory/
  • OpenAI, Memory and new controls for ChatGPT — the official announcement, useful as the "other side" of the design space: memory as automatic personalization, on by default, with controls but not transparency. Worth reading next to the Claude Code docs to see the philosophical fork. https://openai.com/index/memory-and-new-controls-for-chatgpt/

Harness Engineering · Part 7 of 10. Previous: What does it mean for the harness to "trust" the model?. Next: Why Claude Code feels different from Cursor.

← back to /writingset in fraunces · geist · geist mono