Harness Notes

JSON

Compaction

5 records · Updated 2026-10-15

What each harness does when the conversation outgrows the context window: when it compacts, what it keeps, and how you can steer it.

When it happens

QuestionCodex CLIchecked at 0.162.1Claude Codechecked at 2.1.299Cursor Agentchecked at 2026.10.12-d47ca18OpenCodechecked at 2.0.28pichecked at 1.2.0
Automatic compaction, and when

Yes. Before each turn, after each model step that needs a follow-up, and when you switch to a model with a smaller window, Codex compares the active context (the last reported input + output token count) to an auto-compact limit of 90% of the model's context window (or model_auto_compact_token_limit if lower) and compacts when it is reached; it also force-compacts at the usable window, 95% of the context window. For the bundled 272,000-token models that means compaction at about 244,800 tokens, with a hard ceiling at 258,400.

model_post_turn_compact_threshold_percent (default 0, off) adds an optional extra check after a final answer.

Source

Yes. Without a configured window, Claude Code compacts as the conversation reaches the model's context limit; models running a native 1M window (Fable, Sonnet 5+, Haiku 5.5, Opus 4.7+) compact at about 967K tokens, and Sonnet 4.6 / Opus 4.6 without [1m] (or any model with CLAUDE_CODE_DISABLE_1M_CONTEXT=1) compact at the 200K boundary. Context is measured from the latest API response's input tokens (input plus cache reads and writes), and a reserve for output is held back, so raising CLAUDE_CODE_MAX_OUTPUT_TOKENS makes it compact sooner.

Since v2.1.290 it also compacts a terminal conversation of 200K+ tokens left idle about 54 minutes on the one-hour prompt cache, just before the cache expires (idleCompaction).

On a model ID it doesn't recognise (such as a gateway alias) it compacts at the window it assumes for that ID; correct it with CLAUDE_CODE_MAX_CONTEXT_TOKENS.

Subagents compact independently as their own context fills.

Source

Yes. When a chat's context window gets close to full, Cursor summarizes older parts of the conversation to make room, and this also happens partway through long tool-calling turns. Cursor does not publish the exact trigger percentage or token count. Its servers decide when to compact, and the preCompact hook reports the current context_usage_percent, context_tokens and context_window_size each time it happens.

The preCompact example payload (85%, 120000 of 128000 tokens) is only an illustration, not the threshold.

Source

Yes. Before each model step OpenCode estimates the prompt size and compacts when it reaches the window minus a buffer. The estimate is the provider-reported tokens from the last response plus about 4 characters per token for anything added since. The default buffer is 10% of the window or 16,000 tokens, whichever is larger (models under 32k keep just 10%). The window is the model's input limit if it has one, otherwise its context limit.

Models with an unknown window never auto-compact; only a provider rejection triggers it.

Source

Yes. Pi compacts automatically when contextTokens > contextWindow - reserveTokens, with reserveTokens defaulting to 16384 (so a 200K-token model compacts above roughly 183.6K tokens). Context is counted from the last valid assistant response's reported usage (totalTokens, or input + output + cache read + cache write) plus a chars/4 estimate for any messages added since. Pi checks before each new prompt, after a tool batch finishes and before the next assistant response in the same run, and again when the run ends.

Right after a compaction, Pi ignores the old (pre-compaction) usage figures and estimates the rebuilt context from scratch until the next response arrives.

Source
Change the trigger or turn it off

Partly

Set model_auto_compact_token_limit in config.toml to compact earlier; with the default model_auto_compact_token_limit_scope = "total" it is capped at 90% of the context window, while "body_after_prefix" counts only tokens added since the carried-over prefix. model_post_turn_compact_threshold_percent (0-100) also compacts after a final answer once that percentage of the usable window is used. There is no setting to turn automatic compaction off: the 95% usable-window guard always applies.

model_context_window can raise the window up to the model's maximum (872,000 tokens for most bundled models), which moves both thresholds.

Source

Set the auto-compact window (100K to 1M tokens, capped at the model's window) with /autocompact 500k (saved per model under modelSettings), "autoCompactWindow": 500000 in settings for every model, claude --autocompact <size> for one launch, or CLAUDE_CODE_AUTO_COMPACT_WINDOW=500000, which overrides all the others; /autocompact auto returns to the default. CLAUDE_AUTOCOMPACT_PCT_OVERRIDE (1-100) can only lower the trigger percentage. Turn automatic compaction off with the Auto-compact toggle in /config (autoCompactEnabled: false) or DISABLE_AUTO_COMPACT=1, and all compaction including /compact with DISABLE_COMPACT=1.

The environment variable only accepts a plain integer; 500k is read as 500 and clamped to 100K.

A subagent can compact earlier with autoCompactWindow in its frontmatter (v2.1.296+).

Turning auto-compact off also turns off idle compaction; set idleCompaction: false to disable only the idle pass.

Source

Not supported

No. There is no setting, flag or environment variable to change when automatic summarization triggers or to turn it off. The only lever is a bigger window: pick a larger-context model variant in /model or with --model 'model[context=1m]', or use /max-mode on legacy request-based plans.

Source

Set compaction.buffer to the number of tokens to keep free below the limit; a larger buffer compacts earlier. Set "compaction": { "auto": false } to turn automatic compaction off. Manual compaction still works when it is off.

V2 has no OPENCODE_DISABLE_AUTOCOMPACT env var. V1's reserved becomes buffer.

Source

Set compaction.reserveTokens (default 16384) in ~/.pi/agent/settings.json or <project>/.pi/settings.json; a larger reserve makes compaction happen earlier. Use compaction.modelOverrides keyed by exact provider/modelId to set a different reserveTokens or keepRecentTokens for one model. Turn auto-compaction off with "compaction": { "enabled": false } or the Auto-compact toggle in /settings. /compact still works when it is off.

compaction.enabled applies to all models and cannot be overridden per model.

Turning off auto-compaction also turns off automatic overflow recovery.

reserveTokens also limits how long the summary can be: up to 80% of it, capped by the model's maximum output.

Source
Compact by hand

Partly

Type /compact in the TUI (it can run even while a task is in progress). It takes no arguments, so you cannot tell a single /compact what to keep; persistent instructions only go through compact_prompt, which applies to local compaction only.

Source

Run /compact, optionally with focus instructions such as /compact focus on the auth bug fix. To compact only part of the conversation, open /rewind, pick a message and choose Summarize from here or Summarize up to here, optionally typing guidance for the summary.

Source

Run /summarize in an interactive session to summarize the conversation and free up context. /compress and /compact are aliases. The command takes no instructions, so you can't tell it what to keep, and it says No active session. if the chat has no turns yet.

Source

Partly

Type /compact or press the leader key then c in the TUI. You can also call opencode api post /api/session/<id>/compact --data '{}', or ctx.session.compact() from a plugin. It runs at the next safe point, even for short histories. The command takes no instructions about what to keep; use compaction.keep.tokens or a plugin compaction hook instead.

The V1 alias /summarize is not registered in the V2 TUI.

Source

Run /compact, or /compact <instructions> to tell the summary what to focus on. Pi adds your text to the summary prompt as Additional focus: <instructions>. In RPC mode, send {"type":"compact","customInstructions":"..."}. Extensions can call ctx.compact({ customInstructions }).

/compact fails with "Nothing to compact (session too small)" or "Already compacted" when there is nothing to summarise.

Source
See how full the context is

The TUI footer shows NN% context left, and /status shows NN% left (used / window). You can add a context item to the footer with /statusline. The percentage treats the first 12,000 tokens as baseline and measures against the full context window, so it reaches 0% later than auto-compaction fires (90%).

Source

Run /context for a live breakdown of what fills the window (system prompt, tools, memory files, messages), including a warning when you are past the limit. For a constant readout, configure a status line that shows context_window.used_percentage; /usage also warns as you approach the auto-compact window.

The status line percentage is measured against the model's full window, so it no longer shows when compaction will run once you set a smaller auto-compact window.

Source

The prompt bar footer shows how full the context window is as a percentage (set AGENT_CLI_HIDE_PROMPT_BAR=true to hide the bar). Run /context for a breakdown by category: system prompt, tools, rules, skills, MCP, subagents, summarized conversation and conversation. The /context command isn't in the slash-command reference table, but it's covered in the CLI changelog and present in CLI 2026.10.12.

Source

The TUI prompt footer and the sidebar's Context section show the last response's tokens and the percentage of the model's context window, for example 45,000 (23%). Auto-compaction fires around 90% of the window (less on small models), so plan for compaction before 100%.

Source

The interactive footer shows context use as <percent>%/<window>, followed by (auto) when auto-compaction is on. The figure turns to a warning colour above 70% and an error colour above 90%, and shows ? right after a compaction until the next response reports usage. /session shows session statistics; RPC get_session_stats and the extension call ctx.getContextUsage() return the same contextUsage estimate that compaction uses.

Source

What it does

QuestionCodex CLIchecked at 0.162.1Claude Codechecked at 2.1.299Cursor Agentchecked at 2026.10.12-d47ca18OpenCodechecked at 2.0.28pichecked at 1.2.0
What replaces the conversation

With OpenAI (and Azure Responses) providers, Codex uses remote compaction: it sends the history plus a compaction trigger through the Responses API, and the server-side model returns one encrypted compaction item. With other providers it runs locally: the current model gets the summarization prompt (or compact_prompt) and writes a handoff summary, which is stored as a user message beginning with a fixed "Another language model started to solve this problem..." prefix. Either way the history is replaced by retained user messages, freshly rebuilt initial context, and the summary or compaction item. After that Codex warns that long threads and repeated compactions reduce accuracy.

Custom providers can choose with model_providers.<id>.capabilities.remote_compaction = "v2" or "unsupported".

With the token_budget feature enabled, compaction resets the context window without summarizing.

Source

Claude Code sends a separate request to the session's model with the same system prompt, tools and history plus a summarisation instruction, and replaces the message history with the structured summary it returns (you see "Conversation compacted"). The request inherits the session's extended-thinking setting and uses your fallback model chain, but never falls back to a model with a smaller context window. Startup context such as CLAUDE.md and memory is then reloaded from disk around the summary.

Source

Partly

Cursor's backend writes the summary, not your local CLI. The CLI sends a summarize action and shows Summarizing while it runs. Older messages are replaced by a summary that counts as 'Summarized conversation' in the context breakdown, and your latest message is kept word for word. Cursor doesn't document which model writes the summary, and for teams that don't allow data storage, summarization fails rather than storing data.

Source

OpenCode summarizes everything except the most recent conversation into a structured Markdown checkpoint (Objective, Requirements, Decisions, Work State, Next Move, Relevant Files, Important Context). It uses the session's model and asks once more if the reply misses the template. Later requests begin with one <conversation-checkpoint> message holding the summary plus the recent conversation as text, and later compactions update that checkpoint. With settings.compaction: { "type": "native" } on supported OpenAI Responses models, the provider returns an encrypted checkpoint instead.

The docs say there is no separate compaction model, but the source does honor a model set on the hidden compaction agent.

Source

Pi asks the current session model to write a structured checkpoint summary (Goal, Constraints & Preferences, Progress, Key Decisions, Next Steps, Critical Context, plus lists of files read and modified). It sends the older messages as serialized text with thinking blocks removed and each tool result cut to 2000 characters. Pi then appends a compaction entry, and later requests get the system prompt, then the summary, then the recent messages kept verbatim. On repeat compactions, the previous summary is updated rather than rewritten from scratch.

When a single long user turn exceeds the kept budget, Pi writes two summaries (earlier history and the start of that turn) and merges them.

An extension can supply the summary instead, using any model it likes.

Source
What survives

Partly

Codex rebuilds the initial context after compaction: base and developer instructions, AGENTS.md, environment and permissions context, and the skills and plugins catalog. Local compaction keeps your most recent user messages, up to about 20,000 tokens. Remote compaction keeps your user messages and short non-final sub-agent messages (each up to 10,000 tokens), up to about 64,000 tokens total, newest first. Assistant replies, tool calls and tool outputs are dropped and survive only through the summary.

Images in retained messages may be dropped (only their text is kept) when the token budget is exceeded.

Source

The system prompt and output style still apply; project-root CLAUDE.md, unscoped rules, auto memory and the plan-mode plan are re-injected from disk, and a fresh git status is read. Claude Code re-reads up to five recently modified files it read or edited (files over 5,000 tokens come back as a path only), re-injects invoked skill bodies capped at 5,000 tokens each and 25,000 total, keeps the task list, and reminds Claude of running background commands and subagents. Path-scoped rules and nested CLAUDE.md files are summarised away until a matching file is touched again, and the skill listing is not re-sent.

Recent turns are folded into the summary rather than kept verbatim, except in overflow recovery, which can keep the newest exchanges or your newest prompt word for word.

Run /reload-skills to put the full skill list back after compaction.

Source

Partly

The system prompt, tool definitions, rules, skills, MCP instructions and subagent docs are counted separately from the conversation, so summarization doesn't touch them. Since September 2026 your most recent message is kept word for word after summarization. In CLI 2026.10.12 the session also stores todos, plans and invoked skill blocks outside the summarized turns. Cursor doesn't document exactly how many recent turns or files are kept.

Source

About compaction.keep.tokens of the newest conversation is kept beside the summary (default 15,000), starting at a user-message boundary. In that kept part, tool output over 1,250 characters is shortened and attachments become one-line descriptions. Instruction files such as AGENTS.md are excluded from the summary and resent in their current version as the new baseline. Activated skill text is kept only if it falls inside the recent window.

Source

The system prompt is kept in full: context files such as AGENTS.md, tool declarations and loaded skill descriptions. It is stored as a checkpoint in the compaction entry and replayed ahead of the summary. Roughly the last compaction.keepRecentTokens (default 20000) of messages stay verbatim; cuts never separate a tool result from its call. Everything older survives only as the summary, which carries forward cumulative <read-files> and <modified-files> lists. There is no separate todo or plan store to preserve.

Skill bodies the model loaded during the conversation are ordinary messages, so older ones are summarised like anything else.

Extension state stored in session entries follows the session tree and survives compaction.

Source
Trimming without summarising

Partly

Yes, separately from compaction: each tool or function output is truncated when it is stored in history, to 10,000 tokens by default for bundled models. You can change this with tool_output_token_limit (or per MCP tool with mcp_servers.<id>.tools.<tool>.output_token_limit). Before remote compaction, Codex also shortens old function-call outputs if needed so the request fits the window. There is no separate setting to prune old turns.

Source

Yes. As the context fills, Claude Code clears older tool outputs first and only summarises if that isn't enough, and when a request would exceed the image or PDF limits it drops a batch of the oldest images and PDFs. There is no setting to tune or disable this clearing.

Source

Not documented

Cursor doesn't describe any separate step that trims old tool outputs without summarizing, and there is no setting to control one. The only documented ways to free context are automatic summarization and /summarize.

Source

Not supported

No. V2 has no separate tool-output pruning. compaction.prune and compaction.tail_turns are ignored with a warning, and recent context is kept by token budget only. Tool output is shortened only inside the compaction checkpoint.

Source

Partly

Pi does not prune or clear old tool outputs on its own. The only automatic trimming is that tool results are cut to 2000 characters inside the text sent for summarisation. Extensions can trim without summarising by appending context_edit entries, which omit or replace earlier messages in future requests while keeping them on disk, or by filtering messages in a context event handler.

During overflow recovery, Pi itself appends context_edit entries to drop the failed attempt from future context.

Source
The full history afterwards

Yes. The session rollout under ~/.codex/sessions/ is append-only: compaction adds a compacted record with the replacement history (and, for local compaction, the summary text in message) after the original turns, which remain. Remote compaction summaries are encrypted, so you cannot read them; codex resume restarts from the latest compaction point.

Source

Yes. The session JSONL in ~/.claude/projects/<project>/<session-id>.jsonl keeps the earlier messages, with a compact_boundary entry recording the trigger and pre-compaction token count, and fullscreen mode keeps every earlier message in scrollback. To read the summary itself, use a PostCompact hook (compact_summary) or the Agent SDK's compact_boundary message stream.

With CLAUDE_CODE_TRANSCRIPT_LOCAL_GC=1, long -p and Agent SDK sessions drop pre-compaction history from transcripts over 5 MB.

Transcripts are deleted after cleanupPeriodDays (30 days by default).

Source

Yes. Each chat's ~/.cursor/chats/<hash>/<chatId>/store.db keeps summary archives that hold the messages that were summarized, and a JSONL copy is written to ~/.cursor/projects/<slug>/agent-transcripts/<chatId>/. After summarizing, the CLI shows the summary in a cyan Summary box in the chat. If summarization fails or you press Stop during it, the earlier conversation is kept.

The store.db and JSONL formats are internal and undocumented.

Source

Yes. Earlier messages stay stored even when they're no longer sent to the model. The checkpoint is recorded as a compaction message with the summary text and the kept recent text, and the TUI shows the compaction as it starts, streams, and ends.

Source

Yes. Sessions are append-only JSONL files under ~/.pi/agent/sessions/--<path>--/, and compaction only appends a compaction entry. Every original message stays on disk and in /tree, /export and /share. The summary is stored in that entry's summary field and appears in the transcript as a collapsible block showing the token count before compaction; click it to expand.

Source

Shaping it

QuestionCodex CLIchecked at 0.162.1Claude Codechecked at 2.1.299Cursor Agentchecked at 2026.10.12-d47ca18OpenCodechecked at 2.0.28pichecked at 1.2.0
Customise the summary or hook in

Set compact_prompt (inline) or experimental_compact_prompt_file (a file path) in config.toml to replace the summarization prompt; the inline value wins, and both apply only to local compaction. PreCompact and PostCompact hooks run around both manual and auto compaction (matcher on trigger: manual or auto). A hook returning continue: false stops the turn, but it cannot change the summary.

Source

Pass instructions to /compact, or add a # Compact instructions section to the project CLAUDE.md to steer every summary. Hooks: PreCompact (matcher manual or auto) receives the /compact instructions and can block compaction with exit code 2 or {"decision":"block"}; PostCompact receives the compact_summary; and a SessionStart hook with matcher compact adds its output to the compacted context. The built-in summary prompt itself cannot be replaced.

Blocking an automatic compaction that was triggered to recover from an overflow makes the request fail with the original error.

Source

Partly

You can't change the summary prompt. A preCompact hook in hooks.json runs before every compaction and receives trigger (auto or manual), usage numbers and messages_to_compact. It can only observe: it can return a user_message to show you, but it can't block or change the compaction. A Claude Code PreCompact hook is mapped to preCompact. There is no post-compaction hook.

Source

Plugins can register ctx.session.hook("compaction", ...) to edit the messages, system text, or options of the summary request. Setting event.result = { summary } supplies your own summary and skips the model call. Plugins can follow session.compaction.started, delta, ended, and failed events. The built-in summary prompt itself can't be changed in config, and there are no PreCompact or PostCompact shell hooks.

OpenCode appends its own summary prompt after the hooks run, so a hook cannot replace it except by supplying result.

Source

Yes, through extensions. session_before_compact fires before manual, threshold and overflow compactions and can cancel or return your own summary, firstKeptEntryId and details. session_compact fires after success and session_compact_failed after a failure or abort. session_before_tree does the same for branch summaries. The built-in summary prompt cannot be changed by a setting; use /compact <instructions> or an extension.

The event payload includes reason (manual, threshold or overflow) and willRetry. JSON and RPC streams emit compaction_start and compaction_end events.

Source
When a request overflows anyway

Partly

If a normal request still overflows, the turn ends with "Codex ran out of room in the model's context window. Start a new thread or clear earlier history before retrying." Codex then marks the context as full, so the next turn compacts before sending, but it does not retry the failed request. If the compaction request itself overflows during local compaction, Codex drops the oldest history items one at a time and retries.

Codex compacts and retries in the same turn only for Guardian auto-review sessions whose review budget is exhausted.

Source

If the API rejects a request as too long (Prompt is too long), Claude Code compacts the oldest exchanges and retries, compacting again with less recent history if needed, and as a last resort keeps only your newest prompt verbatim. If that fails, or auto-compact is off, you see Context limit reached · /compact or /clear to continue. If the context refills to the limit right after compacting several times, it stops with an Autocompact is thrashing error.

A single-exchange conversation can't be compacted; the error explains whether your content or the system prompt, tools and attachments fill the request.

CLAUDE_CODE_DISABLE_UNKNOWN_MODEL_WINDOW_ENFORCEMENT=1 makes unrecognised model IDs rely only on this overflow recovery.

Source

Since v2026.10.08, a session that hits the context limit summarizes and then continues the turn instead of getting stuck. An earlier fix (v2026.09.15) stopped long Claude and GPT turns from re-compacting on every step without freeing any space.

Source

If the provider rejects a request as too long, OpenCode compacts, aiming at 70% of the rejected size, and retries once. A second rejection is returned as an error. If the summary request itself is too long, OpenCode sends a flattened text version and shrinks it to 70%, 50%, then 35%, dropping the oldest exchanges, before giving up. With compaction.auto: false it does not compact on overflow and returns the error.

The docs' Settings table says auto controls overflow recovery as well as preflight compaction, and the source agrees: auto=false skips both.

Source

If the provider returns a context-overflow error, or a response stops early with stopReason: "length", Pi drops the failed attempt from context, compacts and retries once. A second failure shows "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model." If a successful response pushes past the window, Pi compacts without retrying.

Recovery is skipped when compaction.enabled is false, or when the error came from a different model than the one now selected.

Custom providers with unusual overflow messages must map them to context_length_exceeded for recovery to trigger.

Source

Notes and sources

Codex CLI
Claude Code
Cursor Agent
OpenCode
pi