The first time I watched a coding agent forget a six-hour refactoring session, I assumed it was a bug. It was not.

The forgetting was the designed behavior of a system that treats memory as optional.

Working with Claude Code on a Django-to-FastAPI migration, I had watched the agent map out the entire model layer, document the migration order, and track 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.

Claude Code is not unusual here. 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

Forgetting comes from how these agents are architected. A coding agent running in a terminal operates in layers that each retain information differently.

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. None of that is 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 broader point about why context windows and memory are not the same thing is worth internalizing before you try to fix persistence issues, because the failure modes are different and so are the solutions.

Project-level memory files form the second layer. Claude Code uses CLAUDE.md in your project root.

Cursor uses similar project memory conventions. These files persist across sessions and survive restarts, though the agent does not update them automatically.

Cross-session persistent memory is the third layer. Claude Code has a SQLite database at ~/.claude/memory.db that stores what the agent learns across sessions.

The database only exists once you run the agent with the --memory flag. Without that flag, nothing is created, and every session starts fresh.

An agent can have access to working context, project files, and persistent memory while its operator treats them as one system. The agent looks like it has memory because you have been working with it for days.

Restart the terminal, though, and the session layer is gone. The project files still hold what you wrote manually.

The SQLite database, if it exists, holds what the agent chose to record. That uneven combination is what makes the experience feel inconsistent: one day the agent recalls a decision you never wrote down, the next day it forgets a constraint you mentioned an hour ago.

Context Window as Sliding Window

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 follows.

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.

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 scoping behaves like a per-project drawer rather than one shared shelf: a fact the agent learned about api-gateway does not bleed into your work on billing-service unless you go pull it across yourself.

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, all of them genuine findings like which service owned a shared schema. I have also run sessions where the count stayed at zero because I never asked the agent to track anything, even after an afternoon of real work.

The project file CLAUDE.md works differently. You write it.

The agent reads it on every session start, yet it does not update it unless you specifically ask. Read-only access by default is intentional. CLAUDE.md is your file, encoding your decisions, and the agent respects that ownership the way it would not silently rewrite a config file you committed.

The Failure Modes to Check

Context window exhaustion is the failure mode that bites most coding agents. During a large task, the agent accumulates file reads, tool results, and reasoning in the context window.

A large context window can still fill during a repository migration. Each opened file, tool result, patch, and test run consumes part of the same finite budget.

The agent started dropping older file contents from context and making decisions based on incomplete information. It happened with no error, the same way a person three hours into a meeting answers confidently about a slide they no longer remember.

Just quietly wrong code, like reintroducing an import I had already told it to delete.

Checkpointing is the fix. For long tasks, I write periodic summaries to CLAUDE.md or the SQLite database, usually after every handful of files: which modules are done, which are still pending, and any decision that would be expensive to rediscover.

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. A stable SQLite schema does not mean the content written into it stays compatible with every reader.

An entry written six months ago might use a format that the current agent interprets differently, like a note that says "use the new auth flow" when there have since been two newer ones. To handle that, I review and prune memory entries monthly.

Entries older than 90 days get audited. When 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 when the persistence layer is not connected properly.

Diagnose it with a specific test: start a session, do meaningful work, close the terminal, open a new session, and ask the agent what it remembers. An answer of nothing means 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.

When it is the second case, you need to prompt more explicitly. A line like "remember that the auth service uses JWT with RS256" triggers a database write where a passing mention of the same fact will not.

The practical guide to AI memory management for LLMs covers the eviction and retention decisions behind what gets written and what gets dropped, which helps explain why some entries appear and others do not.

Reach for CLAUDE.md for what you know the agent needs on every session: architecture decisions, coding standards, team conventions, environment setup, the fact that tests run under make test and not pytest directly. These do not change often and the agent reads them automatically.

Living in version control with your code makes it the most reliable memory mechanism you have.

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 layered memory model 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

Across weeks or months on the same codebase, the memory architecture matters more than the model choice. A Sonnet 4 with good memory discipline outperforms an Opus 4 with none.

A model that can access relevant context from six months ago, like the reason a particular table was denormalized, will make better decisions about a large refactoring than a model that starts fresh every session and proposes undoing that choice.

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.

All of which means treating 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.

For 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 when the implementations differ.

Agents that ship with real memory discipline are still the exception. Coding agents mostly 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.