Skip to content
    ↑↓ select↵ openesc close
    arafays

    Dcp

    opencode-dcp·v2.0.0-beta.13·Memory & Context

    Dynamic Context Pruning (DCP) plugin for OpenCode V2 - model-driven context compression, tool-output pruning, and context-window nudges

    GitHub stars

    4

    +3 in 30 days

    Monthly installs

    1,644

    425 in 7 days

    Composite score

    49.6

    Multi-signal model

    Last commit

    5 days ago

    2026-09-29

    Install and configure

    opencode.json

    Writes 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"]
    }

    OpenCode 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-greater 0.0.0-* prerelease as satisfying the range, and junk tags like windows-fix lack the Plugin export.

    How it works

    On every model dispatch (ctx.session.hook("context")) the plugin transforms the outbound transcript only — stored session history is never modified:

    1. Scan & mirror — index the transcript with stable keys; remember it so the prune tool can resolve ranges.
    2. 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 as b1, b2, ….
    3. Compression blocks — active blocks remove their covered ranges and splice a synthetic [Compressed conversation section] summary at the recorded anchor.
    4. Pruning — superseded/errored tool outputs are replaced with short placeholders (protected tools like question/edit are never touched).
    5. Nudges — when provider usage crosses maxContextLimit, a reminder asks the model to run prune; rate-limited by nudgeFrequency. 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