The first time I watched a coding agent forget a six-hour refactoring session, I assumed it was a bug. It was not. It was the designed behavior of a system that treats memory as optional.
I had been working with Claude Code on a Django-to-FastAPI migration. The agent had mapped out the entire model layer, documented the migration order, and tracked which endpoints needed rewriting. Then I closed the terminal. When I opened a new session the next morning, the agent greeted me like a stranger. No memory of the migration. No record of what we had completed. Back to zero.
This is not a Claude Code problem. Every coding agent I have tested works this way by default. Session context is ephemeral by design, and the persistence mechanisms exist but are easy to miss if you do not know what to look for.
Why Coding Agents Forget by Default
The gap comes from how these agents are architected. A coding agent running in a terminal operates in layers that have different retention semantics.
The first layer is session context. Everything the agent knows about the current task lives in the context window of a running process. Close that process and the context is gone. This is not a bug. Stale context from old sessions causes more problems than forgotten context does, so engineers building these systems made ephemeral memory the default.
The second layer is project-level memory files. Claude Code uses CLAUDE.md in your project root. Cursor uses similar project memory conventions. These files persist across sessions and survive restarts, but the agent does not update them automatically.
The third layer is cross-session persistent memory. Claude Code has a SQLite database at ~/.claude/memory.db that stores what the agent learns across sessions. This database only exists if you run the agent with the --memory flag. Without that flag, the database is never created, and every session starts fresh.
The failure mode I see most often is an agent that has access to all three layers but the engineer does not know they exist. The agent looks like it has memory because you have been working with it for days. But the moment you restart the terminal, the session layer is gone. The project files still have what you wrote manually. The SQLite database, if it exists, has what the agent chose to record. The combination creates an experience that feels inconsistent.
How Memory Serialization Actually Works
The serialization layer is where persistence either happens or does not. I covered serialization patterns in depth in my post on memory serialization between sessions, but the short version for coding agents is this.
When you run Claude Code with --memory, the agent gains the ability to write entries to a SQLite database. These entries are retrievable in future sessions and are scoped by project. If you are working in a repository called api-gateway, the agent stores findings tagged with that project. Switch to a different directory and those entries do not surface unless you specifically query for them.
The schema has five columns: id, content, project, created_at, updated_at, and tags. The content field holds whatever the agent decided to remember. The project field scopes retrieval. The tags field lets you filter.
import sqlite3
conn = sqlite3.connect('/home/ubuntu/.claude/memory.db')
cur = conn.cursor()
# Check how many entries exist after a week of use
cur.execute("SELECT COUNT(*) FROM memory_entries;")
print(f"Total entries: {cur.fetchone()[0]}")
# Check entries for a specific project
cur.execute("""
SELECT content, created_at
FROM memory_entries
WHERE project = 'api-gateway'
ORDER BY created_at DESC
LIMIT 5;
""")
for row in cur.fetchall():
print(f"{row[1]}: {row[0][:100]}")
The entries do not accumulate automatically. The agent writes to this database when you explicitly ask it to remember something, or when it decides a finding is significant enough to record. I have run sessions where the database gained 15 entries. I have also run sessions where the count stayed at zero because I never asked the agent to track anything.
The project file CLAUDE.md works differently. You write it. The agent reads it on every session start but does not update it unless you specifically ask. This is intentional. CLAUDE.md is your file, encoding your decisions, and the agent respects that ownership.
The Specific Failure Modes I Hit
Context window exhaustion is the failure mode that bites most coding agents. When you are working on a large task, the agent accumulates file reads, tool results, and reasoning in the context window. A 200K token context window sounds large until you are in the middle of a 50-file migration. I hit the wall at roughly the 30-file mark when working with Claude Sonnet 4. The agent started dropping older file contents from context and making decisions based on incomplete information. No error. Just quietly wrong code.
The fix is checkpointing. For long tasks, I write periodic summaries to CLAUDE.md or the SQLite database. The short-term memory patterns for AI agents that I wrote about apply directly here. The context window is short-term memory. What you serialize to disk is long-term memory. The agent needs both, and you need to manage the boundary explicitly.
Schema drift is a second failure mode. The SQLite memory database schema has not changed in the versions I tested, but the content the agent writes to it changes constantly. An entry written six months ago might use a format that the current agent interprets differently. I handle this by reviewing and pruning memory entries monthly. Entries older than 90 days get audited. If the content no longer reflects project reality, I delete it.
Cross-session continuity breaks in a third way I did not anticipate. A coding agent can have good memory within a session and zero memory across sessions if the persistence layer is not connected properly. I diagnosed this by running a specific test: start a session, do meaningful work, close the terminal, open a new session, and ask the agent what it remembers. If the answer is nothing, the persistence layer is not working.
The Practical Fixes That Actually Work
Enable --memory on every session. Add an alias to your shell profile so it is not extra typing.
# In your .bashrc or .zshrc
alias cc='claude --memory'
Verify the database is being written to. Run this between sessions.
sqlite3 ~/.claude/memory.db "SELECT COUNT(*) FROM memory_entries;"
A count of zero after a week of regular use means the agent is not writing anything. Either --memory is not active, or the agent is not deciding that anything is worth recording. If the latter, you need to prompt more explicitly. "Remember that the auth service uses JWT with RS256" triggers a database write.
Use CLAUDE.md for what you know the agent needs on every session. Architecture decisions, coding standards, team conventions, environment setup. These do not change often and the agent reads them automatically. This is the most reliable memory mechanism because it lives in version control with your code.
The SQLite database is for cross-session tracking. I use it for migration status, known issues, and findings that span multiple projects. A customer support agent might track user preferences here. A coding agent tracks technical debt and architectural findings.
Store full conversation logs separately if you need them. The memory hierarchy for AI systems makes the case for separating structured state from raw log data. The log is append-only and grows unbounded. The structured state is what the agent uses to make decisions. I keep a sliding window of recent log entries for reconstruction and serialize the structured state independently.
What This Means for Long-Running Codebase Work
If you are working on a codebase over weeks or months, the memory architecture matters more than the model choice. A Sonnet 4 with good memory discipline outperforms an Opus 4 with none. The reason is straightforward: a model that can access relevant context from six months ago will make better decisions about a large refactoring than a model that starts fresh every session.
The episodic, semantic, and working memory map I wrote covers this in detail. Episodic memory is what happened in specific sessions. Semantic memory is what the agent knows about the codebase as a whole. Working memory is what is active right now. Coding agents are good at working memory, poor at episodic memory without explicit serialization, and inconsistent at semantic memory unless you maintain the project files.
The practical implication is that you need to treat memory management as part of your workflow, not an optional feature. Before starting a large task, establish what the agent needs to know. During the task, serialize significant findings. After the task, verify that what you want remembered was actually written to a persistent layer.
If you want to understand the broader context, state of AI agent memory in 2026 covers the full landscape of memory approaches across different agent systems. The patterns are similar even if the implementations differ.
The agents that ship with real memory discipline are still the exception. Most coding agents give you the tools and expect you to know how to use them. Once you understand how the persistence layers work, the forgetting problem is solvable. It just requires treating memory as something you architect, not something that happens automatically.