Skip to content
Crystal CodeDocs
ENEnglish

Compaction

Crystal does not reduce context. Before each model round, and again before the post-turn compaction check, optional microcompaction may replace old successful tool results with Tool result omitted after compaction. It does not call a model. The last protectTurns user turns stay intact, then the newest protectTokens of older successful results stay intact. Older successful results are replaced only when the estimated size of the removed text is more than minimumTokens. The placeholder that replaces them is not subtracted from that estimate. User text, assistant text, and failed results stay. The walk stops at the previous summary. The archive, the screen, resume, fork, and export keep the original tool text. A rewrite is saved on the model transcript. The following compact decision then uses that transcript’s estimate, because the previous provider usage still counts the removed text. Microcompaction is off when microCompaction is omitted. /compact micro toggles it, and on or off sets it, writes config.json, and does not summarize. It is refused during a turn or compaction. /status adds a Microcompaction row only while it is on. Defaults are 2 turns, 40000 protected tokens, and 20000 minimum tokens. protectTurns must be at least 1. The token counts must be non-negative. Invalid values refuse startup. Full compaction’s own prune does not follow this switch.

When estimated transcript size or the last model-round usage crosses the lesser of the configured fraction of the model context window and the usable window (context minus reserved output), the host:

  1. Clears old tool results outside a protected recent band of 2 user turns and 40000 tokens, when that frees more than 20000 tokens.
  2. Asks for one structured summary of older turns, folding any previous summary, and keeps a recent tail verbatim. The tail is 25% of the usable window, at least 2000 tokens and at most 32000. That summary request follows the same retry policy as a model round. The session model writes it unless compactionModel is enabled. The summary prompt reserves min(session model maxTokens, 16384) tokens, and never more than half the effective summary window, so a window smaller than 16384 can still be summarized. A model without maxTokens reserves 16384 when the window is large enough. A summary whose finish reason is length is not stored.
  3. Stops if the summary request itself cannot fit or the summarizer returns nothing and prune did not help. The turn does not retry compaction in a loop.

CTX percent uses the last model round’s provider usage while a round is streaming, then a local transcript estimate after each tool batch until the next round reports. It is not the sum of rounds in the turn. The status bar can show 100% when usage meets or exceeds the window. Compaction does not block the session loop: the progress row stays on Compacting and the composer remains usable.

/compact (alias /summarize) runs immediately and does not wait for the threshold. When the retained tail already holds every turn, it still summarizes everything before the latest user turn. A session with nothing before that turn prints Nothing earlier to compact. It is refused while a turn is running. /compact model and /compact thinking show or set the optional summarizer and its gear. /compact summary toggles showCompactionSummary, and /compact auto (alias automatic) toggles showAutomaticCompactionSummary. /compact micro toggles microcompaction. Any of those commands accepts on or off, writes config.json, and does not summarize. Any other argument is rejected. compactionModel in config.json is enabled, provider, model, and optional thinkingEffort. An omitted object means off, and enabled: false keeps a stored provider, model, and gear unused. While off, the summary request uses the session client and omits reasoning. While on, the host opens a separate client and maps that model’s gear the same way as the approval model: no thinking omits reasoning, off disables it when the model allows that, and default or an unsupported gear uses the provider default without changing the saved gear. Changing the session model does not replace that client. A side question that must summarize first opens its own compaction client and releases it; the answer still uses the session model. The trigger, retained tail, and CTX percent stay on the session window. The summary prompt budget is the smaller of that window and the compaction model’s declared window. A summary that cannot fit takes the existing path that does not write one. /status adds a Compaction model row only while the switch is on. crystal, crystal space, and crystal run accept --compaction-model on|off, --compaction-provider, --compaction-model-id, and --compaction-thinking for one process. Those flags are not written to config.json. on needs a saved selection or a provider and model id on the same command. User and assistant text in the folded head are replaced by the summary; they are not kept beside it. The screen keeps the earlier lines. When showCompactionSummary is on (the default; omitted from config.json when on, false when off), a manual /compact prints the stored summary under those lines in a rounded panel titled Earlier context. Automatic compaction prints Compacted context only, unless showAutomaticCompactionSummary is on. That switch defaults off, is omitted from config.json until enabled, and uses the same panel. It does not change /compact itself. A compaction with no summary text does not print one. A side question that summarizes a private copy does not print it.

Sessions are written to ~/.crystal/sessions/<id>.json after each completed turn, after a successful /compact, and on an orderly exit when the transcript has a user message or a compaction summary. The file stores the compacted model transcript (live system prompt, one summary, recent tail, and reasoning items with their readable text and opaque provider state), the last usage snapshot, and cumulative provider usage. crystal --resume (-r) opens a terminal selector for this workspace. crystal --resume <id> loads that file and stays in the process workspace. crystal --resume <path> lists that directory, asks for trust before the selector, and enters the directory after a session is chosen. Escape leaves the process workspace unchanged. crystal --resume all lists every workspace, shows each path, and enters the chosen session’s workspace after trust. --workspace and --resume <path> must name the same directory when both are set. A missing or empty session exits without entering the TTY. /resume, /resume <path>, and /resume all use the same rules inside a running session. /resume <id> restores that transcript and stays in the current workspace. The word all is reserved. A value that is both an existing directory and a session id is rejected. After a workspace change, the live system prompt is refreshed from that directory’s Plan/Work text; the summary and tail are kept. The selector lists resumable sessions newest first by update time, supports typing to filter by id, preview, or workspace path, and leaves the current session untouched on Escape. Usage is restored so the status bar, /status, and the next compact decision have a baseline. Sessions saved before cumulative usage was introduced retain an unknown cumulative value rather than treating their last request as the whole session. /clear starts a new id.

/sessions lists resumable sessions for the current workspace in descending update order; /sessions all includes every workspace. The current id is marked and every row keeps the complete id for use with /resume <id> or /fork <id>. Empty and unreadable session files are omitted.

/fork first persists the current conversation, copies its transcript, compaction summary, todos, mode, counters, and usage baseline to a new id, and continues on that id. The source snapshot remains available under its original id and is not overwritten by the branch. /fork <id> branches a saved session instead. A branch uses the current workspace and a refreshed live system prompt. Forking stops a running turn before taking the snapshot; listing sessions does not.