Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
43d6e7a
refactor: compress to rule them all
spoons-and-mirrors Feb 9, 2026
7e3fbed
tweaks
spoons-and-mirrors Feb 9, 2026
00ae4b4
3.0 release image
spoons-and-mirrors Feb 10, 2026
55f4f5f
prompt rewrite
spoons-and-mirrors Feb 10, 2026
8c28716
feat: annotate tool outputs with token counts
spoons-and-mirrors Feb 11, 2026
553ca89
pull prompts from dev for ref
spoons-and-mirrors Feb 11, 2026
6bdbd95
remove uid refs
spoons-and-mirrors Feb 11, 2026
8d21d58
refine tool format
spoons-and-mirrors Feb 11, 2026
15e4f17
prompts
spoons-and-mirrors Feb 11, 2026
a65d5db
rm dev prompts
spoons-and-mirrors Feb 11, 2026
9cffd3c
nudge
spoons-and-mirrors Feb 11, 2026
90318ce
changin token count wording
spoons-and-mirrors Feb 11, 2026
4c6b024
prompts: preserving user intent
spoons-and-mirrors Feb 11, 2026
1132af4
nudgeGap
spoons-and-mirrors Feb 12, 2026
da56861
feat: cLog
spoons-and-mirrors Feb 11, 2026
e391a8f
summary searching sucks
Tarquinen Feb 12, 2026
7741734
nudge
spoons-and-mirrors Feb 12, 2026
7a48c26
prompts
spoons-and-mirrors Feb 12, 2026
9b40772
cleanup context-limit hint injection architecture
Tarquinen Feb 12, 2026
ffc340d
token counts targets
spoons-and-mirrors Feb 12, 2026
701088b
range chronology badgering
spoons-and-mirrors Feb 12, 2026
13d622a
tool inputs badger
spoons-and-mirrors Feb 12, 2026
48d4729
refactor context-limit anchor lifecycle
Tarquinen Feb 12, 2026
eea6067
rename
Tarquinen Feb 12, 2026
3b19bb8
cleanup
Tarquinen Feb 12, 2026
e2b2797
cleanup
Tarquinen Feb 12, 2026
4025efe
cleanup
Tarquinen Feb 12, 2026
7608931
bargraph: v1
spoons-and-mirrors Feb 12, 2026
63bd217
bargraph v2
spoons-and-mirrors Feb 12, 2026
5c8e9b7
different shading for "new stuff since last compress use"
spoons-and-mirrors Feb 12, 2026
07eb6b5
cleanup
Tarquinen Feb 12, 2026
aa60c0d
remath proportional bargraph display
spoons-and-mirrors Feb 12, 2026
12c763a
cleanup
Tarquinen Feb 12, 2026
fca89fb
Merge branch 'refactor/one-tool-to-rule-them-all' into cleanup/contex…
Tarquinen Feb 12, 2026
83907c2
cleanup
Tarquinen Feb 12, 2026
38dc7f4
Merge pull request #386 from Opencode-DCP/cleanup/context-limit-hints
Tarquinen Feb 12, 2026
ed7e66f
use real nudge prompt
Tarquinen Feb 12, 2026
96e5b2e
add system prompt to bargraph session representation and use full bra…
spoons-and-mirrors Feb 12, 2026
96062b0
differentiate system prompt char
spoons-and-mirrors Feb 12, 2026
d4d637f
refactor: derive compress graph from token buckets
Tarquinen Feb 13, 2026
94f97bd
remove: unused contextPressure and compressContext config options
Tarquinen Feb 13, 2026
6c9c795
remove: unused nudgeEnabled and nudgeFrequency config options
Tarquinen Feb 13, 2026
bffa213
refactor: rename limitNudgeInterval to nudgeGap
Tarquinen Feb 13, 2026
e18f764
cleanup: remove dead prune/distill refs from prompts
Tarquinen Feb 13, 2026
acd72b9
cleanup: remove prune/distill remnants
spoons-and-mirrors Feb 13, 2026
7de0666
cleanup: simplify prompts to compress-only
Tarquinen Feb 13, 2026
8896aaa
cleanup: remove ToolFlags, simplify renderSystemPrompt
Tarquinen Feb 13, 2026
2399d1f
fix: fallback token accounting when api tokens missing
spoons-and-mirrors Feb 13, 2026
eaf25eb
cleanup: remove prompt loading indirection
Tarquinen Feb 13, 2026
43497b1
cleanup: rename applyAnchoredHints to applyAnchoredNudge
Tarquinen Feb 13, 2026
3684485
cleanup: remove unused nudgeCounter
Tarquinen Feb 13, 2026
e2cb885
cleanup: remove unused lastToolPrune
Tarquinen Feb 13, 2026
6ab7f24
feat(ui): render positional compress graph
Tarquinen Feb 13, 2026
65b016c
fix(compress): reject ambiguous summary matches
Tarquinen Feb 13, 2026
8af64d1
feat(ui): restore strict bargraph v2 compress map
Tarquinen Feb 13, 2026
0bdce2e
cleanup(ui): remove unused compression graph helpers
Tarquinen Feb 13, 2026
a600a10
cleanup: don't search reasoning parts for compress strings
Tarquinen Feb 13, 2026
65dcd21
chore: default nudgeGap to 5
Tarquinen Feb 13, 2026
302e901
format
Tarquinen Feb 13, 2026
53dee49
Merge pull request #381 from misterdas/fix/critical-bugs-and-improvem…
Tarquinen Feb 14, 2026
6ce2fb4
Merge remote-tracking branch 'origin/dev' into refactor/one-tool-to-r…
Tarquinen Feb 14, 2026
1394615
refactor: rework compress flow with block placeholders
Tarquinen Feb 15, 2026
3d867b3
docs: clarify compress placeholder guidance
Tarquinen Feb 15, 2026
80c8fd0
prompt: removing macro scale, try and force the model to compress sho…
spoons-and-mirrors Feb 15, 2026
8f57ea3
Merge branch 'refactor/one-tool-to-rule-them-all' into feat/compress-…
Tarquinen Feb 15, 2026
fd233eb
refactor: migrate scripts to OpenCode session API
Tarquinen Feb 15, 2026
eddf269
feat: migrate compress to injected ID boundaries
Tarquinen Feb 16, 2026
7b0dfea
Merge pull request #392 from Opencode-DCP/feat/compress-block-placeho…
Tarquinen Feb 16, 2026
385f361
refactor: migrate compress boundary resolution to injected IDs
Tarquinen Feb 17, 2026
27ed0b1
docs: update compress boundary guidance
Tarquinen Feb 17, 2026
0bd9771
refactor: inject assistant message IDs into last tool output
Tarquinen Feb 17, 2026
e59e216
docs: clarify dcp message-id metadata tags in prompts
Tarquinen Feb 17, 2026
66f4e66
refactor: inject IDs after compress
Tarquinen Feb 17, 2026
362352d
refactor: align compress blocks with bN metadata and placeholders
Tarquinen Feb 17, 2026
3c9ce68
docs: simplify and align compress/system ID guidance
Tarquinen Feb 17, 2026
12dc48c
refactor: make synthetic injection IDs deterministic
Tarquinen Feb 17, 2026
298d3eb
refactor: rename nudgeGap to nudgeFrequency and fix config inconsiste…
Tarquinen Feb 17, 2026
47017dc
refactor: remove tools.settings.protectedTools
Tarquinen Feb 18, 2026
e8e29e7
fix: preserve compress input schema when pruning
Tarquinen Feb 18, 2026
73220ff
refactor: gate ID injection on compress permission
Tarquinen Feb 18, 2026
2348e75
cleanup
Tarquinen Feb 18, 2026
3142eb9
feat: migrate opencode scripts from API to sqlite
Tarquinen Feb 18, 2026
506da6c
refactor: move inject helpers to messages utils
Tarquinen Feb 18, 2026
1a7442d
feat: add soft nudge anchors for context reminders
Tarquinen Feb 19, 2026
ea36818
refactor: stop generating non-system prompts from markdown
Tarquinen Feb 19, 2026
c75edaa
fix: guard malformed compress summaries
Tarquinen Feb 19, 2026
0752119
Merge branch 'dev' into refactor/one-tool-to-rule-them-all, resolving…
Tarquinen Feb 19, 2026
90889d0
refactor: simplify compress notification summary and rename header wr…
Tarquinen Feb 19, 2026
2fa382f
refactor: remove compress wrappers
Tarquinen Feb 19, 2026
ba4e7d4
fix(utils): skip thought signature validator for google and vertex mo…
Tarquinen Feb 21, 2026
c8d3404
feat(utils): add system note to synthetic tool part
Tarquinen Feb 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ Thumbs.db
# OpenCode
.opencode/

# Python cache
__pycache__/
*.py[cod]
*$py.class

# Generated prompt files (from scripts/generate-prompts.ts)
lib/prompts/**/*.generated.ts

Expand All @@ -40,4 +45,4 @@ test-update.ts
docs/
SCHEMA_NOTES.md

repomix-output.xml
repomix-output.xml
5 changes: 4 additions & 1 deletion .repomixignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ dist/
repomix-output.xml
bun.lock
package-lock.jsonc
LICENCE
LICENSE
scripts/
tests/
README.md
44 changes: 14 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ Restart OpenCode. The plugin will automatically start optimizing your sessions.

## How Pruning Works

DCP uses multiple tools and strategies to reduce context size:
DCP uses one user-facing tool and strategies to reduce context size:

### Tools
For model-facing behavior (prompts and tool calls), this capability is always addressed as `compress`.

**Distill** — Exposes a `distill` tool that the AI can call to distill valuable context into concise summaries before removing the tool content.
### Tool

**Compress** — Exposes a `compress` tool that the AI can call to collapse a large section of conversation (messages and tools) into a single summary.
**Compress** — Exposes a single `compress` tool with one method: select a conversation range using injected `startId` and `endId` (`mNNNN` or `bN`), then replace it with a technical summary.

**Prune** — Exposes a `prune` tool that the AI can call to remove completed or noisy tool content from context.
The model can use that same method at different scales: tiny ranges for noise cleanup, focused ranges for preserving key findings, and full chapters for completed work.

### Strategies

Expand Down Expand Up @@ -105,13 +105,10 @@ DCP uses its own config file:
> // Protect file operations from pruning via glob patterns
> // Patterns match tool parameters.filePath (e.g. read/write/edit)
> "protectedFilePatterns": [],
> // LLM-driven context pruning tools
> // LLM-driven context management tool
> "tools": {
> // Shared settings for all prune tools
> // Shared settings for context management
> "settings": {
> // Nudge the LLM to use prune tools (every <nudgeFrequency> tool results)
> "nudgeEnabled": true,
> "nudgeFrequency": 10,
> // Token limit at which the model compresses session context
> // to keep the model in the "smart zone" (not a hard limit)
> // Accepts: number or "X%" (percentage of model's context window)
Expand All @@ -123,28 +120,16 @@ DCP uses its own config file:
> // "openai/gpt-5": 120000,
> // "anthropic/claude-3-7-sonnet": "80%"
> // },
> // Additional tools to protect from pruning
> "protectedTools": [],
> // How often the context-limit nudge fires (1 = every fetch, 5 = every 5th)
> "nudgeFrequency": 5,
> },
> // Distills key findings into preserved knowledge before removing raw content
> "distill": {
> // Unified context compression tool
> "compress": {
> // Permission mode: "allow" (no prompt), "ask" (prompt), "deny" (tool not registered)
> "permission": "allow",
> // Show distillation content as an ignored message notification
> "showDistillation": false,
> },
> // Collapses a range of conversation content into a single summary
> "compress": {
> // Permission mode: "deny" (tool not registered), "ask" (prompt), "allow" (no prompt)
> "permission": "deny",
> // Show summary content as an ignored message notification
> "showCompression": false,
> },
> // Removes tool content from context without preservation (for completed tasks or noise)
> "prune": {
> // Permission mode: "allow" (no prompt), "ask" (prompt), "deny" (tool not registered)
> "permission": "allow",
> },
> },
> // Automatic pruning strategies
> "strategies": {
Expand Down Expand Up @@ -181,16 +166,15 @@ DCP provides a `/dcp` slash command:
- `/dcp stats` — Shows cumulative pruning statistics across all sessions.
- `/dcp sweep` — Prunes all tools since the last user message. Accepts an optional count: `/dcp sweep 10` prunes the last 10 tools. Respects `commands.protectedTools`.
- `/dcp manual [on|off]` — Toggle manual mode or set explicit state. When on, the AI will not autonomously use context management tools.
- `/dcp prune [focus]` — Trigger a single prune tool execution. Optional focus text directs the AI's pruning decisions.
- `/dcp distill [focus]` — Trigger a single distill tool execution. Optional focus text directs what to distill.

- `/dcp compress [focus]` — Trigger a single compress tool execution. Optional focus text directs what range to compress.

### Protected Tools

By default, these tools are always protected from pruning:
`task`, `todowrite`, `todoread`, `distill`, `compress`, `prune`, `batch`, `plan_enter`, `plan_exit`
`task`, `todowrite`, `todoread`, `compress`, `batch`, `plan_enter`, `plan_exit`

The `protectedTools` arrays in each section add to this default list.
The `protectedTools` arrays in `commands` and `strategies` add to this default list.

### Config Precedence

Expand Down
Binary file added assets/images/3.0 release.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 9 additions & 52 deletions dcp.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@
"type": "string",
"enum": ["off", "minimal", "detailed"],
"default": "detailed",
"description": "Level of notification shown when pruning occurs"
"description": "Level of notification shown when context management occurs"
},
"pruneNotificationType": {
"type": "string",
"enum": ["chat", "toast"],
"default": "chat",
"description": "Where to display prune notifications (chat message or toast notification)"
"description": "Where to display notifications (chat message or toast notification)"
},
"commands": {
"type": "object",
Expand Down Expand Up @@ -104,31 +104,19 @@
},
"tools": {
"type": "object",
"description": "Configuration for pruning tools",
"description": "Configuration for context-management tools",
"additionalProperties": false,
"properties": {
"settings": {
"type": "object",
"description": "General tool settings",
"additionalProperties": false,
"properties": {
"nudgeEnabled": {
"type": "boolean",
"default": true,
"description": "Enable nudge reminders to prune context"
},
"nudgeFrequency": {
"type": "number",
"default": 10,
"description": "Frequency of nudge reminders (in turns)"
},
"protectedTools": {
"type": "array",
"items": {
"type": "string"
},
"default": [],
"description": "Tool names that should be protected from automatic pruning"
"default": 5,
"minimum": 1,
"description": "How often the context-limit nudge fires when above contextLimit (1 = every fetch, 5 = every 5th fetch)"
},
"contextLimit": {
"description": "When session tokens exceed this limit, a compress nudge is injected (\"X%\" uses percentage of the model's context window)",
Expand Down Expand Up @@ -160,52 +148,21 @@
}
}
},
"distill": {
"type": "object",
"description": "Configuration for the distill tool",
"additionalProperties": false,
"properties": {
"permission": {
"type": "string",
"enum": ["ask", "allow", "deny"],
"default": "allow",
"description": "Permission mode (deny disables the tool)"
},
"showDistillation": {
"type": "boolean",
"default": false,
"description": "Show distillation output in the UI"
}
}
},
"compress": {
"type": "object",
"description": "Configuration for the compress tool",
"description": "Configuration for the unified compress tool",
"additionalProperties": false,
"properties": {
"permission": {
"type": "string",
"enum": ["ask", "allow", "deny"],
"default": "ask",
"default": "allow",
"description": "Permission mode (deny disables the tool)"
},
"showCompression": {
"type": "boolean",
"default": false,
"description": "Show summary output in the UI"
}
}
},
"prune": {
"type": "object",
"description": "Configuration for the prune tool",
"additionalProperties": false,
"properties": {
"permission": {
"type": "string",
"enum": ["ask", "allow", "deny"],
"default": "allow",
"description": "Permission mode (deny disables the tool)"
"description": "Show compression summaries in notifications"
}
}
}
Expand Down
24 changes: 1 addition & 23 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Plugin } from "@opencode-ai/plugin"
import { getConfig } from "./lib/config"
import { Logger } from "./lib/logger"
import { createSessionState } from "./lib/state"
import { createPruneTool, createDistillTool, createCompressTool } from "./lib/strategies"
import { createCompressTool } from "./lib/tools"
import {
createChatMessageTransformHandler,
createCommandExecuteHandler,
Expand Down Expand Up @@ -61,15 +61,6 @@ const plugin: Plugin = (async (ctx) => {
ctx.directory,
),
tool: {
...(config.tools.distill.permission !== "deny" && {
distill: createDistillTool({
client: ctx.client,
state,
logger,
config,
workingDirectory: ctx.directory,
}),
}),
...(config.tools.compress.permission !== "deny" && {
compress: createCompressTool({
client: ctx.client,
Expand All @@ -79,15 +70,6 @@ const plugin: Plugin = (async (ctx) => {
workingDirectory: ctx.directory,
}),
}),
...(config.tools.prune.permission !== "deny" && {
prune: createPruneTool({
client: ctx.client,
state,
logger,
config,
workingDirectory: ctx.directory,
}),
}),
},
config: async (opencodeConfig) => {
if (config.commands.enabled) {
Expand All @@ -99,9 +81,7 @@ const plugin: Plugin = (async (ctx) => {
}

const toolsToAdd: string[] = []
if (config.tools.distill.permission !== "deny") toolsToAdd.push("distill")
if (config.tools.compress.permission !== "deny") toolsToAdd.push("compress")
if (config.tools.prune.permission !== "deny") toolsToAdd.push("prune")

if (toolsToAdd.length > 0) {
const existingPrimaryTools = opencodeConfig.experimental?.primary_tools ?? []
Expand All @@ -118,9 +98,7 @@ const plugin: Plugin = (async (ctx) => {
const permission = opencodeConfig.permission ?? {}
opencodeConfig.permission = {
...permission,
distill: config.tools.distill.permission,
compress: config.tools.compress.permission,
prune: config.tools.prune.permission,
} as typeof permission
},
}
Expand Down
10 changes: 4 additions & 6 deletions lib/commands/help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,16 @@ const BASE_COMMANDS: [string, string][] = [
]

const TOOL_COMMANDS: Record<string, [string, string]> = {
prune: ["/dcp prune [focus]", "Trigger manual prune tool execution"],
distill: ["/dcp distill [focus]", "Trigger manual distill tool execution"],
compress: ["/dcp compress [focus]", "Trigger manual compress tool execution"],
}

function getVisibleCommands(config: PluginConfig): [string, string][] {
const commands = [...BASE_COMMANDS]
for (const tool of ["prune", "distill", "compress"] as const) {
if (config.tools[tool].permission !== "deny") {
commands.push(TOOL_COMMANDS[tool])
}

if (config.tools.compress.permission !== "deny") {
commands.push(TOOL_COMMANDS.compress)
}

return commands
}

Expand Down
Loading