Skip to main content

Compaction & Branch Summarization

LLMs have finite context windows. Atomic reduces transcript context with verbatim line compaction while preserving an exact count of recent context-visible messages as ordinary messages. Branch summarization is a separate, intentionally lossy feature used only when navigating away from a branch. Compaction runs entirely locally with the active session model; no external compaction service is involved. The model only selects which lines to delete — Atomic reconstructs the retained text mechanically, so surviving lines are never rewritten.

Overview

There is one context-compaction door: compact.

Verbatim Line Compaction

What “verbatim” means

Atomic serializes the compactable part of the conversation into role-tagged lines:
The planner sees the same text numbered as N→content and returns only one-based, inclusive line ranges as bare records:
Each line is start,end — unsigned decimal integers, one comma, no brackets or prose. Atomic safety-normalizes endpoints by swapping reversed pairs, clamping to the transcript, sorting, merging overlap/adjacency, and splitting around explicit protected spans. It then reconstructs from the original input lines. The model never writes, summarizes, reorders, or normalizes retained text. Every retained non-marker line is byte-identical to an input line and remains in input order.

Markers and repeated compaction

Each deleted span is replaced on its own line with exactly:
The spelling is always plural, including (filtered 1 lines). When a later compaction swallows an earlier marker, Atomic adds the earlier marker’s count to the new marker. Adjacent old markers are folded too, so counts remain cumulative across repeated compactions. On repeated compaction, the planner receives the prior durable verbatim summary plus every currently active ordinary message except the exact protected tail.

Protected structure

Role-header lines such as [User]: and [Assistant]: are ordinary ranked lines and may be deleted. Explicit protected spans, including blank lines, are never deleted. The configured number of newest context-visible messages remains outside the classifier request entirely; all preceding active transcript content is included. Images in the compactable region become the literal line [image]; images in the protected recent tail remain normal image content. Tool-result text remains capped at 16,000 characters before becoming durable compaction text, with an explicit truncation marker for the remainder.

Parameters

The effective parameters appear in extension events and successful results: preserve_recent counts context-visible messages without aligning the boundary to a user turn. An assistant message or tool result may therefore begin the kept tail. A value of 0 protects no messages and makes the entire active transcript compactable. If query is absent, Atomic derives it from the last visible user message. Configure defaults in ~/.atomic/agent/settings.json or .atomic/settings.json:
reserveTokens controls the automatic threshold that decides when compaction runs; it is not converted into a classifier line ratio. Manual calls can pass parameter overrides through the SDK.

When compaction runs

  • Manual: /compact, ctx.compact(), session.compact(), or RPC { "type": "compact" }.
  • Threshold: automatic compaction starts when estimated context usage exceeds the effective input budget minus reserveTokens. Atomic checks both completed responses and the prospective next-turn context after tool results have been appended. A post-tool crossing is compacted before the active Pi tool loop sends its follow-up provider request.
  • Overflow: an actual provider context overflow compacts and then retries the interrupted turn.
Exactly the configured recent-message tail is outside the compactable region; Atomic does not force the final logical turn to remain outside it. Pressing Escape while compaction is active cancels it like other session operations. In isolated interactive mode, cancellation and host UI response frames use an independent RPC control lane, so they can reach the engine while the ordinary compact request is still pending instead of waiting behind it. Atomic writes a backup snapshot immediately before appending a compaction boundary. The post-tool check stays inside the active Pi loop: it runs at most one ordinary verbatim compaction attempt for that completed tool turn, returns the rebuilt context to the loop, and never calls or schedules agent.continue(). Normal context reconstruction preserves provider tool-call/result protocol validity. Below-threshold tool turns follow the unchanged request path. Because the same active run resumes without emitting another agent_start, the interactive TUI replaces the compaction loader with its working spinner as soon as successful mid-turn compaction ends; streaming feedback therefore resumes immediately without waiting for another user interaction.

One-pass planning and failure behavior

Atomic asks the active session model, at the active reasoning level and through the normal session stream/provider wrapper, to rank every eligible line in one global pass and apply one threshold. The entire compactable region is sent in exactly one classifier request; it is never split into chunks. Manual, threshold, and overflow compaction all calculate the line target directly from the prepared compression_ratio. Explicit protected lines form a hard keep floor. The request uses the same provider path and failure handling as pi’s summary compaction. Provider/API errors, overflow, abort, malformed output, or empty/unusable safe ranges fail after that one request. These failures write no compaction entry and schedule no continuation. During the post-tool preflight, failure or cancellation also stops the active loop before its follow-up provider request, is surfaced through the normal compaction lifecycle, and is not admitted to ordinary provider retry or model fallback. There is no semantic retry, critical rung, deterministic fallback, or deterministic target correction. A syntactically valid usable result is accepted once after safety-only normalization, even when it deletes fewer lines or tokens than requested. Atomic never adds or restores model-selected deletions to force a target. During overflow recovery, the existing one-shot compact-and-retry continuation may therefore surface unresolved overflow naturally. During a post-tool preflight, Atomic likewise does not add a second compaction strategy or attempt; if the rebuilt context is still known to exceed the provider’s hard input limit, it refuses to send the follow-up request and reports the limit failure clearly.

Length-truncated response recovery

When the planner model’s output is truncated by max_tokens (indicated by stopReason: "length"), Atomic silently recovers complete newline-terminated deletion records from the truncated response. A deterministic line parser validates each completed line (those followed by a newline) against the strict start,end grammar. The final fragment after the last newline is always discarded — even if it looks syntactically complete — because EOF may have cut a multi-digit integer (e.g. 300,30 could have intended 300,305). If any completed line has invalid syntax or zero usable records survive validation, recovery fails and the normal RangePlanError path applies. Example of truncated output:
Recovery yields 120,180 and 6,40; discards 300, without guessing. The planner prompt instructs the model to emit ranges in descending deletion confidence (lowest continuation value first) so the most important deletions appear earliest and survive truncation. Successful partial recovery is an ordinary successful compaction: no warning, banner, toast, or special status copy appears. The UI shows the normal spinner then ✻ Context compacted. For operational observability, a private recovery diagnostic sidecar is written beside persisted sessions with 0600 permissions. It records the full raw response, stop reason, usage, request maxTokens, model metadata, recovered range count, and recovery category. The sidecar path is never surfaced in the success UI, error messages, or user-visible status. In-memory sessions and sidecar write failures do not affect the successful recovery.

Planner failure diagnostics

For a persisted session, a failed planner call writes a JSON sidecar beside the session JSONL and includes its path in the RangePlanError, for example:
The private sidecar uses 0600 permissions where supported and records the full planner response text, stop reason, provider error, usage, request maxTokens, timestamp, failure category, and non-secret model metadata. It does not record API keys, request headers, the planner prompt, or the numbered transcript request. The raw response itself may contain sensitive text if the model echoed input, so treat the sidecar with the same care as its adjacent session file. Diagnostic categories distinguish malformed output, valid output with no usable ranges, provider errors, and stream failures. In-memory sessions do not create sidecars. If the diagnostic write fails, Atomic preserves the original error and classification rather than replacing the planner failure. Interactive main chat and attached workflow stage chat treat compaction_end as the authority for cancellation and failure UI. A failed or cancelled /compact stops its spinner, shows the event-provided status or diagnostic path without a duplicate stack trace, writes no boundary, and leaves the session usable for another /compact attempt or a normal follow-up turn. Context thresholds and persisted token-reduction statistics use API-aware normalized usage. OpenAI Responses, Codex Responses, and OpenAI Completions sum uncached input plus cache-read/cache-write partitions. Anthropic Messages alone applies the mirrored-cache guard needed by compatible endpoints that duplicate the same prompt tokens across input and cache fields.

Persistence and resume

A successful run appends the existing pi-style type:"compaction" entry shape:
A compaction entry is active only when details.strategy === "verbatim-lines". On rebuild, Atomic emits a visible custom-role boundary message containing the durable summary, followed by the original messages beginning at firstKeptEntryId. When no pre-boundary context-visible message is retained—such as with preserve_recent: 0firstKeptEntryId is null. Messages appended after the boundary are always replayed. The boundary is converted to a user-role provider message and shown in the TUI as a collapsible compaction card. Resume does not rerun planning or re-derive deletions: the exact compacted string and nullable tail boundary are already in JSONL. Existing records with a string firstKeptEntryId keep their original resume behavior. Legacy context_compaction logical-deletion records and old compaction summary records without the discriminator are inert archival data. Their historical omissions are not reapplied when an old session resumes.

Extension hooks

session_before_compact

Extensions may cancel or provide a complete replacement for the prepared region:
preparation is a deep-frozen clone. An override changes only the compacted region text; Atomic retains the prepared boundary and persists the supplied text verbatim. Empty/whitespace text is rejected. The override path does not require provider credentials.

session_compact

After persistence, Atomic emits an observe-only event:
Observer errors are isolated and cannot roll back the already-persisted boundary.

Branch Summarization

When It Triggers

When you use /tree to navigate to a different branch, Atomic offers to summarize the work you’re leaving. This injects context from the left branch into the new branch. Branch summarization is a separate mechanism from context compaction. It generates a summary of the abandoned branch path and injects it into the new branch position. This is appropriate here because the alternative (losing branch context entirely on navigation) is worse than a lossy summary.

How It Works

  1. Find common ancestor: Deepest node shared by old and new positions
  2. Collect entries: Walk from old leaf back to common ancestor
  3. Prepare with budget: Include messages up to token budget (newest first)
  4. Generate summary: Call LLM with structured format
  5. Append entry: Save BranchSummaryEntry at navigation point

Cumulative File Tracking

Branch summarization tracks files cumulatively. When generating a summary, Atomic extracts file operations from:
  • Tool calls in the messages being summarized
  • Previous branch summary details (if any)
This means file tracking accumulates across nested branch summaries, preserving the full history of read and modified files.

BranchSummaryEntry Structure

Defined in session-manager.ts:
Extensions can store custom data in details. See collectEntriesForBranchSummary(), prepareBranchEntries(), and generateBranchSummary() for the implementation.

Branch Summary Format

Branch summarization uses a structured format:

Message Serialization for Branch Summaries

Before branch summarization, messages are serialized to text via serializeConversation():
This prevents the model from treating it as a conversation to continue. Tool results are truncated to 2000 characters during serialization. Content beyond that limit is replaced with a marker indicating how many characters were truncated.

Extension Hooks for Branch Summarization

session_before_tree

Fired before /tree navigation. Always fires regardless of whether user chose to summarize. Can cancel navigation or provide custom summary.
See SessionBeforeTreeEvent and TreePreparation in the types file.

Settings

Configure compaction in ~/.atomic/agent/settings.json or <project-dir>/.atomic/settings.json (legacy .pi paths are also supported):
Disable auto-compaction with "enabled": false. You can still compact manually with /compact.

Historical formats

Two old formats remain parseable but inactive:
  • type:"context_compaction" records store logical entry/content-block deletion targets from older versions. Those records are inert, so content they once hid can re-enter context when an old session resumes.
  • type:"compaction" without details.strategy: "verbatim-lines" stored generated summary prose. Those records also remain inert.
Both are distinguished from active boundaries by the discriminated details on the shared CompactionEntry shape; the session format version is the same for all of them.