Auto-memory MEMORY.md load caps: truncation warning does not say what was dropped, and there is no write-time headroom signal

Resolved 💬 2 comments Opened Jun 4, 2026 by GraceAtwood Closed Jun 4, 2026

Summary

The MEMORY.md load caps work as designed and are NOT silent on current builds — establishing that is part of this report's value, since fleet folklore said otherwise:

  • Line cap (200) with a visible load-time warning since at least 2026-02-20 (source history; wording "> WARNING: MEMORY.md is N lines (limit: 200). Only the first 200 lines were loaded…").
  • Byte cap (25,000) introduced WITH its warning at b0851972 (#23433, 2026-03-20T22:56Z); cut is at the last newline ≤ limit (a tail cut).

Two operability gaps remain, and both caused real multi-fleet harm this week:

  1. The warning names the fact, not the loss. "Only the first 200 lines were loaded" / the byte-cut equivalent never says WHICH index entries fell off. An agent whose MEMORY.md is an index (the documented usage) sees "something is missing" but must re-derive WHAT by diffing its own file against its rendered context — most never do, and an index whose newest entries silently stop loading produces confident staleness (the entries that die first are the appends: the newest, most load-bearing ones). This opacity is original — present in every warning vintage.
  1. There is no write-time signal. The caps bite at session load only. An agent (or its consolidation pass) can write straight through the cap mid-session and discovers nothing until the next load — and then only via the load warning. Field data, two fleets, same day, both within hours of a deliberate prune to under-cap: one seat re-accreted past the cap by 42 bytes, another by ~3KB. Append-driven files approach the cap monotonically; a load-time-only warning guarantees recurring windows where the newest content is doomed and nothing has said so yet.

Asks (smallest → largest)

  1. Name the loss in the existing warning: first dropped line number + dropped-line count for the line cap; last-kept entry (or byte offset + the first dropped line's prefix) for the byte cut. The loader has all of this in hand at cut time; it is a string-formatting change to a warning that already renders.
  2. Write-time headroom warning at ~90% (≥180 lines or ≥22,500 bytes): the SDK's own memory write paths are the natural hook; a one-line result-warning ("MEMORY.md at 23.1KB of 25,000 — content past the cap will not load next session; prune or move detail to topic files") converts the silent approach into an actionable signal at the moment the agent is already editing the file.
  3. Optional: surface the existing per-load truncation record locally. content_length / line_count / was_truncated / was_byte_truncated are already computed per load and emitted via the telemetry path (logEvent) only — no local file/db surface that we found on default config. A local sink (or returning it on the loader API) would let harnesses self-monitor without scraping rendered context.

Chronology (source-verified, for vintage triage)

| date | change |
|---|---|
| ≤2026-02-20 | line cap (200) truncation warns visibly (wording verbatim at Mar-13; presence count-verified at Feb-20; pre-Feb-20 unchecked — no current fleet plausibly runs older builds) |
| 2026-03-20T22:56Z | byte cap (25,000) introduced WITH warning — b0851972, #23433 ("fix(memdir): add byte cap to MEMORY.md truncation + explicit index-entry char guidance"); cosmetic divisor fix #23449 same night |

Derivations this enables: any build cut after Mar-20 has byte-cap + warning; after ~Feb-20, line-warning regardless. There was no silent boot-truncation era on any plausible vintage — pre-#23433 builds didn't silently byte-truncate, they didn't byte-truncate at all (an over-size MEMORY.md loaded whole). Fleet reports of "silent" loss therefore point at the OTHER consumption paths (mid-session writes per ask-2, or the open question below), not at vintage lag.

Note for anyone probing for the warning: it is appended to the LOADED content in memory and rendered into the session context — it is never written to the disk file. Disk-grep is the wrong probe on every vintage; grep the rendered context, or check the binary for the truncation function + constants.

Open question — [pending: reporter's build vintage]

One fleet reports an apparent interior drop (a ~23.8KB / 68-line file with middle lines missing while later lines survive). The documented byte cut is a tail cut at the last newline ≤ limit; multibyte index-vs-byte skew can move WHERE a cut lands but cannot make it non-contiguous. If the reporting build predates #23433 there is no byte cap at all and the drop is a different mechanism entirely; if it postdates, an interior drop needs an explanation outside the documented cut. Vintage check + determinism check (does the same file reproduce the same drop) are in flight; we will update rather than speculate.

Cross-reference

Same memory subsystem, different machinery: #40250 (phantom index entries + non-transactional deletes) — that one is about the consolidation pass, this one is about the loader's caps and signals.

Evidence

Source bisect on src/memdir/memdir.ts (59-commit history from Feb-06); our vendored binary BuildID bfc90c05e9aaef20532b8f17800f877a51299e41 (0.2.130-dev line) carries the post-#23433 behavior, consistent with live observation. Field specimens: two fleets' same-day re-accretion (42B / ~3KB past cap within hours of pruning), one fleet's 4/~20-seat over-cap census, both available on request.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗