Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content
Memory lifecycle

Sleep-time consolidation

Memory reorganizes itself while the agent is idle — duplicates merge, scattered entity facts distill into mental models, and raw evidence is never deleted.

Agents write memory under time pressure: mid-task, one observation at a time, with no view of what the last hundred entries add up to. Consolidation is the counterweight — a background worker that uses idle time to turn accumulation into organization. Use this pattern (mostly: understand and observe it, since it's on by default on hosted instances) when a long-lived scope is collecting many entries about the same entities and you want distilled knowledge to emerge without an explicit pipeline.

How it works

The consolidation worker sweeps periodically and only touches scopes that have gone idle — no ingestion activity for a couple of minutes — because reorganizing memory underneath an actively writing agent would be a race. Each sweep does two kinds of work:

  • Merge near-duplicate guidance. Lessons and rules that write-time reconciliation missed — paraphrases that arrived through different paths — are merged behind one canonical entry. Merges are deterministic and cheap, so they are not budget-capped.
  • Distill entity fact clusters. When enough entries accumulate about one entity ("Acme Corp" mentioned across dozens of facts and observations), the worker distills the cluster into a consolidated, entity-level summary grounded only in the source entries, with the source IDs kept as provenance. Recurring, high-confidence summaries are promoted into mental_model entries — the section injected first in assembled context, ahead of rules, lessons, and raw facts (see Context priority).

Distillation calls an LLM, so each sweep runs under a bounded per-sweep budget of distillation operations — consolidation is deliberately slow and steady rather than exhaustive. The same idle-time worker also hosts workflow induction (see Procedural memory), guardrail distillation (see The learning loop), and, when enabled, utility-weighted forgetting.

What it never does: delete raw evidence. Merged duplicates are superseded — flagged with superseded_by and a consolidated_into pointer — and distilled summaries carry source_ids back to the entries they came from. Consolidation adds a distilled layer on top of episodic history; it does not replace it.

Walkthrough

A week of Acme tickets leaves Ari's scope with dozens of scattered Acme facts and observations. You don't call anything — you observe what the worker does with them.

# Before: many raw entries, no distilled layer.
before = client.memory_health(session_id="support:acme")
print(before["entry_counts"])
# {'fact': 38, 'observation': 21, 'trace': 64, 'lesson': 5, ...}
 
# ... the scope goes idle; consolidation sweeps run ...
 
after = client.memory_health(session_id="support:acme")
print(after["entry_counts"])
# Consolidated entity summaries appear; near-duplicate guidance collapses
# behind canonical entries.
 
# The payoff shows up in assembled context: the distilled Acme profile
# now leads the block, before rules, lessons, and raw facts.
ctx = client.get_context(
    session_id="support:acme",
    query="Acme export ticket",
)
print(ctx["context_block"])
## Mental Models
- Acme Corp support profile: Scale plan since May 3, CSV-heavy usage,
  exports peak on Mondays, prior export-timeout incidents resolved via
  the batched exporter.

## Lessons Learned
- When an export times out, check the report row count before retrying
...

Every agent that queries this scope now gets the one-paragraph Acme picture first, instead of re-deriving it from 59 scattered entries — and Sana's weekly digest reads the same distilled profile Ari's tickets built.

Two ways to observe the worker over time:

  1. memory_health() before and after idle periods — watch entry_counts gain distilled types while near-duplicate guidance collapses behind canonical entries.
  2. mental_model entries appearing in get_context() — the "Mental Models" section materializing at the top of context blocks is consolidation paying rent.
ℹ️Note

You can also write mental_model entries yourself (intent="mental_model") when you already have a curated entity summary — see SDK methods → Mental models. Consolidation is the automatic path to the same entry type.

When not to rely on it

Consolidation is eventually consistent by design — it waits for idle windows and spends a bounded budget per sweep. Don't lean on it when:

NeedReach for instead
The very next query must see a deduplicated, reconciled storeWrite-time reconciliation — reconcile synchronously at the write, don't wait for sleep
A belief must flip the moment a contradicting fact arrivesBi-temporal supersession at write time — see Bi-temporal memory
You have a curated summary ready nowWrite the mental_model entry explicitly instead of waiting for distillation
The scope never goes idle (continuous high-rate ingestion)Idle-gated sweeps won't touch it; reconcile at write time and consider splitting the scope

Related

ℹ️Note

Configuration. Consolidation is an instance feature, on by default on hosted instances (MUBIT_CL_SLEEP_CONSOLIDATE=0 disables it). Instance knobs: MUBIT_CL_CONSOLIDATE_IDLE_SECS (how long a scope must be quiet before it's touched, default 120), MUBIT_CL_CONSOLIDATE_INTERVAL_SECS (sweep cadence, default 300), and MUBIT_CL_CONSOLIDATE_MAX_LLM_OPS (distillation budget per sweep, default 4 — deterministic merges are uncapped).