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

Compaction survival

Long-running conversations eventually hit the context-window limit, and the usual escape — summarize and compact — silently discards whatever only existed in the window. This pattern makes compaction safe: checkpoint() persists the working context as a durable entry before you compact, and the fresh window seeds itself from memory. Use it any time an agent conversation can outlive one context window.

How it works

window fills → checkpoint() → compact → new window seeds from get_context() → continue

checkpoint(context_snapshot=..., label=..., metadata=...) writes a checkpoint entry to long-term memory — a durable snapshot of task state, independent of both the LLM window and the run's live working memory. The response returns checkpoint_id and a token_estimate for the snapshot. After compaction, the new window recovers the state two ways:

  • Assembled: get_context() includes a checkpoints section in its priority order, so a resume query brings the snapshot back alongside rules, lessons, and facts.
  • Targeted: fetch only checkpoints with mode="sections", sections=["checkpoints"], or recall them directly with entry_types=["checkpoint"].

Don't confuse this with working memory's own lifecycle. Working-memory variables decay and expire automatically — that's the runtime pruning scratch state, not you preserving it (see Working memory vs long-term memory). A checkpoint is the deliberate act: you choose the moment and the content, and the snapshot survives runs.

checkpoint()Working-memory decay
TriggerYou call it (pre-compaction, risky transition, handoff)TTL expiry, relevance pruning
ContentWhatever snapshot you passLive variables, verbatim
LifetimeDurable — survives runsThe current task
Recoveryget_context() / recall()None (or runtime graduation to LTM)

Walkthrough

At Nimbus, Ari's escalation for Acme Corp's CSV-export incident reaches turn 80 and the window is full. Three attempted fixes, a pending approval from Rex, and the current hypothesis exist only in the conversation. Before compacting:

cp = client.checkpoint(
    session_id="nimbus:ari:esc-2201",
    label="pre-compaction-turn-80",
    context_snapshot=(
        "Escalation TCK-2201 (Acme CSV export). Reproduced at 500k rows. "
        "Tried: retry (failed), cache flush (failed), batched exporter (works, "
        "pending Rex approval). Next: confirm approval, then close with postmortem."
    ),
    metadata={"ticket": "TCK-2201", "turn": 80, "pending": "rex-approval"},
)
checkpoint_id = cp["checkpoint_id"]
 
# ... compact the conversation with your framework ...
 
# Fresh window: seed from memory. The checkpoint comes back as its own
# section, alongside the rules and lessons the task still needs.
seed = client.get_context(
    session_id="nimbus:ari:esc-2201",
    query="Resume the Acme CSV export escalation where it left off",
    max_token_budget=1200,
)
messages = [{"role": "system", "content": BASE_PROMPT + "\n\n" + seed["context_block"]}]

Nothing durable was lost: the compacted turns are gone from the window, but the task state, the pending approval, and the next step were re-derived from memory, not from a lossy summary alone.

Scoping reflection to "since the checkpoint"

The checkpoint also becomes a temporal anchor. The reflect request accepts a checkpoint_id so reflection considers only evidence created after that checkpoint — useful when the pre-compaction half of the run has already been reflected on. Rust forwards it as a typed field:

use mubit_sdk::ReflectOptions;
 
let lessons = client.reflect(ReflectOptions {
    run_id: Some("nimbus:ari:esc-2201".into()),
    checkpoint_id: Some(checkpoint_id),
    ..ReflectOptions::default()
}).await?;
ℹ️Note

checkpoint_id is a wire-level field on the reflect request — the typed Python and JS reflect() helpers do not forward it. Use the low-level passthrough (client.advanced.reflect({ run_id, checkpoint_id }) in JS; in Python too from SDK v0.12.0) or, on Python 0.11.0 and earlier, send it directly over the transport (POST /v2/control/reflect with {"run_id": ..., "checkpoint_id": ...}).

When not to use it

Skip the ceremony when the task fits comfortably in one window, and don't checkpoint every turn — knowledge that is already durable as typed entries (facts, lessons, traces written along the way) needs no snapshot. Checkpoint at the moments that matter: before compaction, before a risky transition, before a handoff. For reversible what-if exploration, a core branch session is the better tool — see Sessions & branching.

Related