OpenCode V2 plugin: bootstrap is injected on the 'context' hook only, so every compaction request misses the prompt cache
- I searched existing issues and this is not a duplicate (closest: #2306, the V2 port that added the
contexthook)
Environment (required)
| Field | Value |
|---|---|
| Superpowers version | 6.4.2 (github:obra/superpowers, .opencode/plugins/superpowers.js) |
| Harness (Claude Code, Cursor, etc.) | OpenCode 2 (V2 plugin API) |
| Harness version | 2.0.18 |
| Your model + version | Qwen3.8-Flash-Next (local, mlx-serve 26.9.6, OpenAI-compatible provider). Report written by Claude Opus 5.5 in Claude Code from the server log and the OpenCode session database. |
| All plugins installed | superpowers; one local plugin that only sets sampling / reasoning-effort fields on the request body |
| OS + shell | macOS (host), OpenCode in a Debian container, sh |
Is this a Superpowers issue or a platform issue?
- I confirmed this issue does not occur without Superpowers installed
Not tested by uninstalling. Superpowers is what makes the two requests differ: the prompts match up to the end of system + tools, which is where the bootstrap goes, and registering the same handler on compaction makes them match up to the tail (numbers below).
What happened?
The OpenCode V2 plugin registers its bootstrap injection only on ctx.session.hook('context', ...). OpenCode 2 builds the compaction (summary) request through a separate hook, compaction. OpenCode's own built-in plugins register the same handler on context, compaction and generate.
So the compaction request's first user message lacks the bootstrap that every normal turn had. The prompt diverges right after system + tools, and on any backend with prefix caching the whole session is re-prefilled cold at every compaction. That usually means a 150-200k-token prompt, which is exactly when a cold prefill is most expensive. For hosted models this is a cache miss on the largest request of the session; for local models it is minutes.
Steps to reproduce
- OpenCode 2.0.18 + superpowers 6.4.2, any provider whose server reports prefix-cache hits (e.g. llama.cpp / mlx-serve logs).
- Work a session until auto-compaction fires.
- Compare the compaction request's cached-token count with the previous normal turn's.
Expected behavior
The compaction request reuses the cached prefix up to where it diverges near the tail.
Actual behavior
Same session, same server, 2026-09-26:
| user-text bytes | cached / prompt tokens | prefill | |
|---|---|---|---|
| last normal turn | 64,784 B | (warm) | |
| compaction request, unpatched | 63,314 B (~1.5 KB less: the bootstrap) | 8,192 / 199,112 (= system + tools only) | 510 s |
| compaction request, patched as below | 176,687 / 177,402 | 13.7 s (SSD restore) |
An earlier compaction the same day showed the same thing: 8,909 / 201,332 matched, 536 s.
Fix
Register the existing handler on both hooks, as OpenCode's built-ins do:
const bootstrapHook = async (event) => { /* existing body, unchanged */ };
await ctx.session.hook('context', bootstrapHook);
await ctx.session.hook('compaction', bootstrapHook);The existing body already copes with a compaction-shaped event (it skips when the bootstrap is present and appends a user message when there is none). We have run this patch locally since 2026-09-26; the measurement above is with it.
Debug log or conversation transcript
Server log excerpt (mlx-serve), unpatched compaction:
POST /v1/chat/completions (247 msgs, ..., sys=22099b, user=63314b, tools=13164b, tool_msgs=115)
> "You MUST summarize the conversation above into a structured summary that will be..."
prompt=199112 tokens
[hot-cache] reused 8192/199112 tokens (matched 8999; entry 4/4)
<- 199112+5310 tokens streamed [prefill: 374.6 tok/s (8192 cached / 199112 total), decode: 66.1 tok/s] [stop]Patched:
> "Update the existing checkpoint in the conversation above into one consolidate..."
prompt=177402 tokens
[disk-cache] restored 176687/177402 tokens from SSD in 13709ms (ssm@176687)
<- 177402+6901 tokens streamed [prefill: 38.3 tok/s (176687 cached / 177402 total), decode: 49.1 tok/s] [stop]Source: obra/superpowers