Ninety minutes into a debugging session, your agent forgets the file it renamed an hour ago. The one fact the whole task hinges on. It didn’t get distracted — its context got garbage-collected.
What is context compression?
A long agent session piles up tokens: file reads, tool outputs, stack traces, whole failed attempts. Eventually it closes in on the model’s context window, and something has to give — old content gets summarized or dropped so the session can keep going. That’s context compression.
The concept is universal. The interesting parts are when it fires, who decides, and what gets thrown away. Every tool answers those differently.
What is DCP?
DCP — Dynamic Context Pruning — is an OpenCode plugin, not a model feature. It sits between your session history and the LLM request, deciding what actually gets sent to the model. That placement sounds mundane; it’s the whole point.
What DCP does
- Never mutates the actual session; swaps in placeholders/summaries only at request time, so the transcript on disk stays complete for auditing or replay.
- Three separate strategies, not one blunt mechanism:
compress— model-invoked tool, summarizes closed/stale spans (or individual messages in experimental mode)deduplication— drops repeated identical tool calls, keeps latestpurgeErrors— strips inputs from failed tool calls after N turns, keeps the error text
Usecases
A session makes the strategies concrete — and shows what they do to the token bill:
| turn | action | without DCP | with DCP | strategy |
|---|---|---|---|---|
| 1 | read auth.py (~1.4K) | 1.4K | 1.4K | — |
| 2 | read auth.py again | 2.8K | 1.4K | dedup |
| 3 | read auth.py again | 4.2K | 1.4K | — |
| 5 | pytest fails ×3, tracebacks | 9.6K | 6.8K | — |
| 7 | 4 turns past the failures | 11.0K | 5.6K | purgeErrors — inputs gone, errors kept |
| 9 | “fix imports” wraps up | 15.2K | 6.1K | compress — model nudged via exposed tool; 8 turns → a ~300-token summary |
| 15 | pytest green, more edits | 23.4K | 9.0K | — |
| 20 | session still going | 31.8K | 11.6K | — |
Numbers are illustrative — file sizes and tracebacks vary — but the shape is the point: at this rate the raw history crosses ~190K around turn 120 and hits panic compaction, while the pruned view stays lean because compress keeps folding closed spans. Each mechanism fired for a different reason: repetition, staleness, task closure. None of them waited for a threshold.
The nudge, and when there isn’t one
Those three strategies split into two kinds of work:
- Rules — no nudge. Dedup and purgeErrors are deterministic. Identical repeated call? Drop the older copies. Failed input four turns stale? Strip it. They fire on every request whether the model is thinking about memory or not — no model involvement, no permission asked.
- Judgment — nudge. Compress is the only strategy that needs taste: is this span actually finished? A plugin can’t know that. So DCP nudges: a hint travels with the request, telling the model the compress tool exists and when it fits. The model reads it and decides.
Nudged, not forced — and that’s the deliberate trade. Forcing would mean gating the model’s work on a memory call it might disagree with, so DCP accepts the “model forgot to compress” failure mode instead.
vs Claude Code auto-compact
- Trigger: fixed token/% threshold (currently ~95%, historically inconsistent — buffer size changed silently between versions).
- Mechanism: one-shot, whole-transcript summarize-and-replace when it fires.
- Control:
/compact [instructions], CLAUDE.md compact section — and for years no true off switch; documented env-var attempts to disable were silently ignored through 2025–26. Working switches only arrived recently, and that era is why people stopped trusting them.
vs Codex CLI
- Trigger:
model_auto_compact_token_limit, similarly threshold-based, capped at 90% — can’t be raised further. - Mechanism: for OpenAI-hosted models, compaction is a server-side encrypted blob (
type=compaction,encrypted_content) — opaque even to the client, explicitly “not intended to be human-interpretable.” Local models get plaintext LLM summarization instead. - On repeated compaction, prior summaries get discarded and replaced, not nested — each pass is built from the previous summary, so you lose fidelity every round.
The interesting bit
Both incumbents treat compaction as an infrastructure event: a threshold trips, the system yanks the whole transcript and replaces it with a summary, regardless of whether anything meaningful just finished. DCP inverts that — pruning tied to task completion semantics the model itself judges.
That’s a genuinely different failure mode to guard against. Instead of “ran out of room, panic-summarize everything,” it’s “model forgot to call compress, context grows unchecked.” Both are real; they’re duals, and each design picks one for you.
