Compaction & Branch Summarization
September 20, 2026 · View on GitHub
LLMs have finite context windows. Atomic reduces older transcript context with verbatim line compaction while preserving a configured count of recent context-visible messages. Branch summarization is a separate, lossy feature used when navigating away from a branch.
Compaction runs locally without an external compaction service. It normally asks the active session model to rank lines. If that model cannot rank them because of a rate limit, quota exhaustion, provider error, context overflow, or empty plan, Atomic borrows the next model from your configured fallbackModels for that planner request.
A configured fallback model may therefore receive the compaction transcript, using that provider's own credentials. Borrowing never changes the session's model or thinking level. The model only selects lines to delete. Atomic reconstructs retained text from the originals, so surviving lines are never rewritten.
On this page and its reference
This page covers the concepts and normal use of compaction and branch summarization. Parameters, persistence, extension hooks, formats, settings, and historical formats live in the Compaction reference.
Overview
| Mechanism | Trigger | Model output | Durable result |
|---|---|---|---|
| Verbatim compaction | /compact, RPC compact, or automatic threshold/overflow recovery | Bare start,end deletion records (one per line) | A CompactionEntry whose summary is mechanically reconstructed transcript text |
| Planner fallback borrowing | Any terminal planner outcome on the current planner model | Same deletion records, from a configured fallbackModels entry | The same "planned" boundary, with details.plannerModel naming the borrowed model |
| Fresh context window | Load-bearing compaction after every configured model failed | (none — no model call) | A CompactionEntry with details.rung: "fresh" |
| Branch summarization | Optional /tree navigation | Generated summary prose | A BranchSummaryEntry |
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:
[User]: Fix the failing parser test
[Assistant thinking]: I will inspect the parser.
[Assistant tool calls]: read(path="src/parser.ts")
[Tool result]: export function parse(...) {
...
[Assistant]: The off-by-one error is fixed.
The planner sees the same text numbered as N→content and returns only one-based, inclusive line ranges as bare records:
2,5
The model selects lines to delete; it does not rewrite retained text. Retained non-marker lines stay byte-identical and in their original order.
Markers and repeated compaction
Each deleted span is replaced on its own line with exactly:
(filtered N lines)
Counts remain cumulative across repeated compactions. The spelling is always plural, including (filtered 1 lines).
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.
keepContext tags
Wrap any section you never want compressed in <keepContext> / </keepContext>. Tagged content survives compression verbatim regardless of the compression ratio:
<keepContext>
You are researching only. Do not implement code changes.
</keepContext>
Protection includes the tags and survives repeated compaction, even if the planner ignores its instructions.
- Put each tag on its own line. Tags mentioned inside prose do not protect content.
- A span stays within one user or assistant message. An unclosed span protects through that message's end; a closing tag without an opener is ignored.
- Tags in tool results have no effect. Restate important file or fetched content in your own message.
- Protected content counts toward the keep target. Protect only essential constraints, since protecting more leaves less room for surrounding context.
Results report protected ranges as keptRanges.
Parameters
Moved to Compaction reference.
Per-model budgets
Moved to Compaction reference.
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. When a provider reports all-zero usage, Atomic estimates the visible message size instead of skipping the check. 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.
- Truncated response: a
lengthstop before the original requested output cap gets one compact-and-retry attempt, independent of reported context-window metadata. If no compactable region exists, Atomic makes at most one direct continuation under that same recovery budget; a later actual context overflow remains eligible for load-bearing recovery. A response that reached the cap keeps Atomic's bounded direct-continuation behavior.
The recent tail counts messages, not whole turns. Queued input resumes when the active run becomes idle after automatic compaction. Escape cancels active compaction; you do not need to press it to release queued input. Atomic saves a backup before writing the compaction boundary.
Automatic continuations belong to the original prompt, including repeated output-cap continuations. The prompt and agent_settled lifecycle finish only after the entire chain drains, so status integrations such as Herdr stay working through quiet response waits and continuation gaps.
Concurrent manual SDK requests share one run and result; abortCompaction() cancels it for all waiters. A manual request during automatic compaction cancels unfinished automatic work and its pending continuation, then runs after the active work settles. If the automatic boundary already committed, the manual run follows it. In the TUI, /compact can take over automatic compaction but refuses a second manual compaction or branch summary. Ordinary text remains queued until non-mid-turn compaction finishes, fails, or is cancelled.
SDK prepareNextTurn and prepareNextTurnWithContext callbacks receive rebuilt context after post-tool compaction. A shouldStopAfterTurn result of true leaves queued input pending until an explicit prompt or continuation. Mid-turn compaction resumes streaming without another user action.
Planning rungs and failure behavior
Atomic uses the session's reasoning level unless a fallback entry specifies its own level. The provider controls the planner's output limit.
settings.retry controls retries within one model. If planning fails, Atomic tries configured settings.fallbackModels in order, using each model's own credentials. Unavailable credentials do not prevent trying later models. Borrowing does not change the chat model, thinking level, or model-selection events.
When every configured model is exhausted, what happens depends on how much the caller can afford to lose:
| Call site | Urgency | Can borrow a model | Can start a fresh context window |
|---|---|---|---|
/compact, ctx.compact(), session.compact(), RPC compact | recoverable | yes | no |
| Threshold auto-compaction | recoverable | yes | no |
| Overflow recovery | load-bearing | yes | yes |
| Post-tool preflight | load-bearing | yes | yes |
Recoverable failure writes no boundary, schedules no continuation, and reports the cause through compaction_end. Manual calls cannot request destructive recovery. Overflow recovery and post-tool preflight can fall back to the fresh context window below.
A successful compaction may delete less than requested. The retry can still report a context overflow.
The fresh context window rung
If all configured planners fail during overflow recovery or post-tool preflight, Atomic can discard older compactable conversation and its prior summary. Explicit protected spans and the recent tail remain, unless the tail alone exceeds the provider's hard input limit. A region too small to plan is cleared only when known not to fit; a post-tool threshold crossing that still fits leaves it unchanged.
The chat shows ✻ Context cleared (compaction degraded) rather than ✻ Context compacted, and results record details.rung: "fresh". Check what context remains before continuing important work.
Clearing context does not fix provider rate limits or guarantee the next turn succeeds. Atomic refuses a follow-up request still known to exceed the hard input limit. A committed boundary remains visible even if that request fails; compaction_end can contain both result and errorMessage.
Length-truncated response recovery
Atomic may recover usable deletion records when the provider truncates a planner response. Successful recovery appears as ordinary ✻ Context compacted; unusable output advances to the next configured model.
Planner failure diagnostics
For a persisted session, each failed planner attempt writes its own JSON sidecar beside the session JSONL and carries the path on the typed outcome. When a recoverable compaction exhausts every configured model, the resulting RangePlanError includes that path, for example:
Compaction range planning returned malformed output (diagnostic: /path/session-compaction-diagnostic-1785222000000-019fa7….json)
Treat diagnostic sidecars like session files: a raw model response may echo sensitive input. They use 0600 permissions where supported and omit API keys, request headers, and the planner request. In-memory sessions do not create them.
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.
The displayed token count and estimated reduction can differ. See the persisted statistics reference when interpreting results.
Persistence and resume
Moved to Compaction reference.
Extension hooks
Moved to Compaction reference.
session_before_compact
Moved to Compaction reference.
session_compact
Moved to Compaction reference.
session_compact_failed
Moved to Compaction reference.
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
Atomic summarizes the branch you leave, prioritizing newer messages within its token budget, and saves the summary at the navigation point. It rejects incomplete summaries rather than saving partial prose.
Tree before navigation:
┌─ B ─ C ─ D (old leaf, being abandoned)
A ───┤
└─ E ─ F (target)
Common ancestor: A
Entries to summarize: B, C, D
After navigation with summary:
┌─ B ─ C ─ D ─ [summary of B,C,D]
A ───┤
└─ E ─ F (new leaf)
Cumulative File Tracking
Branch summaries retain the cumulative history of read and modified files, including files recorded by earlier branch summaries.
BranchSummaryEntry Structure
Defined in session-manager.ts:
interface BranchSummaryEntry<T = unknown> {
type: "branch_summary";
id: string;
parentId: string | null;
timestamp: string; // ISO timestamp
summary: string;
fromId: string; // Entry we navigated from
fromHook?: boolean; // true if provided by extension (legacy field name)
details?: T; // implementation-specific data
}
// Default branch summarization uses this for details (from branch-summarization.ts):
interface BranchSummaryDetails {
readFiles: string[];
modifiedFiles: string[];
}
Extensions can store custom data in details.
Branch Summary Format
Moved to Compaction reference.
Message Serialization for Branch Summaries
Moved to Compaction reference.
Extension Hooks for Branch Summarization
Moved to Compaction reference.
session_before_tree
Moved to Compaction reference.
Branch Summaries
When /tree switches away from one branch to another, Atomic can summarize the abandoned branch and attach that summary at the new position. This preserves important context from the path you left without replaying the whole branch.
When prompted, choose one of:
- no summary
- summarize with the default prompt
- summarize with custom focus instructions
Branch summaries are separate from /compact: branch navigation can generate summary prose (optionally with focus instructions), while Verbatim Compaction lets a model select numbered line ranges and reconstructs retained text mechanically.
Use the Compaction reference for extension hooks and saved formats.
Summary request isolation
Summary and planner requests do not execute tools or write into the main chat's prompt cache. They retain normal authentication, cancellation, and retry behavior.
A model in settings.fallbackModels may receive the compaction transcript. It uses its own provider credentials. Remove an entry if you do not want that provider to receive transcript content.
Settings
Moved to Compaction reference.
Historical formats
Moved to Compaction reference.