Dcp
Dynamic Context Pruning (DCP) plugin for OpenCode V2 - model-driven context compression, tool-output pruning, and context-window nudges
4
+3 in 30 days
1,644
425 in 7 days
49.6
Multi-signal model
5 days ago
2026-09-29
Install and configure
opencode.jsonWrites to this project's opencode.json — applies to this repository only.
opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-dcp@2.0.0-beta.13"]
}Writes to ~/.config/opencode/opencode.json — applies to every project.
~/.config/opencode/opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-dcp@2.0.0-beta.13"]
}If you want to modify the plugin locally, install it into the project and reference the local path.
shell
pnpm add -D opencode-dcpOpenCode loads npm dependencies through its embedded runtime on startup and caches them locally — no manual global install needed.
Dynamic Context Pruning (DCP) for OpenCode V2.
Keeps the model's context window high-signal by letting the model compress closed sections of the conversation into its own dense technical summaries, pruning superseded tool outputs, and nudging when context pressure crosses a budget.
Requires OpenCode V2 (
opencode2). The plugin API is beta; pin versions that match your OpenCode release.
Install
opencode2 plugin add opencode-dcp
This installs the package into OpenCode's plugin cache and registers its server
entrypoint in your global config. The TUI companion needs no extra step: the
runtime detects the companion itself (via the package's ./tui export), so a
locally connected TUI discovers the active plugin and loads its ./tui export
from the cache on its own. Or add it
directly to a project config:
{
"plugins": [
{
"package": "opencode-dcp",
"options": {
"debug": false,
"maxContextLimit": "70%"
}
}
]
}
Development (this repo): build first (npm install && npm run build), then
point config at the local entrypoint:
{
"plugins": [
{
"package": "../dist",
"options": {
"debug": true,
"maxContextLimit": "70%",
"tui": { "enabled": false }
}
}
]
}
The build copies tui.tsx next to dist/index.js, and the runtime auto-loads a
sibling tui.* file beside a local plugin's index.* entrypoint — so the
companion loads for this local-path entry too, exactly like the ./tui export
does for package installs.
Requires OpenCode V2 (
opencode2). OpenCode V2 auto-updates, so the package tracks@opencode/plugin(the committed lockfile pins the exact resolved version for local dev). Don't use a caret range on a prerelease (^0.0.0-beta-…) — npm treats any lexically-greater0.0.0-*prerelease as satisfying the range, and junk tags likewindows-fixlack thePluginexport.
How it works
On every model dispatch (ctx.session.hook("context")) the plugin transforms the
outbound transcript only — stored session history is never modified:
- Scan & mirror — index the transcript with stable keys; remember it so the
prunetool can resolve ranges. - Boundary IDs — every message gets an alias
m0001, m0002, …injected as<dcp-message-id>tags on user texts and textual tool results. Compressed sections are addressed asb1, b2, …. - Compression blocks — active blocks remove their covered ranges and splice
a synthetic
[Compressed conversation section]summary at the recorded anchor. - Pruning — superseded/errored tool outputs are replaced with short
placeholders (protected tools like
question/editare never touched). - Nudges — when provider usage crosses
maxContextLimit, a reminder asks the model to runprune; rate-limited bynudgeFrequency. Reminders name both denominators (the pruning budget and the model window) and re-measure per dispatch, so an older percentage is never acted on. A completed prune is answered by a one-shot acknowledgement on the next dispatch that quotes the fresh measurement and says whether another pass is needed.
The model calls prune itself. It is deliberately registered as a direct
tool (options.codemode: false, never the platform's codemode: true default):
only codemode === false tools are emitted as native tool definitions, so the
full PRUNE_RANGE boundary-ID rules ship on every request instead of being
folded into the Code Mode execute catalog, whose inline listings truncate each
tool's first line to 120 characters. The name prune avoids clashing with the
platform's built-in compress tool, and options.permission: "prune" pins the
permission action to the tool's own name. It picks non-overlapping ranges by boundary ID and writes
dense summaries per range. A range may cover previously pruned blocks: including
(bN) carries that block's full content forward, omitting it permanently drops
the block's content from context — how stale completed work gets pruned.
Deduplication and error-purge strategies run
at compression time so idle sessions keep their prompt-cache prefix stable.
State persists per session across restarts via plugin storage.
TUI panel
A companion TUI module ships with the package and is enabled by default
(the runtime loads the package's ./tui export). While a session runs it shows:
- Prompt footer status: live outbound-token savings of the last dispatch
(
DCP −38% · 8.1k pruned), or — while no blocks are active — the measured window pressure (DCP idle · 62% of window) instead of a misleading−0%savings figure. - Prune summary card above the composer: pops when a compression lands and
auto-hides after 30 seconds — cumulative savings, a context-usage bar for the
session model, and the compression's scope: the pruned section before/after
token sizes (
19.5k → 0.7k tok, with the percent scoped to the section, not the whole context). Command palette → "DCP: toggle prune summary card" pins it for the session. - Command palette → "DCP: compression report": per-session totals (dispatches, compressions, blocks), last-dispatch delta, cumulative token savings from blocks and pruning, and the most recent compression events.
Mechanism: the server plugin writes a stats snapshot to the TUI's watched
storage file (~/.local/state/opencode/<channel>/tui/plugin.opencode.dcp.tui.stats.json)
after every dispatch and compression; the TUI module reads it as a reactive
store, so numbers update live. Disabling stops stats writes and quiets the
panel:
{
"plugins": [
{
"package": "opencode-dcp",
"options": { "tui": { "enabled": false } }
}
]
}
Commands
| Command | Effect |
|---|---|
/dcp-prune [focus] |
Instructs the model to run a pruning pass now |
Options
All optional (defaults shown):
{
"enabled": true,
"debug": false,
"allowSubAgents": false, // run inside sub-agent sessions
"maxContextLimit": 70000, // absolute tokens, or "NN%" of the model window
"nudgeFrequency": 5, // min messages between nudges
"iterationNudgeThreshold": 0, // messages since last user turn before an iteration nudge (0 = off)
"protectedTools": [], // globs never auto-pruned ("mcp*")
"protectedFilePatterns": [], // path globs never auto-pruned ("secrets/**")
"tui": { "enabled": true }, // companion TUI panel (stats + report)
"strategies": {
"deduplication": { "enabled": true, "protectedTools": [] },
"purgeErrors": { "enabled": true, "turns": 4, "protectedTools": [] }
}
}
Permissions: the tool's permission action is prune; gate it with normal V2
permission rules ({ "action": "prune", "effect": "allow" }).
Develop
npm install
npm run typecheck # tsc --noEmit
npm test # node --import tsx --test test/*.test.ts
npm run build # tsup -> dist/
MIT. See LICENSE.
Similar plugins
Dcp Dynamic Limits
opencode-dcp-dynamic-limits
OpenCode plugin that syncs DCP context limits to the active model and quiets chat reminder spam.
Okf Context
opencode-okf-context
OpenCode plugin: progressive disclosure + auto-unload for OKF (Open Knowledge Format) knowledge bundles. Inspired by DCP's outbound-only context transformation.
Rtk
opencode-rtk-plugin
OpenCode v2 plugin that rewrites shell commands through rtk to cut LLM token usage by 60-90%.