Repository navigation
v1.0.0
OpenCode Cache Engine release v1.0.0
Dual-runtime release — one package, native support for OpenCode V1 and the OpenCode V2 adapter.
I'm proud to announce the release of the first stable milestone of the project!
After the v0.5.x provider line and the v0.6.0 shared-core consolidation, v1.0.0 ships a single npm package that loads on both OpenCode runtimes, keeps the mature V1 behavior intact, and adds a preview V2 adapter that reuses the same policy resolver and usage/accounting core.
Highlights
- One package, two runtimes:
opencode-cache-enginenow registers cleanly on OpenCode V1 (1.18.35) and OpenCode V2 (2.0.26) by package name — verified end-to-end in isolated runtimes. - Dual default entry:
./serverexposes both the V1Pluginand a V2-compatible default object, with a lazy V2 import so V1 never initializes V2 code. - New
./v2export — the OpenCode V2 adapter (preview). - Provider-aware cache stability across 11 model families (10 shipped + neutral fallback), with the shared core extracted for reuse.
- 335 tests, 0 failures.
V2 compatibility:
This is the first release with full V2 compatibility.
The dual-entry model
./server (src/cache-engine.ts) now provides:
- the named
CacheEngine(the V1Plugin), and - a default object
{ id, server: CacheEngine, setup(ctx) }, whosesetuplazilyimport("./cache-engine-v2.mjs")and delegates.
V1 selects server(input, options); V2 selects setup(ctx). Package exports: ./server → src/cache-engine.ts, ./tui → src/tui.mjs, ./v2 → src/cache-engine-v2.mjs.
Verified loading (isolated, by package name)
- V1 1.18.35 —
opencode plugin -g opencode-cache-engine(writesplugin:["opencode-cache-engine"]) → run executed V1 hooks and emitted V1 telemetry (policy-resolution,prefix-observation,prefix-change,usage), 0 V2-only signals. - V2 2.0.26 —
opencode plugin add opencode-cache-engine(writesplugins:["opencode-cache-engine"]) → run loggedloading plugin id=opencode-cache-engine entrypoint=…/src/cache-engine.tsand the V2 adapter produced telemetry.
Important: install by name
- Recommended:
opencode-cache-engine(bare name). - Do not pass a subpath (
opencode-cache-engine/v2): the loader reads it as an npm/Git spec and the install fails.
Preview caveats (please read)
- Managed-config discovery/registration of
./v2remains unverified beyond the isolated shim/name-based tests (project-local shim and by-name install verified). - GPT cache-key wire carriage — NOT PASS (Gate 4). The adapter mutates the request as designed, but on the tested routes the field could not be attributed to the adapter (the OpenAI-compatible schema strips it; the OpenAI/Azure route is independently pre-populated by the harness).
- OpenRouter header attribution — unverified. Evidence shows preservation/fallback, not that the adapter attached the header in the integration path.
- Usage accounting is best-effort, never exactly-once (volatile events, in-memory cursor, compaction truncation, eviction/mark-expiry edge cases).
Changes
V1 runtime (mature, unchanged behavior)
- Hooks:
chat.headers,chat.params,experimental.chat.system.transform,experimental.session.compacting, and friendliereventaggregation onsession.idle. - Provider policies: passive by default, with narrowly scoped, evidence-backed interventions only where a documented benefit exists:
- GPT‑5.6+ — inject only missing
promptCacheKey/promptCacheOptions(implicit, 30m). - GLM‑5.3 / MiMo‑V2.6 — the single prompt-text transform: content-preserving relocation of the identifiable
<env>block. - OpenRouter affinity — deterministic
x-session-idfor GLM/MiMo only, preserving any existing header. - Everything else (DeepSeek, Kimi, Claude, Gemini, Qwen, Grok, Meta Muse, MiniMax) stays loopback-passive and observes provider-reported usage.
- GPT‑5.6+ — inject only missing
V2 runtime (preview adapter)
./v2→src/cache-engine-v2.mjs: a plain{ id, setup(ctx) }plugin that reuses the shared policy resolver and usage/accounting core.- Hooks:
context— GPT‑5.6+ missing-field cache key/options; GLM/MiMo structural<env>relocation (now multi-part-aware; it relocates exactly the single eligible system text part and leaves every other part untouched).model.request— OpenRouterx-session-idaffinity (guarded; it never duplicates a pre-existing session header).- Usage —
session.usage.updated(primary) andsession.idle(secondary) drive the shared history scan viasession.context({ sessionID }), with a bounded per-session model (LRU cap + tombstones + evicted marks), cancellation, and fail-safe error handling.
Verification & evidence
- Unit tests:
335 pass / 0 fail(Node's built-in runner). - Package:
npm pack→ 9 files, includessrc/cache-engine-v2.mjs(~21 kB). - Isolated live load test (this release):
- Tarball
opencode-cache-engine-0.7.1.tgzsha2564103ecb214d4f36c97707160de522f7f94d32ce1dd8566fb3974cc16eb176fa9. - Installed
src/cache-engine.tssha256c449b2655a98362c156c14905ffa636e9ece5d0a4500243e88863390aa727d9e(matched the tarball). - V1 1.18.35 and V2 2.0.26 both installed by name from a disposable local registry and loaded/executed the plugin; no real provider traffic.
- Tarball
- Isolation: all tests ran in
bubblewrap --unshare-netwith private HOME/XDG; the host managed service was never touched.
Detailed changes
Feature diff vs master@34ce537: 10 files, +3473 / −71.
| File | Change |
|---|---|
src/cache-engine.ts |
+36 — dual V1/V2 default entry (lazy V2 import) |
src/cache-engine-v2.mjs |
new (~505) — V2 adapter |
src/cache-engine-core.mjs |
+73 — structural <env> eligibility (Platform: required), marker-after-<env> no-op, precise separator-newline contract |
test/cache-engine.test.mjs |
+1255 — cross-version entry, V2 fault-injection, multi-part relocation, L1/L2, C1 separator regression |
package.json |
adds ./v2 export; version → 1.0.0 |
docs/research-findings.md |
+913 — RF-OC-017…034 (V2 API/hook/event/usage, loader/CLI, <env> compatibility, separator contract) |
docs/implementation-plan-v2.md |
+462 — V2 readiness §2B–§2D, Gate 0–4 results, limitations, closure |
docs/cache-policy-inventory.md |
+6 — GLM/MiMo V2 relocation-compatibility note |
README.md |
compatibility, installation, quick install (both runtimes), rollback |
AGENTS.md |
+73 — V2/roadmap guidance |
Key commits on the way to 1.0.0: cross-version tests (ac720c5); structural <env> core fix (7b085c6, 4ed1a8f, 36323e7); multi-part V2 relocation (e36d513); V2 surface fault-injection tests (ce31caf); dual entry (947bbdd); C1 clarification (2ab2423, af154f0); docs (8f230c8, 1f0d8b8, 9b6bf56, 0ed32bd, de169fb); merge (0336957); version bump (fc6f6fc); README quick install (b301668).
Known limitations (explicit)
- The V2 adapter is preview, not production: managed-config registration is unproven; GPT wire carriage and OpenRouter header attribution are unresolved; compaction isolation, fork cache-root, and the secondary V1 diagnostics are not ported.
- No exactly-once accounting. Usage is best-effort and can undercount (volatile events, restarts, compaction, eviction); expired marks can recount.
- Loader behavior is version-specific (V1 default-object
serverselection; V2 ignoring the extraserverkey) — verified on 1.18.35 / 2.0.26; other versions are not asserted.
Not in this release
No public npm publish or git tag are performed here (the maintainer handles tagging/publishing; postpublish will create and push the v1.0.0 tag). The feature/v2-adapter-checkpoint branch remains available at its pre-merge tip.
Full Changelog: v0.7.1...v1.0.0
Thank you to everyone for using the plugin and helping make this project successful!
Provider-aware prompt-cache optimization and observability for OpenCode.
opencode-cache-engine is an OpenCode npm plugin that exposes three targets required by OpenCode's installed plugin model:
./server— the V1 CacheEngine runtime, hooks, provider policies, and telemetry (verified on OpenCode 1.x)../tui— plugin-manager registration and enable/disable integration; it
has no CacheEngine-specific UI../v2— the OpenCode V2 adapter (preview): implemented and
offline-tested; isolated shim-based loading,setup, and hook
registration/dispatch are verified in an isolated OpenCode 2.0.26 runtime,
but managed-config discovery/registration remain unverified (and the direct
plugins: ["opencode-cache-engine/v2"]entry did not resolve in the tested
offline configuration)
CacheEngine is an OpenCode plugin designed for long-running agent sessions where prompt-cache efficiency affects both latency and cost. It keeps the harness conservative for providers whose cache behavior is already automatic, while applying provider-specific optimizations where the provider exposes useful cache controls or where prompt structure can be safely improved.
The plugin currently has eleven cache-policy families:
- DeepSeek — passive cache observability; request structure is preserved.
- GPT-5.6 and later — documented cache-key/options metadata, with prompt text unchanged. GPT-6 and future 5.6+/6+/7+ versions resolve through the same documented boundary.
- GLM-5.3 and later — GLM implicit-cache baseline and diagnostics; GLM-5.3 additionally uses a narrow, content-preserving
<env>relocation overlay. - MiMo V2.6 and later — MiMo implicit-cache baseline and diagnostics; MiMo V2.6 Flash/Pro additionally use a narrow content-preserving
<env>relocation overlay. - Kimi — passive Moonshot/Kimi implicit-cache observability; the request is left unchanged. The Anthropic-compatible
cache_controlroute is not implemented. - Claude (Anthropic) — passive classification and accounting; the request is left unchanged because OpenCode itself applies Anthropic
cache_controlbreakpoints. - Google Gemini — passive classification and accounting; Gemini 2.5+ provider-managed implicit caching is left untouched. CacheEngine creates no
CachedContentresources and injects no Gemini cache-control field. - Alibaba Qwen — passive classification and accounting; Qwen's provider-managed implicit caching is left untouched on every route. CacheEngine places no explicit block-level cache_control marker and adds no affinity, because the V1 hook cannot reach message content blocks and OpenCode already applies breakpoints on the Qwen Messages routes.
- xAI Grok — passive classification and accounting. Grok caching is automatic on all Grok language models, and direct xAI already receives a stable conversation affinity key from OpenCode itself, so CacheEngine injects no header or key and rewrites nothing.
- Meta Muse — passive classification and accounting. Muse caching is automatic positional prefix caching; Meta's
prompt_cache_keymust be an application-stable routing hint (never per-session) andprompt_cache_retentionis a request-level policy, so CacheEngine injects neither and rewrites nothing. - MiniMax — passive classification and accounting, route-aware. MiniMax caching is automatic; M2.x additionally supports explicit Anthropic
cache_control(M3 does not), but OpenCode already owns those breakpoints on the Anthropic-compatible routes, so CacheEngine injects nothing.
Initial models were personally chosen for their performance in max programming task completed per dollar. More models can be added based on newer releases or updates.
Future releases will be based on newer versions of models from the above providers, as well as any model that performs optimally over the Pareto distribution on OpenRouter as well as on personal discretion. Since cache stability policy doesn't change much for the providers, there's no need for a code rebase.
Installation
V1 (stable):
opencode plugin opencode-cache-engine # TUI/CLI installer
or set config:
"plugin": ["opencode-cache-engine"]
V2 (preview):
opencode plugin add opencode-cache-engine # TUI/CLI installer
or set config:
"plugins": ["opencode-cache-engine"]
Both install the package by name, and each runtime selects the interface it supports from the package's ./server export (V1 → server, V2 → setup). Do not pass opencode-cache-engine/v2 as the package specifier; use the bare name.
Best complemented with agents for the particular models configured at AlexJoaquimPereira/opencode-agent-config