condensate

How it works

Context windows and memory

How Condensate keeps long tasks inside the model's context window.

On this page

Every model call has a finite context window, and a long task outgrows it. This page explains when Condensate reduces the context sent to the model, which reduction it uses, who writes the summary and how each engine applies it. The thread's durable record is never rewritten.

The log stays. The next model input changes.
Durable history
RequestReadsToolsDecisionsRecent work
Recorded events remain available to inspect.
↓ model-facing projection ↓
Next model input
RequestReadsToolsDecisionsRecent work

Earlier messages compete with new work for a finite context budget.

Conceptual example, not a token measurement. A summary is one reduction strategy; the planner also supports cheaper tool-result reductions.

History and context

History answers “What happened?” Context answers “What will the model see on its next call?” A context reduction changes the second and leaves the first intact.

The thread log is append-only. A window is recorded as an event that says where the cut is, and the model-facing view is rebuilt from the log on each call. Nothing already in the log is rewritten.

For example, a large file read may remain useful as historical evidence even when the next model call only needs a receipt and the recent conversation. The agent can read the file again when it needs the details.

When a window is taken

A window is planned before a model call when the next prompt would go past the session's working ceiling. The ceiling is a share of the model's own window, kept below it because every call resends the whole prompt and long prompts are slow. By default it is 40 percent of the window for Condensate's own agent and Codex, capped at 120,000 tokens, and 75 percent for Claude Code, capped at 200,000, with a floor of 48,000. CONDENSATE_WINDOW_CEILING_CLAUDE, CONDENSATE_WINDOW_CEILING_PI and CONDENSATE_WINDOW_CEILING can lower it, never raise it. The _PI variable covers both Condensate's own agent and Codex. Room for the reply is kept separately, as an output reserve below the ceiling. The planner measures the last prompt the provider counted, then adds an estimate for what has been appended since.

When a window is due, Condensate tries the tiers from cheapest to most expensive:

  1. microcompact is tried first. If it frees less than 10 percent of the context, or the prompt still lands over the ceiling, Condensate moves on.
  2. collapse is tried the same way.
  3. summary is the last tier. It is always taken once it is reached.

A tier that has already run since the last summary is not repeated. A collapse is never followed by the microcompact it already covers.

Some conditions hold a window back, because a cut in the wrong place would cost more than it saves:

ConditionWhat Condensate does
The fixed baseline (system prompt and skills) takes up most of the ceilingRaises the ceiling so the baseline uses at most three quarters of it, up to the model's own window. Only when even that leaves less than a quarter free does Condensate report that windows cannot help, rather than cutting
A delegated child thread has not been joined yetKeeps the spawn and everything after it verbatim, so the child's result is not lost. The window waits if nothing above the spawn is worth cutting. A forced window, where the provider has refused the prompt, cuts anyway
Windows come too often: three within three turns, three summaries within ten minutes, or a summary that freed less than 10 percentStops windowing for now and records that as a system line, instead of summarizing the same content again and again

Reduction strategies

The window planner supports three operations, from cheaper reductions to a summary:

OperationWhat changes in the model-facing viewWhy use it?
microcompactClears older tool results the model can read again, such as file reads, searches, and diffsLarge read results can usually be obtained again
collapseAlso clears older action results, such as commands and edits, and leaves a receipt for eachThe model keeps a record that the action happened without its full output
summaryReplaces an older part of the conversation with one summary and keeps the most recent part verbatimCarries forward a shorter account of earlier work

Cheap tiers never clear small results or the most recent tool results. Memory and control results, such as recall, retain, approvals, and compaction tools, are only ever replaced by a summary.

The window kinds are defined in packages/engine/src/window/projector.ts:

export type WindowKind = "microcompact" | "collapse" | "summary";

A summary can invoke a curator model. The other transformations do not inherently require an additional model call.

Who writes a summary

A summary has one of three authors:

AuthorWhen it applies
The thread itselfThe thread answered a compaction request with its own summary. Condensate uses that text as written and records the thread as the author.
The curatorAny other summary. The curator writes the summary in one call with no tools. It runs first on a fast model set by CONDENSATE_CURATOR_MODEL, with thinking turned off where the model allows it. If that model does not answer, CONDENSATE_CURATOR_FALLBACK_MODEL is tried, and after that the thread's own model.
The systemLast resort. The curator has 180 seconds plus 10 seconds per 10,000 tokens in use (CONDENSATE_WINDOW_DEADLINE_MS overrides this). If it misses that while there is still room, the cut waits and the turn goes on uncut. If the window is forced, because the prompt is at the model's hard limit, Condensate drops the earlier messages without a summary. The window then tells the model that this happened and asks it to reread the brief, the latest steer, and any file before relying on it.

The curator is told to keep every failed tool call with its error text, and every human message, verbatim. It treats earlier summaries as history, not as things a human said. Failures are kept because they are usually the history a resumed agent needs most.

Head threads

A head thread keeps more of its context than other threads. Its line is the model's own window, less the output reserve and room for one more tool result, not the working ceiling.

On the API engine, Condensate's own loop, a head is compacted automatically. When its prompt crosses its line, the runtime cuts it down the same ladder as any other thread, and the curator writes any summary. Nothing asks the head, and nothing waits for an answer. A head can hand over its own summary first with compact_context, or ask for a microcompact with compact_microcompact. The runtime takes that request before the head's next model call, in place of the curator's summary. Neither tool is required.

On Claude Code and Codex, a head is not cut on Condensate's own initiative. When its prompt crosses its line, the runtime asks the head to compact through POST /threads/:id/compact and waits for an answer. If nobody answers before the deadline, the runtime cuts on a summary it writes itself.

Operators and tools can look at and answer a pending ask, or request a compaction, with these calls:

CallPurpose
GET /threads/:id/compactShows the pending ask, any compaction already requested, and a preview of what a cut would remove
POST /threads/:id/compactAnswers the pending ask with mode set to summary, microcompact, or decline. The body can also carry keepFrom, summary, reason, and seat. With nothing pending, a summary or microcompact answer queues a compaction. The session takes it at its next tool boundary or, failing that, at the start of its next turn. A decline with nothing pending is refused with nothing-pending.

A thread with more than one session needs the seat parameter or body field. Without it, the call is refused with seat-required.

Inspect a window

Each window is recorded as an event. The event carries the cut point, the line where the kept range begins, the kind, the summary, its author, and the numbers that triggered it. The projector uses these records to build each next model-facing view, so a summary is always tied to a recorded context transition and never to an unexplained rewrite of the conversation.

To inspect the underlying history, request history mode. Replace the thread ID before running this read-only request:

export THREAD_ID='replace-with-an-existing-thread-id'
curl -fsS \
  "http://127.0.0.1:4741/threads/$THREAD_ID/tail?after=0&limit=100&history=1"

limit defaults to 200, and any value above 1000 is clamped to 1000. Page through nextAfter while hasMore is true. History mode also returns events older than the latest snapshot, which ordinary reads skip.

How each engine applies a window

Condensate's own agent (the native loop). The window check runs before every model call, including the calls that follow tool results. If the provider still refuses a prompt as too large, the loop takes one forced window, clears the largest kept tool results until the prompt fits, and makes the call again.

Claude Code. The checkpoint runs after tool use. When a window is due, Condensate forks the Claude session at its root's first safe point and starts the fork with the rendered window as its first message. When a fork would only rebuild a prompt the provider has already refused, such as a session with no measured call yet or a head that left the ask unanswered at overflow, Condensate starts a fresh Claude Code session instead, with the window as its first message. A "Prompt is too long" result forces a window even when the last count was under the ceiling.

Codex. Condensate checks after each completed turn. When a window is due, it interrupts the turn, waits for running tools to finish, and starts a fresh Codex thread with the same persona, tools and permissions. The window goes in as one historical-context message. Codex's own auto-compaction is pushed out of reach so the thread log stays the record. That is a mitigation only: Codex can still compact on its own when a prompt overflows. When it does, Condensate notices the compaction, records a notice, and drops any compaction ask still open for that session. If the curator cannot write a summary, the send fails instead of falling back to Codex's compaction. Set CONDENSATE_CODEX_WINDOWING=0 and restart the session to hand compaction back to Codex.

Subagents. A Claude subagent has its own context. The checkpoint only sees the top-level session's tool results, so it does not window a subagent's context.

If no tier can cut and the next prompt would still be over the ceiling, the turn stops with a stated reason. It does not send a prompt over the ceiling.

Limits of a summary

A model may need to reread a file or prior evidence after compaction. Durable storage preserves the material to inspect; it does not make every earlier detail available in the next model call.

The curator can also consult long-term memory. When a memory service is configured, through CONDENSATE_HINDSIGHT_URL for Hindsight, the curator asks it for reference notes and waits about one and a half seconds. A slow or failed recall costs the summary nothing: the curator writes it without those notes.

Long-term memory is a separate service. A deployment can have durable threads and window compaction without enabling that memory service.