Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
123 commits
Select commit Hold shift + click to select a range
0d8147e
WIP: dev stash changes
Tarquinen Jan 24, 2026
cd77e3d
feat: add squash tool and combo prompt variants
Tarquinen Jan 25, 2026
278f862
refactor: use ulid for synthetic message ID generation
Tarquinen Jan 26, 2026
6ce83d6
refactor: move squashSummaries to top-level state
Tarquinen Jan 26, 2026
41a7c08
refactor: move squash utility functions to tools/utils.ts
Tarquinen Jan 26, 2026
adfdd71
fix: add secure mode authentication support
Tarquinen Jan 27, 2026
ca972e0
refactor: append context info to existing assistant messages instead …
Tarquinen Jan 28, 2026
8e57d9d
fix: improve discard/extract robustness and fix missing cache sync (D…
Tarquinen Jan 28, 2026
db08fc3
v1.3.0-beta.1 - Bump beta version
Tarquinen Jan 28, 2026
0e803ea
docs: sync schema and README with implementation of protected tools
Tarquinen Jan 28, 2026
80f1a7e
docs: add ko-fi badge to README
Tarquinen Jan 28, 2026
a39c766
swap readme buttons
Tarquinen Jan 28, 2026
ff132f1
validate extraction is array
Tarquinen Jan 28, 2026
3470c06
improve squash tool error messages to specify which boundary string f…
Tarquinen Jan 28, 2026
d3cbf5d
revert prompt style to dev branch format with semantic improvements
Tarquinen Jan 28, 2026
74cdce5
v1.3.1-beta.0 - Bump version
Tarquinen Jan 28, 2026
286b309
docs: move demo images to assets/images directory
Tarquinen Jan 28, 2026
ce86682
fix: ensure tool count accuracy in context breakdown using unique cal…
Tarquinen Jan 29, 2026
2255691
cleanup
Tarquinen Jan 29, 2026
0a381d8
refactor: inject assistant text parts instead of tool parts
Tarquinen Jan 29, 2026
f963d8a
refactor: hybrid injection strategy for DeepSeek/Kimi models
Tarquinen Jan 29, 2026
e1f5312
injection guide comments
Tarquinen Jan 29, 2026
a74cb8b
refactor: new prompt structure and dx cli
spoons-and-mirrors Jan 29, 2026
0bcec1d
inline tags to avoid unwanted linebreak
spoons-and-mirrors Jan 29, 2026
c645e69
nudge
spoons-and-mirrors Jan 29, 2026
06ce131
gitignore
spoons-and-mirrors Jan 29, 2026
53e2c15
DCP: Distill Compress Prune
spoons-and-mirrors Jan 29, 2026
5863a1d
reorder tool registering
spoons-and-mirrors Jan 29, 2026
3d9e4df
Merge pull request #327 from Opencode-DCP/prompt/refactor
Tarquinen Jan 30, 2026
efead8f
fix: generate .ts from .md at build time for bundler compatibility
Tarquinen Jan 30, 2026
cdb5862
refactor: consolidate cli/ into scripts/
Tarquinen Jan 30, 2026
f123eb3
Fix context summary output to handle cases where only tools or only m…
Tarquinen Jan 30, 2026
2cd85fc
revert: show cooldown for errored tools to prevent loop behavior
Tarquinen Jan 30, 2026
866bdc1
spell check
Tarquinen Jan 30, 2026
d66a6c2
docs: standardize DCP tool order to distill, compress, prune
Tarquinen Jan 30, 2026
22f5848
Rename compress tool config from showSummary to showCompression
Tarquinen Jan 30, 2026
9ad912c
chore: bump version to 1.3.1-beta.2
Tarquinen Jan 30, 2026
fbf3bd8
Merge pull request #331 from Opencode-DCP/beta
Tarquinen Jan 31, 2026
d71f5c6
stuff
Tarquinen Jan 31, 2026
4bd1fb8
maybe
Tarquinen Jan 31, 2026
85b0aeb
cc cache readme stuff
Tarquinen Jan 31, 2026
b8d7486
cleanup
Tarquinen Jan 31, 2026
0fc988a
cleanup tool cache logic
Tarquinen Jan 31, 2026
a8b2551
update dependencies and migrate to v2 sdk
Tarquinen Jan 31, 2026
a21285a
feat: add full tool pruning for edit and write tools
Tarquinen Jan 31, 2026
dc104e2
fix: move schema validation to execute() for better error messages
Tarquinen Jan 31, 2026
7453ed4
v1.3.2-beta.0 - Bump version
Tarquinen Jan 31, 2026
4e03a4b
refactor: use Set for prune ID storage
Tarquinen Feb 1, 2026
b3d9e5b
feat: support toast notifications via notificationType config option
essinghigh Feb 1, 2026
8f469ad
prettier
essinghigh Feb 1, 2026
7e3a43c
Merge branch 'dev' into notification-toast-dev
Tarquinen Feb 1, 2026
e96796d
Merge pull request #340 from essinghigh/notification-toast-dev
Tarquinen Feb 1, 2026
6148868
refactor: revert to simpler tool part injection for all models
Tarquinen Feb 1, 2026
698392e
fix: restore Gemini thoughtSignature bypass for synthetic tool parts
Tarquinen Feb 1, 2026
0bcacfb
refactor: rename prunedCount to prunedToolCount for clarity
Tarquinen Feb 1, 2026
e595928
docs: add pruneNotificationType to README config example
Tarquinen Feb 1, 2026
e82ed4d
feat: add message count tracking to stats display
Tarquinen Feb 1, 2026
1d93287
v1.3.3-beta.0 - Bump version
Tarquinen Feb 1, 2026
5166df3
refactor: inject context as text part in existing user message
Tarquinen Feb 2, 2026
3a1bfd6
feat: use synthetic assistant messages for non-DeepSeek/Kimi injection
Tarquinen Feb 2, 2026
0467654
refactor: use tool parts for all non-user-message injections
Tarquinen Feb 3, 2026
7e44bd7
chore: track tests/, gitignore tests/results/
Tarquinen Feb 3, 2026
5df9e01
feat: add session analysis utility scripts
Tarquinen Feb 3, 2026
16c8f25
test: add DCP cache testing script
Tarquinen Feb 3, 2026
1a3b7f3
refactor: simplify context injection to use tool parts universally
Tarquinen Feb 3, 2026
cbbf60a
chore: remove unused variant variable from inject.ts
Tarquinen Feb 3, 2026
e5b2038
feat: add token counting for prunable tools
Tarquinen Feb 3, 2026
7304f0a
feat: add context usage info to prunable tools list
Tarquinen Feb 3, 2026
b5a4d05
refactor: use userInfo consistently in synthetic part creation
Tarquinen Feb 3, 2026
e76a8ce
readme update
Tarquinen Feb 3, 2026
19484ca
Relicense to AGPL-3.0 and add Contributor License Agreement (CLA)
Tarquinen Feb 4, 2026
3828d47
Add PR template and update CONTRIBUTING.md with official CLA info
Tarquinen Feb 4, 2026
2f036c6
Clarify CLA process and reference SAP template in CONTRIBUTING.md
Tarquinen Feb 4, 2026
ebf8ba2
chore: format legal and PR files
Tarquinen Feb 4, 2026
5b88376
chore: switch to implicit CLA model
Tarquinen Feb 4, 2026
4e43419
docs: add uniform token pricing providers to best use cases
azais-corentin Feb 4, 2026
e27a997
WIP: system prompt refactor
spoons-and-mirrors Jan 30, 2026
7baf250
progress
spoons-and-mirrors Jan 30, 2026
e5c56fc
system
spoons-and-mirrors Jan 30, 2026
6ea2001
Update system.md
spoons-and-mirrors Jan 31, 2026
9722f54
compress default ask permission
spoons-and-mirrors Feb 3, 2026
47406be
system
spoons-and-mirrors Feb 3, 2026
8878b39
system done
spoons-and-mirrors Feb 3, 2026
becbcd9
reorg
spoons-and-mirrors Feb 3, 2026
c7ffaf7
migration: cleanup old gen files
spoons-and-mirrors Feb 3, 2026
ae98667
fix: tool permission
spoons-and-mirrors Feb 3, 2026
edb8353
distill
spoons-and-mirrors Feb 4, 2026
fed4501
prune
spoons-and-mirrors Feb 4, 2026
e3b6f8b
compress: restructure schema with topic primary, content nested (star…
spoons-and-mirrors Feb 4, 2026
cf90194
fix: sync package-lock.json with package.json
Tarquinen Feb 4, 2026
8b79e95
style: fix formatting
Tarquinen Feb 4, 2026
b8ace83
fix compress ask permission overwrite
spoons-and-mirrors Feb 4, 2026
1d8e000
vocab mix
spoons-and-mirrors Feb 4, 2026
01cfafb
small compress change
spoons-and-mirrors Feb 4, 2026
ff89f13
system timing
spoons-and-mirrors Feb 4, 2026
451fb00
typos
spoons-and-mirrors Feb 4, 2026
418ad56
PR #332: prompts rewrite, build prompt gen, tool schemas, compress de…
spoons-and-mirrors Feb 4, 2026
1e211d4
Merge branch 'dev' into patch-1
Tarquinen Feb 4, 2026
93a5e5b
Merge pull request #348 from azais-corentin/patch-1
Tarquinen Feb 4, 2026
daa8d46
Order DCP tool listings
Tarquinen Feb 4, 2026
b2276c7
Implement contextLimit config and update system prompts
Tarquinen Feb 4, 2026
3877f31
Fix schema syntax and format
Tarquinen Feb 4, 2026
b4f8765
fix: respect XDG base directory env vars for config and log paths
NamedIdentity Feb 4, 2026
4ea8591
Add apply_patch and multiedit support to file path extraction
Tarquinen Feb 4, 2026
e916cab
Set showCompression to false by default and sync schema
Tarquinen Feb 4, 2026
9f3903f
v1.4.0-beta.0 - Bump version
Tarquinen Feb 4, 2026
29191fe
fix: respect XDG_DATA_HOME in state persistence storage path
NamedIdentity Feb 4, 2026
7971886
Replace compress enabled with permission enum (ask/allow/deny)
spoons-and-mirrors Feb 5, 2026
59d2f98
distill and prune
spoons-and-mirrors Feb 5, 2026
e7cdd3c
Merge pull request #350 from NamedIdentity/fix/xdg-base-directory-paths
Tarquinen Feb 5, 2026
f968fb9
format
Tarquinen Feb 5, 2026
c9b41c2
Merge branch 'dev' into permissions
Tarquinen Feb 5, 2026
47b1703
Merge pull request #351 from Opencode-DCP/permissions
Tarquinen Feb 5, 2026
424249c
replace context header with token-triggered compress nudge
Tarquinen Feb 5, 2026
6e12c5a
revert: use XDG_CONFIG_HOME for logs instead of XDG_DATA_HOME
Tarquinen Feb 5, 2026
e0ea460
fix: cache toolIdList to prevent prune ID mismatch
Tarquinen Feb 5, 2026
f4bebd7
v1.4.0-beta.1 - Bump version
Tarquinen Feb 5, 2026
177c176
v1.4.1-beta.0 - Bump version
Tarquinen Feb 5, 2026
afeb5e3
logic/prompts: prioritize and restyle compress nudge
Tarquinen Feb 5, 2026
e30d0fe
v1.4.2-beta.0 - Bump version
Tarquinen Feb 5, 2026
e27f47d
contextLimit readme cleanup
Tarquinen Feb 5, 2026
5731262
cleanup
Tarquinen Feb 5, 2026
67684be
more
Tarquinen Feb 5, 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
9 changes: 7 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,16 @@ Thumbs.db
# OpenCode
.opencode/

# Tests (local development only)
tests/
# Generated prompt files (from scripts/generate-prompts.ts)
lib/prompts/**/*.generated.ts

# Tests
tests/results/
notes/
test-update.ts

# Documentation (local development only)
docs/
SCHEMA_NOTES.md

repomix-output.xml
9 changes: 9 additions & 0 deletions .repomixignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.github/
.logs/
.opencode/
dist/
.repomixignore
repomix-output.xml
bun.lock
package-lock.jsonc
LICENCE
26 changes: 26 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Contributing to DCP

Thank you for your interest in contributing to Dynamic Context Pruning (DCP)!

## License and Contributions

This project uses the **GNU Affero General Public License v3.0 (AGPL-3.0)**.

### Contribution Agreement

By submitting a Pull Request to this project, you agree that:

1. Your contributions are licensed under the **AGPL-3.0**.
2. You grant the project maintainer(s) a non-exclusive, perpetual, irrevocable, worldwide, royalty-free, transferable license to use, modify, and re-license your contributions under any terms they choose, including commercial or proprietary licenses.

This arrangement ensures the project remains Open Source while providing a path for commercial sustainability.

## Getting Started

1. Fork the repository.
2. Create a feature branch.
3. Implement your changes and add tests if applicable.
4. Ensure all tests pass and the code is formatted.
5. Submit a Pull Request.

We look forward to your contributions!
640 changes: 619 additions & 21 deletions LICENSE

Large diffs are not rendered by default.

198 changes: 110 additions & 88 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# Dynamic Context Pruning Plugin

[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/dansmolsky)
[![npm version](https://img.shields.io/npm/v/@tarquinen/opencode-dcp.svg)](https://www.npmjs.com/package/@tarquinen/opencode-dcp)

Automatically reduces token usage in OpenCode by removing obsolete tools from conversation history.
Automatically reduces token usage in OpenCode by removing obsolete content from conversation history.

![DCP in action](dcp-demo5.png)
![DCP in action](assets/images/dcp-demo5.png)

## Installation

Expand All @@ -27,15 +28,17 @@ DCP uses multiple tools and strategies to reduce context size:

### Tools

**Discard** — Exposes a `discard` tool that the AI can call to remove completed or noisy tool content from context.
**Distill** — Exposes a `distill` tool that the AI can call to distill valuable context into concise summaries before removing the tool content.

**Extract** — Exposes an `extract` tool that the AI can call to distill valuable context into concise summaries before removing the tool content.
**Compress** — Exposes a `compress` tool that the AI can call to collapse a large section of conversation (messages and tools) into a single summary.

**Prune** — Exposes a `prune` tool that the AI can call to remove completed or noisy tool content from context.

### Strategies

**Deduplication** — Identifies repeated tool calls (e.g., reading the same file multiple times) and keeps only the most recent output. Runs automatically on every request with zero LLM cost.

**Supersede Writes** — Prunes write tool inputs for files that have subsequently been read. When a file is written and later read, the original write content becomes redundant since the current file state is captured in the read result. Runs automatically on every request with zero LLM cost.
**Supersede Writes** — Removes write tool calls for files that have subsequently been read. When a file is written and later read, the original write content becomes redundant since the current file state is captured in the read result. Runs automatically on every request with zero LLM cost.

**Purge Errors** — Prunes tool inputs for tools that returned errors after a configurable number of turns (default: 4). Error messages are preserved for context, but the potentially large input content is removed. Runs automatically on every request with zero LLM cost.

Expand All @@ -47,90 +50,113 @@ LLM providers like Anthropic and OpenAI cache prompts based on exact prefix matc

**Trade-off:** You lose some cache read benefits but gain larger token savings from reduced context size and performance improvements through reduced context poisoning. In most cases, the token savings outweigh the cache miss cost—especially in long sessions where context bloat becomes significant.

> **Note:** In testing, cache hit rates were approximately 65% with DCP enabled vs 85% without.
> **Note:** In testing, cache hit rates were approximately 80% with DCP enabled vs 85% without for most providers.

**Best use case:** Providers that count usage in requests, such as Github Copilot and Google Antigravity, have no negative price impact.

**Best use cases:**

- **Request-based billing** — Providers that count usage in requests, such as Github Copilot and Google Antigravity, have no negative price impact.
- **Uniform token pricing** — Providers that bill cached tokens at the same rate as regular input tokens, such as Cerebras, see pure savings with no cache-miss penalty.

**Best use case:** Providers that count usage in requests, such as Github Copilot and Google Antigravity have no negative price impact.
**Claude Subscriptions:** Anthropic subscription users (who receive "free" caching) may experience faster limit depletion than hit-rate ratios suggest due to the higher relative cost of cache misses. See [Claude Cache Limits](https://she-llac.com/claude-limits) for details.

## Configuration

DCP uses its own config file:

- Global: `~/.config/opencode/dcp.jsonc` (or `dcp.json`), created automatically on first run
- Custom config directory: `$OPENCODE_CONFIG_DIR/dcp.jsonc` (or `dcp.json`), if `OPENCODE_CONFIG_DIR` is set
- Project: `.opencode/dcp.jsonc` (or `dcp.json`) in your project’s `.opencode` directory

<details>
<summary><strong>Default Configuration</strong> (click to expand)</summary>

```jsonc
{
"$schema": "https://raw.githubusercontent.com/Opencode-DCP/opencode-dynamic-context-pruning/master/dcp.schema.json",
// Enable or disable the plugin
"enabled": true,
// Enable debug logging to ~/.config/opencode/logs/dcp/
"debug": false,
// Notification display: "off", "minimal", or "detailed"
"pruneNotification": "detailed",
// Slash commands configuration
"commands": {
"enabled": true,
// Additional tools to protect from pruning via commands (e.g., /dcp sweep)
"protectedTools": [],
},
// Protect from pruning for <turns> message turns
"turnProtection": {
"enabled": false,
"turns": 4,
},
// Protect file operations from pruning via glob patterns
// Patterns match tool parameters.filePath (e.g. read/write/edit)
"protectedFilePatterns": [],
// LLM-driven context pruning tools
"tools": {
// Shared settings for all prune tools
"settings": {
// Nudge the LLM to use prune tools (every <nudgeFrequency> tool results)
"nudgeEnabled": true,
"nudgeFrequency": 10,
// Additional tools to protect from pruning
"protectedTools": [],
},
// Removes tool content from context without preservation (for completed tasks or noise)
"discard": {
"enabled": true,
},
// Distills key findings into preserved knowledge before removing raw content
"extract": {
"enabled": true,
// Show distillation content as an ignored message notification
"showDistillation": false,
},
},
// Automatic pruning strategies
"strategies": {
// Remove duplicate tool calls (same tool with same arguments)
"deduplication": {
"enabled": true,
// Additional tools to protect from pruning
"protectedTools": [],
},
// Prune write tool inputs when the file has been subsequently read
"supersedeWrites": {
"enabled": false,
},
// Prune tool inputs for errored tools after X turns
"purgeErrors": {
"enabled": true,
// Number of turns before errored tool inputs are pruned
"turns": 4,
// Additional tools to protect from pruning
"protectedTools": [],
},
},
}
```

</details>
- Project: `.opencode/dcp.jsonc` (or `dcp.json`) in your project's `.opencode` directory

> <details>
> <summary><strong>Default Configuration</strong> (click to expand)</summary>
>
> ```jsonc
> {
> "$schema": "https://raw.githubusercontent.com/Opencode-DCP/opencode-dynamic-context-pruning/master/dcp.schema.json",
> // Enable or disable the plugin
> "enabled": true,
> // Enable debug logging to ~/.config/opencode/logs/dcp/
> "debug": false,
> // Notification display: "off", "minimal", or "detailed"
> "pruneNotification": "detailed",
> // Notification type: "chat" (in-conversation) or "toast" (system toast)
> "pruneNotificationType": "chat",
> // Slash commands configuration
> "commands": {
> "enabled": true,
> // Additional tools to protect from pruning via commands (e.g., /dcp sweep)
> "protectedTools": [],
> },
> // Protect from pruning for <turns> message turns past tool invocation
> "turnProtection": {
> "enabled": false,
> "turns": 4,
> },
> // Protect file operations from pruning via glob patterns
> // Patterns match tool parameters.filePath (e.g. read/write/edit)
> "protectedFilePatterns": [],
> // LLM-driven context pruning tools
> "tools": {
> // Shared settings for all prune tools
> "settings": {
> // Nudge the LLM to use prune tools (every <nudgeFrequency> tool results)
> "nudgeEnabled": true,
> "nudgeFrequency": 10,
> // Token limit at which the model begins actively
> // compressing session context. Best kept around 40% of
> // the model's context window to stay in the "smart zone".
> // Set to "model" to use the model's full context window.
> "contextLimit": 100000,
> // Additional tools to protect from pruning
> "protectedTools": [],
> },
> // Distills key findings into preserved knowledge before removing raw content
> "distill": {
> // 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: "ask" (prompt), "allow" (no prompt), "deny" (tool not registered)
> "permission": "ask",
> // 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": {
> // Remove duplicate tool calls (same tool with same arguments)
> "deduplication": {
> "enabled": true,
> // Additional tools to protect from pruning
> "protectedTools": [],
> },
> // Prune write tool inputs when the file has been subsequently read
> "supersedeWrites": {
> "enabled": true,
> },
> // Prune tool inputs for errored tools after X turns
> "purgeErrors": {
> "enabled": true,
> // Number of turns before errored tool inputs are pruned
> "turns": 4,
> // Additional tools to protect from pruning
> "protectedTools": [],
> },
> },
> }
> ```
>
> </details>

### Commands

Expand All @@ -141,14 +167,10 @@ 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`.

### Turn Protection

When enabled, turn protection prevents tool outputs from being pruned for a configurable number of message turns. This gives the AI time to reference recent tool outputs before they become prunable. Applies to both `discard` and `extract` tools, as well as automatic strategies.

### Protected Tools

By default, these tools are always protected from pruning across all strategies:
`task`, `todowrite`, `todoread`, `discard`, `extract`, `batch`, `write`, `edit`
By default, these tools are always protected from pruning:
`task`, `todowrite`, `todoread`, `distill`, `compress`, `prune`, `batch`, `plan_enter`, `plan_exit`

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

Expand All @@ -166,4 +188,4 @@ Restart OpenCode after making config changes.

## License

MIT
AGPL-3.0-or-later
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
Loading