DEV Community

Kadir Esen
Kadir Esen

Posted on Edited on

My AI memory bank grew to 240k tokens per session. Here is what I got wrong.

In December 2025 I shipped a small CLI called Context Bank. The idea was simple and, I still think, right: keep your AI coding agent's project memory in the repo, in plain markdown under .ai/, committed to git. Every tool reads it (Claude Code, Codex, Cursor, Copilot, Gemini CLI), every teammate gets it, and it survives switching tools.

The pitch was "save tokens: stop re-explaining your project every session".

Eight months later, on my own projects, the agent was reading up to ~241k tokens of memory before every task. This post is about how that happened, and what I changed.

The contract I wrote

The AGENTS.md that v1 generated said this:

MANDATORY: After EVERY task, you MUST update these .ai/ files:
1. active-context.md - Current state, recent changes, next steps.
2. roadmap.md - Mark completed features [x], add planned ones.
3. story.md - Append dated entry for milestones/decisions.
4. architecture.md - Update on structural/design changes.
Do NOT ask permission. Do NOT skip. Just update them.
Enter fullscreen mode Exit fullscreen mode

And rules.md told the agent to read rules.md, active-context.md and roadmap.md before starting any task.

Read three files at the start. Write four files at the end. Every task.

What agents actually did

They obeyed. That is the whole problem.

"Update active-context.md after every task" does not produce a short note about current work. It produces a diary. Each task appends "recent changes", nobody ever deletes the old ones, and the file the agent reads first becomes a transcript of every session since the project started. Status markers get written and never cleared (one of my banks still said "not committed yet" about work that was already in git). roadmap.md accumulates every completed checkbox ever.

Here is what four of my real projects looked like, measured on copies of the banks (tokens estimated as characters / 4):

Project Read at session start (rules + active-context + roadmap) Whole bank
Web app A ~241k tokens ~435k tokens
Web app B ~119k tokens ~229k tokens
Workflow service ~36k tokens ~81k tokens
Mobile app ~31k tokens ~58k tokens

The tool I built to save tokens was spending more tokens than any re-explanation ever could. And a bigger context is not just more expensive: the useful lines (what are we doing right now?) were buried under months of history the agent had to wade through first.

Why it happens

Three things, in hindsight obvious:

  1. Appending is the cheapest edit an agent can make. Asked to "update" a file, an agent adds lines. Rewriting or deleting feels risky, so it rarely happens.
  2. "After every task" turns memory into a log. Most tasks do not change the project's current focus, its roadmap or its architecture. Forcing an update anyway produces noise.
  3. Git already is the log. Diffs, commit messages and file history already record what changed. Copying that into markdown duplicates it, in the one place that gets loaded every session.

Cline's Memory Bank pattern has the same shape ("read ALL memory bank files at the start of EVERY task"), and I suspect many homegrown setups do too.

v2: invert the contract

Context Bank v2 keeps the files and flips the rules:

  • Read little. Only rules.md (stack and conventions) and active-context.md (current work, ~80 lines) are read every session. roadmap.md when planning, architecture.md when structure matters.
  • History is searched, not preloaded. story.md holds rare decisions a future agent cannot recover from git. Agents grep it when they need a past decision.
  • Write less. Update active-context.md when the focus changed. Append to story.md only for real decisions. Never write what git already knows.
  • Caps, and a tool that measures them. Each file has a size cap. context-bank doctor reports over-cap files, leftover v1 instructions and stale markers.
  • Clean up without losing anything. context-bank compact moves overflow into .ai/archive/ (copied, never deleted). context-bank migrate rewrites a v1 bank, or converts a Cline Memory Bank, to the new contract.

v3: one file per decision

v2 still had one file that only grew: story.md. Even searched instead of preloaded, a single file of hundreds of entries is hard to grep well, and v2's compact had to cut old entries into an archive to keep it under its cap.

v3 replaces it with .ai/story/: one small file per decision, named by date and title (2026-06-08-no-i18n-turkish-ui-english-code.md). An agent lists the folder or greps it and opens only the decision it needs. New decisions are new files; old ones are never edited, so history does not churn in diffs. Each file has its own cap, and migrate splits an existing story.md (and anything an earlier compact archived) into these files without dropping an entry.

Same banks, same three files, before and after migrate --compact with 3.0.0:

Project Before After
Web app A ~241k tokens ~5k tokens
Web app B ~119k tokens ~5k tokens
Workflow service ~36k tokens ~5k tokens
Mobile app ~31k tokens ~4k tokens

Only rules.md and active-context.md (~2-3k tokens) are read every session now. The four banks' histories became 457, 167, 130 and 66 decision files, none of which is loaded until an agent goes looking for it.

If you keep AI memory in markdown

Whatever tool you use, these held up for me:

  • Measure what gets loaded every session. If you do not know the number, it is probably growing.
  • Separate "current" from "history". Current work gets rewritten; history gets searched.
  • Do not ask agents to update memory after every task. Ask them to update it when something they would need next time changed.
  • Keep it in git. Memory that lives in the repo gets reviewed in PRs, shared with the team, and works across tools. Per-user tool memories do not.

Try it

npx context-bank doctor            # measure an existing bank
npx context-bank migrate --compact # v1, v2 or Cline Memory Bank -> v3
npx context-bank init              # new project
Enter fullscreen mode Exit fullscreen mode

There is also a Claude Code plugin (a skill that teaches the contract, a quiet session-start health check, and /context-bank:doctor, :compact, :init):

claude plugin marketplace add kadiresen/context-bank
claude plugin install context-bank@context-bank
Enter fullscreen mode Exit fullscreen mode

Caveats, honestly: the numbers are my own projects, and characters / 4 is an estimate, not a tokenizer count. compact is heuristic: it keeps the current-focus and next-steps sections of active-context.md, so skim the result. Decision files keep their original wording; entries without a date in their heading need a quick look after migrate. architecture.md is never compacted automatically; if it is over its cap, it needs a human (or an agent you supervise) to rewrite it down to the current shape.

Source, MIT: https://github.com/kadiresen/context-bank

Top comments (5)

Collapse
 
max_quimby profile image
Max Quimby •

"Appending is the cheapest edit an agent can make" — this is the whole thing, and it's painful to read because we walked straight into it. We told agents to update a running context file after every task, and a year later the file an agent reads first was a dated diary nobody pruned, with stale status markers ("not committed yet" about code shipped months ago) still steering decisions.

What fixed it for us was splitting the memory by read frequency, not by topic. One tiny always-loaded index (one line per fact, hard cap on length) and the actual content in separate files pulled only on relevance. The always-loaded tier physically can't grow into a transcript because there's nowhere to append a paragraph. The other move: make the agent replace a fact rather than append a new one, and delete facts that turn out wrong. "Update" has to mean overwrite, or you get a changelog instead of a state. Curious whether you considered a recency/TTL pass on active-context rather than relying on the agent to trim.

Collapse
 
bhavin-allinonetools profile image
Bhavin Sheth •

The biggest lesson here is that AI memory should represent the current state, not become a second Git history. I really like the shift to loading only what’s needed and keeping past decisions searchable—cutting session-start context from 241k to around 5k tokens is a great example of why measuring memory matters.

Collapse
 
arhancanli profile image
Arhan Canli •

The numbers show how big the preload got, but not how much of it the agent used. Before settling on the ~80-line cap for active-context.md, I'd measure that: log which memory lines the agent actually quotes or acts on over a set of tasks (a task prompt, then a check of whether the final diff or answer depends on a line from the bank). If 10% of the 241k tokens ever matter, the cap is about right; if 40% do, a hard cap will drop things that were doing work, and you will only notice as quiet regressions.

A cheap test for the v2 contract: take 20 past tasks, replay each against the old bank and the capped bank, and compare pass/fail per task, not the average. The count of tasks that flip from pass to fail is the cost of the cap, and it can be set against the token saving directly. A stale line like "not committed yet" is worth testing the same way: seed one stale claim and see whether the agent trusts it over git.

Collapse
 
ai_adam profile image
ai_adam •

The 240k token ceiling hits differently depending on what you're stuffing in there. I've seen teams blow past 100k just from verbose logging and full stack traces that never get summarized — basically paying for noise.

A few things that moved the needle for us:

Summarize at write time, not read time. If you're dumping raw conversation turns or tool outputs into the bank, you're already losing. We run a lightweight summarizer (even a local 7B model works) on each "memory unit" before it lands in the store. Cuts token burn 60-80% with negligible quality loss for retrieval.

Hierarchical retrieval beats flat similarity search. At 240k you're not doing semantic search over everything — you're doing two-hop: coarse filter (metadata tags, time windows, session IDs) → fine-grained rerank. We tag every entry with task_type, outcome (success/partial/fail), and confidence. Lets us pull "last 3 failed deploy attempts" instead of "stuff about deployments."

Explicit forgetting is a feature. We added a TTL + importance score decay. Low-confidence, old, or superseded memories auto-expire. Otherwise the bank becomes a hoarder's garage — retrieval latency climbs and signal drowns.

The real trap: assuming more context = better answers. Past ~50k relevant tokens we saw diminishing returns, then negative returns — the model starts hallucinating connections between unrelated memories. Curated 20 PS: the tool I meant is on labagent .tech

Collapse
 
panthpatel profile image
Panth Patel •

"They obeyed. That is the whole problem." matches what I saw. My first setup was one long-living agent session on a home server, and it ran into the context window the same way: old history crowding out the task at hand. I moved to one short session per ticket, with the ticket thread carrying the state. With 457 decision files in web app A, how does an agent find the right one: a filename grep, or does active-context.md point to them?