[FEATURE] Make the auto-memory MEMORY.md index size limit (200 lines / 25KB) configurable

Status Open
Maintainer reply None cached
Activity 11 comments · opened Jul 19, 2026

Feature request

Make the auto-memory MEMORY.md index size limit configurable.

Current behavior

Per the memory docs, only the first 200 lines or 25KB (whichever comes first) of MEMORY.md is loaded into context at session start. When a write would exceed the threshold, the write errors and the model is prompted to rewrite/compact the index.

The limit is hard-coded: the only memory-related configuration today is autoMemoryEnabled / autoMemoryDirectory (settings) and CLAUDE_CODE_DISABLE_AUTO_MEMORY (env). There is no setting, env var, or flag to raise the index cap.

Problem

For heavy, long-lived projects the 25KB byte cap becomes a constant ceiling:

  • Our main project accumulated ~500 memory files. Even with the documented best practices applied (hub/topic files, one-line index entries, regular pruning), the index sits at ~17KB across only 41 lines — the line limit is irrelevant; the byte cap is the binding constraint.
  • Each over-limit event forces another compaction pass. Repeated compaction produces ever-denser, less-readable index lines and the index just re-approaches the cap, so the error recurs "constantly" in practice.
  • The trade-off (a larger index costs context-window budget) is one users should be able to opt into per project — a machine-local setting spending a few extra KB of context is a reasonable trade for reliable recall in high-activity repos.

Proposed solution

A settings.json key (e.g. autoMemoryIndexMaxBytes and/or autoMemoryIndexMaxLines), or an env var equivalent, that raises the load/write threshold for MEMORY.md. Keeping the current 200/25KB as the default is fine — the ask is only that power users can lift it.

Environment

  • Claude Code v2.1.215 (native macOS arm64 binary)
  • macOS (Darwin 25.4.0)

View original on GitHub ↗

3 Comments

dannybyrnes · 1 month ago

Seconding this, from the opposite shape of the same problem — and with a case where the compaction target is arithmetically unsatisfiable, which I think points at the root issue: the thresholds are fixed constants that don't scale with memory count.

@zzelner's case is ~500 files where the byte cap binds and the line cap is irrelevant. Mine is the inverse.

Environment: Claude Code 2.1.219 (Claude Desktop, macOS 26.5.2), 146 memory files, index at 17.3KB / 182 lines — both caps near-binding at once.

The compaction prompt fires with a target of 70% of the cap: "under 140 lines" against the 200-line cap, "under 17.1KB" against the 24.4KB cap. But the memory instructions require one line per entry, so 146 memories have a floor of ~178 lines before frontmatter and section headers. The 140-line target cannot be met without deleting roughly 40 memories. No compaction satisfies it; the message fired repeatedly through a long consolidation pass, each time demanding a number arithmetic rules out.

The wording is what I'd flag hardest:

Compact it to under 140 lines now: keep one line per entry, move detail into topic files, and merge or drop stale entries.

At this file count those instructions are mutually exclusive — "one line per entry" and "under 140 lines" cannot both hold with 146 entries — so the only remaining lever is "drop." An agent following the hook literally deletes the user's durable memories to satisfy a lint threshold. I declined and said so to the user, but a less cautious pass would have quietly shed ~40 files, and the hook gives no signal that this is a judgment call rather than a defect to fix.

Two asks in addition to the configurable cap:

  1. Scale the target to entry count, or suppress the prompt once entries + overhead already exceeds it. A target that cannot be met is noise at best and destructive at worst.
  2. Reword so it cannot read as an instruction to delete user data. "Consider retiring memories that are no longer relevant" frames it as the user's call; "merge or drop stale entries ... now" reads as an order, and "stale" is not something the hook can actually assess.

One more data point supporting @zzelner's "ever-denser, less-readable index lines": before this pass, ~25 entries in my index had been compacted into truncated fragments — mode per-task &, test every table +, Keep platform's own literal — cut mid-phrase by earlier compaction rounds. Those are useless for deciding whether a memory is relevant, which is the index's only job. Repeated compaction against a fixed byte cap doesn't just shrink the index, it actively degrades it. Rewriting all 146 entries as complete, terse hooks brought it from 20.4KB to 17.3KB while making every line readable — but that headroom lasts only until the next dozen memories.

hjqcan · 1 month ago

A configurable ceiling would relieve the immediate failure, but I would avoid making a larger MEMORY.md the long-term scaling path.

The durable memory set and the startup index have different jobs. Durable records can grow; the loaded artifact should be a bounded, rebuildable projection. Once the projection no longer fits, compaction should rank or retrieve entries for the current project/task rather than rewrite every entry into increasingly lossy one-liners. Deleting or retiring a canonical memory must be a separate, explicit lifecycle operation—not a side effect of satisfying a context-budget lint rule.

GoodMemory uses that split in practice: canonical scoped records remain inspectable/revisable/forgettable, while fresh installed-host defaults bound the session brief to 1024 tokens and gated prompt injection to 512 tokens. The budgets can be tuned without shrinking the durable store, and generated artifacts are treated as projections rather than source of truth.

That model also gives the hook a safer response when entry_count + overhead > target: rebuild a smaller task-relevant view and report coverage, instead of issuing an arithmetically impossible “drop entries now” instruction.

Reference implementation: https://github.com/hjqcan/GoodMemory

mkavanagh2525 · 16 days ago

Adding a second site with the same failure, plus a measurement that I think answers the "curate better" response this request will otherwise get.

Scale

  • 357 memory files, about 3.7 MB total
  • MEMORY.md: 48 lines, 22,129 characters of loadable content
  • 8 topic sub-indexes already in use, so the hub-and-spoke pattern the docs recommend is applied

Same shape as the original report: at 48 of 200 lines the line limit is nowhere near binding, and the byte cap is the only real constraint.

Measured growth

Over the last 5 days the index grew 2,497 characters, about 499 per day, against roughly 2,900 characters of remaining headroom. That is under a week of runway, and this project has been in that state repeatedly rather than once. In the last 30 days, 95 commits touched MEMORY.md, and 12 of them name compacting, trimming or compressing the index as the work. One is titled, in full:

trim MEMORY.md the last 9 bytes under the 17.1KB budget

A commit whose entire content was 9 bytes of prose surgery. That is the same phenomenon as the 55-byte trim reported in #83114.

Why "curate better" is not the fix

We tried it, and measured it twice in the same project:

  • One trimming pass recovered 0.52 K-chars, while the index had grown 0.9 K-chars between that pass and the previous one. Trimming loses to accretion.
  • An earlier measurement in the same file put the return on a trimming pass at about 2 percent.

Compaction is not a fix that holds. It is a tax that recurs, and the interval between passes is set by how fast the project generates learnings, which is exactly the rate you would want to encourage.

The part that concerns me more than the tax

Compaction is a lossy operation on an index whose lines are load-bearing. This project has two commits that exist only to undo compaction damage:

  • one restoring six guards that a compaction pass had cut as if they were prose
  • one recording the general finding that trimming a pointer line is a deletion, written after three separate proposed cuts would each have destroyed the only surviving copy of a constraint

The reason is structural rather than a discipline problem. Index entries accumulate clauses because each clause was added by a session that had just been burned and judged a one-line pointer insufficient. Compaction pressure therefore does not squeeze out redundancy, because there is little. It squeezes out the least recently useful real constraint, and that failure is silent until the constraint is needed again.

The documented enforcement behavior is what makes this sharp:

If the file is over a limit, the write still succeeds, but Claude Code returns an error telling Claude to rewrite the index, because everything past the limit is dropped on the next load.

The write is not rejected, so the recovery path is the model performing lossy edits on load-bearing content, in band, in the middle of whatever the user actually asked for. And if a session ends without acting on the error, everything past the cutoff is simply absent next session, with nothing at load time indicating that anything is missing.

What would help

Any of these, roughly in order of value here:

  1. A machine-local setting to raise the cap, as this issue asks, so the context cost is opted into knowingly rather than imposed uniformly.
  2. A load-time signal naming what was dropped, so an absent constraint is visible rather than silent. Today the over-limit warning fires at write time, in a session that may have nothing to do with the entries at risk.
  3. An out-of-session curation path, so the work does not land on a session that is holding the user's real task in context.

Showing cached comments. Read the full discussion on GitHub ↗