Thank you for your interest in contributing to Dynamic Context Pruning (DCP)!
This project uses the GNU Affero General Public License v3.0 (AGPL-3.0).
By submitting a Pull Request to this project, you agree that:
- Your contributions are licensed under the AGPL-3.0.
- 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.
- Fork the repository.
- Create a feature branch.
- Implement your changes and add tests if applicable (please NO AI SLOP).
- Ensure all tests pass and the code is formatted.
- Submit a Pull Request.
Use Node.js and npm. From your checkout:
npm ci --legacy-peer-deps
npm run buildThe install flag allows development against the different OpenTUI peer versions used by OpenCode V1 and V2. This also installs the bundled test logger's dependencies through the tests/logger npm workspace.
Run the checks relevant to your changes before submitting a pull request:
npm test # DCP and request-logger tests
npm run typecheck # TypeScript validation
npm run check:package # Build and validate the npm package
npm run format:check # FormattingDCP provides server and terminal integrations for OpenCode V1 and V2, using shared
package entrypoints and dcp.jsonc settings. Exercise both hosts when changing
shared behavior.
Use package.json for dependency requirements and the lab Dockerfile for pinned integration-test versions. Host-specific behavior is implemented in index.ts, tui.tsx, and lib/v2/.
V2 uses @4@ message IDs and @b1@ summary IDs. Compression inputs include the
whole marker; range summaries use @b1@ placeholders for nested summaries.
Message-mode priority labels look like @4@ [high]; @blocked@ marks content
that cannot be selected. V1 uses XML ID tags. Custom prompt overrides must describe
the ID format of the host they run on.
After building, add this checkout's absolute path to your OpenCode configuration.
For V2, use opencode.json:
For V1, add the following to both opencode.json (server plugin) and the
separate tui.json (panel):
{ "plugin": ["/absolute/path/to/opencode-dynamic-context-pruning"] }The sandbox requires Docker, Node/npm, and saved OpenCode authentication. The request logger is included in tests/logger; only the DCP checkout is needed. Complete Development Setup, then run:
npm run sandbox # OpenCode V2
npm run sandbox -- --v1 # OpenCode V1Each launch uses the latest stable OpenCode release for the selected major version,
rebuilds local DCP and the test logger, and prepares a clean Docker image. Run
npm run sandbox -- --help for available options and defaults. Each launch copies
all saved authentication from the matching host version: V1's auth.json, or V2's
credential records and account selections. OpenCode handles provider authentication
normally inside the container; copied credentials can be refreshed there without
writing back to the host.
V1's auth file is under $XDG_DATA_HOME/opencode (normally
~/.local/share/opencode). V2's database is located with opencode2 debug paths db,
or the standard data directory when that command is unavailable. Set DCP_AUTH_PATH
to select a different V1 auth file or V2 database. Credentials embedded in host
configuration or environment variables are not copied. Custom provider definitions
can be added to opencode.json in the sandbox's scratch workspace.
The sandbox has its own sessions, scratch workspace, and configuration under
~/.local/state/dcp-sandbox/. V1 uses the v1/ subdirectory, with a separate
database. Your host project and normal OpenCode configuration are not mounted.
Try /dcp for the panel or /dcp-compress for a compression pass.
npm run sandbox -- --fresh # New profile; keep old runs
npm run sandbox -- --logs # Latest log paths and capture counts
npm run sandbox -- --path # Current profile's host directory
npm run sandbox -- -- --continue # Resume a session
npm run sandbox -- --opencode VERSION # Use an exact release for this launch
npm run sandbox -- --dcp latest --fresh # Test the published npm DCP in a new profile
npm run sandbox -- --dcp 3.2.0 # Test a specific npm DCP release
npm run sandbox -- --transport http # Select V2's transport
npm run sandbox -- --model PROVIDER/MODEL # Select a model available to your accountReplace VERSION, PROVIDER, and MODEL with the release and model you want to test.
Without a saved model choice, OpenCode selects its default. A V2 transport override
applies to the selected model.
Add --v1 to manage the V1 sandbox. Model and transport choices persist.
An exact version override applies only to that launch; otherwise the latest stable
release is selected. --fresh selects a new profile for subsequent launches.
--dcp VERSION uses @tarquinen/opencode-dcp@VERSION through OpenCode's npm plugin
loader instead of building local DCP. It accepts npm versions, tags, and ranges on
both V1 and V2. The test logger is still built locally. The DCP choice applies only
to that launch; omit it or use --dcp local to return to the checkout.
You can edit dcp.jsonc and CLI preferences; opencode.json is launcher-managed.
Set DCP_SANDBOX_DIR to choose another state directory.
For a shortcut on Linux, run from the checkout:
mkdir -p ~/.local/bin
ln -s "$PWD/scripts/sandbox.mjs" ~/.local/bin/dcp-sandbox
dcp-sandboxThe logger is development-only tooling and is excluded from DCP's published npm
package. Each launch has raw/ and readable/ directories under its timestamped log folder.
The launcher manages the WebSocket relay and readable-log watcher. Requests appear
as they are sent; assembled responses appear when they finish, while the session
stays open. --logs only shows paths and capture counts.
Start at readable/index.json, then a session's numbered request folders:
readable/<session>/0001_primary_websocket/
request.json # Pretty-printed body actually sent
response.json # Assistant content, parsed tool calls, token totals, errors
meta.json # Timing, completion, transport, raw source, continuation ID
V2's full pre-transport snapshots are in each session's context/ directory.
WebSocket continuation requests remain deltas with previous_response_id.
Partial and failed responses are marked in metadata. Full provider metadata,
original HTTP bytes, and WebSocket frames remain available in raw/.
The containerized lab exercises packed plugins on V1 and V2, including saved-auth copying, HTTP and WebSocket compression, commands, permissions, concurrent sessions, persistence, and native compaction. It uses a local mock provider without live credentials.
After Development Setup, build tests/lab/Dockerfile using the image tag expected by scripts/lab.mjs, then run:
node scripts/lab.mjsThe runner prints its output directory under /tmp/opencode/dcp-lab/. Set
DCP_LAB_DIR to override it. Add --built to reuse an existing DCP build.
For real-provider checks, node scripts/lab.mjs --live uses the current build and
saved V2 authentication. Its OpenAI Responses scenarios require access to the model
configured in tests/lab/live.mjs.
Inspect capture summaries without opening large transcripts:
node tests/lab/inspect.mjs <log-directory>Terminal-panel checks require uv and reuse a completed lab run:
uv run --with pexpect --with pyte tests/lab/ui.py <lab-output-directory> v2
uv run --with pexpect --with pyte tests/lab/ui.py <lab-output-directory> v1These check the panel, Context, Stats, persisted manual-mode toggle, and closing the dialog. They also check mouse-wheel scrolling and resizing down to 20 rows, with back/close buttons remaining visible. Terminal transcripts and screen snapshots are saved in the lab output.
To check another V2 release, build the lab image with --build-arg V2=VERSION
and pass that image's tag as the final argument to ui.py. Use a separate copy of
the lab output when testing different releases so their databases stay independent.
{ "plugins": [{ "package": "/absolute/path/to/opencode-dynamic-context-pruning" }], "permissions": [{ "action": "compress", "resource": "*", "effect": "allow" }], }