Skip to content
Dan Hopwood

The memory bank framework

Updated: 8 min read

Updated July 2026: the framework originally had six files. progress.md turned out to be a hand-maintained copy of git log, so I retired it. The post now describes the five-file version – there’s a new section on why.

You come back to a project on Monday. You tell the agent what you’re working on and it proposes the solution you talked it out of three days ago.

You re-explain. The next session opens with the same amnesia and the loop starts over.

The fix I use is a structured memory layer called the memory bank: five files at the root of the project. The agent reads them at the start of every session and updates them after significant work. Cross-session context lives in files you control, not inside the session itself.

Five files

The memory bank concept originated with the Cline team and their documentation is worth reading in full. This post is my adapted version. I’ve been using it daily for a year and made a few opinionated changes along the way – I’ll flag those as we go.

Here’s the layout:

memory-bank/
├── project-brief.md     # Foundation: scope, requirements, goals
├── product-context.md   # Why this exists, problems solved, UX goals
├── tech-context.md      # Stack, setup, constraints, dependencies
├── system-patterns.md   # Architecture, patterns, lessons learned
└── active-context.md    # Working state: focus, blockers, open decisions

Four are stable: project-brief, product-context, tech-context, system-patterns. They describe what the project is and how it’s built, and they only change on pivots, refactors or significant lessons. One is live: active-context. The agent updates it as work moves, so it always reflects what’s happening right now.

The exact content boundaries and size limits are in this gist.

A memory bank folder open in Ghostty – five files visible in the sidebar, system-patterns.md open

There used to be a sixth file

The original layout had one more live file: progress.md – what’s done, what’s left, blockers. I retired it in June.

What sent me in was merge conflicts. I’d started running parallel worktrees on the same repo and the live files kept colliding when branches landed close together. So I measured how often those files actually changed: in my most active repo, 18 of the last 41 commits touched the memory bank. The collisions were real. But half of those 18 commits changed nothing else – they were standalone “update memory bank” passes that re-wrote what the commit message already said. One ticket racked up five of them. That was the bigger cost.

Then I pulled the last 20 commit messages from two repos. Each one was agent-written and they were genuinely good: the why behind the change, the review findings, what was verified. I put one ticket’s progress.md entry next to its commit message – same content and the commit was the better-written version. My repos squash-merge, so each ticket lands on main as a single curated commit. So progress.md was essentially a hand-maintained copy of git log main.

One distinction had to hold before I deleted it. Git records what changed but it’s blind to what you decided not to do. “We evaluated X and rejected it” produces no commit, because nothing changed. Without a note somewhere, the agent re-proposes X every session. That ‘don’t re-litigate’ content is the most valuable thing in the whole bank, and none of it belonged in progress.md anyway. It goes in system-patterns.md, the file built for lessons.

So the file is gone and a standing rule replaced it: git is the changelog – don’t re-narrate the diff into the memory bank. active-context.md is now the single live file: current focus, blockers and open decisions, capped at 80 lines.

The wider lesson: every piece of scaffolding in a setup like this encodes an assumption about what the model can’t do on its own, and those assumptions go stale. progress.md earned its place when agent commit messages were thin. They aren’t any more.

How to initialise it

You don’t write the files yourself. The agent does.

First time on a project, attach whatever foundation you have: a lean canvas, an architecture doc, a README, the front page of the marketing site. Then:

initialise memory bank

The agent creates the memory-bank/ folder, writes all five files and comes back with questions where the input was thin. Five minutes of back-and-forth and the project has a spine.

For multi-repo workflows, don’t copy-paste the instructions into each project’s CLAUDE.md. Put them in one place and import. Mine live alongside other coding conventions in ~/cli-agents/shared/coding.md and every project’s CLAUDE.md has this as the first line:

@~/cli-agents/shared/coding.md

Need to tweak the instructions? Update the shared file once and every project picks it up automatically. The gist below is the focused memory-bank-only snapshot if you want the framework on its own.

The session loop

A file structure on its own does nothing. What makes the memory bank work is the loop you run around it:

  1. Start a fresh session
  2. The agent reads all five memory bank files
  3. Do the task
  4. Commit the work
  5. Tell the agent: update memory bank
  6. Commit the memory bank changes
  7. /clear
  8. Next task → step 1

Three rules hold the loop together:

Never compact. Compaction is a lossy summary of a single session: what you reach for when the conversation outgrows the model’s context window. The memory bank is the opposite: structured files that persist across sessions, lossless by definition. With that structure in place, you don’t need compaction at all. Turn it off.

This is where I diverge most sharply from Cline’s official guidance, which recommends auto-compaction alongside the memory bank. The two systems work against each other. Auto-compaction makes the agent feel like it can run forever. That encourages long sessions, and long sessions generate bloated context – exactly what the memory bank exists to prevent.

One goal per session. Not a single task, because you’d be exiting every five minutes. Not a day’s work, because the session would bloat. A goal is what sits in between: the work that ends at a natural pause point. Rebuilding a page of a marketing site is a good example. You make a handful of improvements until the page feels done, then you commit, update the memory bank and exit.

My sessions tend to run 250–400k tokens. That’s plenty of work, and still a long way short of Opus’s 1M limit. Most people let sessions grow until the model starts losing the thread. Stop earlier.

Update before exit. When I tell the agent to update the memory bank, it doesn’t guess what changed. It runs git diff on the code since the last commit, reads all five files, and writes updates against that diff. Then it runs git diff on the memory bank itself to verify everything was captured and nothing important was lost in the edits. The whole thing takes 30 seconds. It catches the almost-right updates before the next session trusts them as gospel.

git diff of a memory bank update after a feature commit

What this buys you: /compact becomes dead weight. Every session starts clean, loads the same structured context, finishes short. There’s no long-running conversation to summarise because you didn’t let one form. Claude Code comes with five layers of context management for exactly the failure modes the memory bank prevents. Once the loop is in place, most of those layers stop earning their keep.

Discipline that keeps the files current

The memory bank only works if the files stay accurate. Four rules:

Full content boundaries, size thresholds and audit triggers are in the gist. Copy it, import it, adapt it.

Why it stuck

Install it because you’re sick of re-explaining your project.

Keep it because it stops your codebase drifting.

Why ‘drifting’ matters more than ‘forgetting’ is a longer argument – I wrote it up separately: Forgetting isn’t the problem.

Build Notes

Every Thursday morning. Discoveries from building Fidero entirely with AI agents – the patterns, tools and decisions that actually worked.

Read the latest issue


Share this post on:
Edit on GitHub
Previous Post
Forgetting isn't the problem
Next Post
Rebuilding fidero.com with an AI agent – the reference-doc-driven workflow