Memory that stays accurate as your agent learns.
Every write improves memory. But over months of sessions, files accumulate noise — stale preferences, overlapping facts, partial updates that were never reconciled. A compaction pass reads all memory, merges what matters, and discards what doesn't. MemexAI revision history means the merge is always reversible.
Memory that grows also degrades.
The first few sessions write clean, high-signal facts. Then the user changes their mind. A preference gets updated but the old entry stays. Two sessions write similar facts in slightly different words. A goal that was written three months ago is no longer relevant — but the agent still reads it on every call.
The prompt block grows. Retrieval starts returning older, lower-quality matches alongside fresh context. The agent's behavior becomes inconsistent — not because it forgot something, but because it's reading too much conflicting information at once.
With embedding-based memory, this problem is invisible. You can't see which entries are redundant. You can't tell which old fact is winning retrieval over a newer correction. You can't clean the index without risking deleting something important.
With file-based memory, the problem is at least visible — you can open the files and see the noise. But cleaning it by hand doesn't scale, and a compaction agent that writes without an audit trail is a liability rather than a solution.
Compaction that's auditable by design.
MemexAI's file-based memory is both the reason compaction is tractable and the reason it's safe. You can read all files, pass them to an LLM, and write back a merged result — and every version is preserved in revision history.
The compaction agent
Call user.list() to enumerate all memory files for a user, read each one, send them to an LLM with a merge instruction, then write the result back. The reason field on the write tags every revision with 'scheduled-compaction' so you can distinguish compaction writes from agent writes in the access log.
import { createMemex } from '@memexai/core'
import { generateText } from 'ai'
const memex = createMemex(DATABASE_URL)
async function compactMemory(userId: string) {
const user = memex.forUser({
userId,
actor: 'compaction-agent',
})
const { files } = await user.list()
const contents = await Promise.all(
files.map(f => user.read(f.path))
)
const { text: compacted } = await generateText({
model,
system: `Merge, deduplicate, and tighten these memory
files. Remove stale or redundant facts. Return one
clean Markdown document.`,
prompt: contents
.map(c => `## ${c.path}\n${c.content}`)
.join('\n\n'),
})
await user.write(
'user/profile.md',
compacted,
'scheduled-compaction',
)
}What you get
Every compaction write creates a revision. The admin console shows you exactly what changed — the full content before and after, the timestamp, and the actor field identifying the compaction agent. If the LLM merged something incorrectly, you can roll back to any prior revision in seconds.
Run compaction as a cron job triggered after a user's memory has been quiet for a defined period — consistent with the background dreaming pattern. Quiet memory is a signal that the user's context has stabilized and is worth consolidating.
The shared/ namespace can hold a compaction prompt you tune over time — instructions for what to preserve, what to discard, and how to structure the merged output. Update the shared file and all future compaction runs reflect the change without a deployment.