opencode-clm 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,7 +3,7 @@
3
3
  From 0.1.1 on, release notes are generated by git-cliff from Conventional Commits and
4
4
  published on [GitHub Releases](https://github.com/bcmyguest/opencode-clm/releases).
5
5
 
6
- ## 0.1.0 (unreleased)
6
+ ## 0.1.0
7
7
 
8
8
  First release: Context Language Model mode for OpenCode 1.18, ported from pi-clm 1.0.0.
9
9
 
package/NOTICE CHANGED
@@ -23,10 +23,18 @@ Derived from pi-clm (code and model-facing text, adapted for OpenCode):
23
23
  src/types.ts src/types.ts
24
24
  steering/house-brief.md steering/house-brief.md (byte-identical copy)
25
25
  skills/clm-context/SKILL.md src/skills/live-context/SKILL.md
26
+ src/panel/timeline.ts src/timeline.ts (context chart and its zoom levels)
27
+ src/panel/diff.ts src/diff.ts (side-by-side diff)
28
+ src/panel/view.ts src/viewer.ts (panel pages)
29
+ src/panel/keys.ts src/viewer.ts (key handling)
30
+ src/panel/model.ts src/viewer.ts (revision view model)
31
+ src/panel/command.ts src/index.ts (/clm and /clm config parsing)
26
32
 
27
33
  Written for this package (structure follows pi-clm, text does not):
28
34
  src/presentation.ts (system-prompt protocol section and /clm status text),
29
- src/policy.ts (edit gate and its refusal note), src/opencode.ts.
35
+ src/policy.ts (edit gate and its refusal note), src/opencode.ts, and the OpenCode TUI
36
+ adapter (tui.ts, src/tui/*, src/panel/lines.ts, src/panel/files.ts,
37
+ src/session-files.ts).
30
38
 
31
39
  Context Language Models
32
40
  Paper: arXiv 2609.37725. Research code:
package/README.md CHANGED
@@ -1,318 +1,131 @@
1
1
  # opencode-clm
2
2
 
3
- An [OpenCode](https://opencode.ai) plugin that runs a model as a Context Language Model
4
- (CLM): the model edits a text mirror of its own conversation, and the edited mirror
5
- becomes its input on the next request. OpenCode's stored session stays unchanged.
3
+ [![npm](https://img.shields.io/npm/v/opencode-clm)](https://www.npmjs.com/package/opencode-clm)
4
+ [![CI](https://github.com/bcmyguest/opencode-clm/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/bcmyguest/opencode-clm/actions/workflows/ci.yml)
6
5
 
7
- It ports [pi-clm](https://github.com/lolipopshock/pi-clm) 1.0.0, the Pi extension that
8
- accompanies the CLM paper ([arXiv 2609.37725](https://arxiv.org/abs/2609.37725)).
9
- [PORTING.md](PORTING.md) maps each pi-clm file to its counterpart here.
10
-
11
- ## Install
12
-
13
- Tested with OpenCode 1.18.34.
14
-
15
- From npm, once published, in `opencode.json`:
16
-
17
- ```json
18
- { "plugin": ["opencode-clm"] }
19
6
  ```
20
-
21
- From a local clone:
22
-
23
- ```json
24
- { "plugin": ["file:///path/to/opencode-clm/index.ts"] }
7
+ ____ _ __ __
8
+ / ___| | | \/ |
9
+ | | | | | |\/| |
10
+ | |___| |___| | | |
11
+ \____|_____|_| |_|
12
+
13
+ opencode-clm
14
+ the agent that manages its own context
25
15
  ```
26
16
 
27
- ## Configuration
17
+ `opencode-clm` is an [OpenCode](https://opencode.ai) plugin that lets the agent manage its
18
+ own context: before each request the plugin writes the conversation to a file, the
19
+ language model edits that file with its ordinary tools, and the edited version becomes its
20
+ next input. OpenCode's stored session stays unchanged. It ports
21
+ [pi-clm](https://github.com/lolipopshock/pi-clm), the Pi extension for the paper
22
+ [Context Language Models](https://arxiv.org/pdf/2609.37725) and its [research
23
+ codebase](https://github.com/facebookresearch/context-language-models).
28
24
 
29
- Pass options as the second element of a plugin tuple:
25
+ ## Install
30
26
 
31
- ```json
32
- { "plugin": [["opencode-clm", { "budget": "64k", "gate": "shrink" }]] }
27
+ ```sh
28
+ opencode plugin opencode-clm # this project: .opencode/opencode.json and .opencode/tui.json
29
+ opencode plugin -g opencode-clm # global: opencode.json(c) and tui.json in ~/.config/opencode
33
30
  ```
34
31
 
35
- Each option falls back to its environment variable, then to the default. The plugin reads
36
- them once at load; an invalid value fails the plugin load with an error that names the
37
- option.
38
-
39
- | option | env | default | values |
40
- |---|---|---|---|
41
- | `enabled` | `CLM_ENABLED` | `true` | `false` registers no hooks |
42
- | `budget` | `CLM_BUDGET` | `32000` | tokens (`32000`, `32k`, `1.5m`, `32_000`), or `window` for the model's context window. The model window minus its output limit caps the value |
43
- | `reserve` | `CLM_RESERVE` | `2048` | tokens held back below the budget for generation |
44
- | `remindAt` | `CLM_REMIND_AT` | `0.25,0.5,0.75` | fractions (`0.25,0.5`) or percentages (`25/50%`) strictly between 0 and 1; `off` disables all reminders, the budget − reserve reminder included |
45
- | `gate` | `CLM_EDIT_GATE` | `fit` | `fit`, `shrink` or `none` |
46
- | `guard` | `CLM_OVERFLOW` | `withhold` | `withhold` or `off` |
47
- | `observationCap` | `CLM_OBSERVATION_CAP` | off | `characters[:head fraction]`, e.g. `10000:0.5`; at least 200; head fraction defaults to 0.8; `off` or `0` disables |
48
- | `mirrorDir` | `CLM_MIRROR_DIR` | `<project>/.opencode/clm` | parent of the per-session directories; relative paths resolve against the project |
49
- | `steering` | `CLM_STEERING` | none | path to a steering document, or `house` for the bundled `steering/house-brief.md`; `none` or `off` disables |
50
- | `compactPrompt` | `CLM_COMPACT_PROMPT` | built-in | path to a `/clm-compact` template; `default`, `none` or `off` mean the built-in prompt |
51
- | `estimateFactor` | `CLM_ESTIMATE_FACTOR` | `1` | 1 to 4; multiplies the chars/4 token estimate (1.5–2 for dense content) |
52
- | `reasoning` | `CLM_REASONING` | `true` | render assistant reasoning in the mirror |
53
- | `dumpRequests` | `CLM_DUMP_REQUESTS` | `false` | write each transformed request to `<session dir>/requests/nN.json` |
54
- | `skill` | — | `true` | register the `clm-context` skill; `false` matches pi-clm's CLM mode, which offers no skill |
55
- | `commands` | — | `true` | register `/clm` and `/clm-compact` |
56
-
57
- Booleans accept `true/false`, `1/0`, `on/off` and `yes/no`.
58
-
59
- **Choosing `budget`.** The budget counts the whole request, OpenCode's system prompt and
60
- tool schemas included. With OpenCode 1.18 and its default tools those take about 17,000
61
- to 19,000 tokens of every request (measured with provider counts), before the
62
- conversation starts. A budget must hold that overhead, the `reserve`, and a working margin
63
- for the conversation; the plugin uses 8,000 tokens, room for the task, a few tool results
64
- and edits. With the default reserve that gives a minimum of about 19,000 + 2,048 + 8,000 ≈
65
- 29,000 tokens; the default 32,000 clears it. More tools (MCP servers, plugins) or a
66
- steering document raise the overhead.
67
-
68
- When the budget is smaller, the session raises it. On the first request that follows a
69
- measured reply, the plugin takes the provider's input count minus its own conversation
70
- estimate as the fixed overhead. It measures only while the conversation is at most a
71
- quarter of that count, so the estimate's error stays small; a session resumed with a long
72
- history is measured once its context is short. If the provider reports no usage, the
73
- plugin's own size estimate stands in until a provider count arrives. If budget − reserve
74
- leaves less than 8,000 tokens after the overhead, the effective budget becomes overhead +
75
- 8,000 + reserve, never above the model window minus its output limit (uncapped while the
76
- window is unknown). The plugin then logs a `budget-too-small` event, shows a warning
77
- toast, and tells the model once. When the window cap leaves less than the margin, the
78
- notice says so; lower `reserve` or use a model with a larger window. The overhead is
79
- stored in `state.json`, so the raise holds after a restart, and it is measured once per
80
- session: switching agent or model, or adding an MCP server, later does not update it.
81
- `/clm` shows the fixed overhead, the usable budget (budget − reserve − overhead) and the
82
- effective budget when raised.
83
-
84
- A steering document carries context-management strategy (when to compact, what to keep);
85
- the plugin itself states only the editing protocol. The plugin reads the document once at
86
- load and appends it to the system prompt; `/clm` shows its name and SHA-256 prefix.
87
-
88
- A `compactPrompt` template may use `{{mirror}}`, `{{current}}`, `{{budget}}` and
89
- `{{instructions}}`. The plugin rereads it on every use.
90
-
91
- ## Commands
92
-
93
- - `/clm [status | path | on | off | reset]`: `status` (the default) prints the session's
94
- mirror path, revision, accepted and rejected edits, gate, guard, budget reading and
95
- active revision, and shows a toast. `path` prints the mirror path. `on` and `off` switch
96
- CLM for the session. `reset` drops the accepted revision, so the next request carries
97
- the stored history. The command costs one model turn: OpenCode cannot cancel a command,
98
- so the model receives the text and repeats it.
99
- - `/clm-compact [instructions]`: asks the model to compact its context now by editing the
100
- mirror. Text after the command is appended to the prompt.
101
-
102
- If your config already defines `clm` or `clm-compact`, the plugin keeps your command,
103
- logs a warning and leaves it alone. A failing command prints `[CLM] /<name> failed:
104
- <reason>` and shows an error toast.
105
-
106
- ## Tools
107
-
108
- - `clm_annotate`: `action` is `create`, `resolve` or `list`. `create` takes a mirror block
109
- id (`source`), `title`, `reason`, `futureAction` and `retention`:
110
- - `pin` keeps the exact source text in every request (up to 8,000 tokens);
111
- - `continuity` keeps the title, reason, next action and recall id in every request;
112
- - `archive` keeps nothing in the request; the source is available through recall.
113
- - `clm_recall`: returns an annotation's saved source; `maxTokens` 128–8,000, default 2,000.
114
-
115
- ## Skill
116
-
117
- `skills/clm-context/SKILL.md`, adapted from pi-clm's `live-context` skill, tells the model
118
- when and how to edit the mirror: batched surgical edits, keeping conversational units
119
- together, durable summaries, and Python scripts that list headers and replace or remove
120
- blocks by id. The plugin adds the `skills` directory to OpenCode's `skills.paths`.
121
-
122
- ## How it works
123
-
124
- **Mirror.** Before each model request, the plugin writes every message after the first
125
- user message to `LIVE_CONTEXT.md` in the session directory. Line 1 is a `[[LIVE_CONTEXT
126
- ...]]` header with the revision and document id; each message follows as a block headed
127
- `[[CTX_TURN document=<id> index=<n> role=<role> id=<block id> protected=<bool>]]`. The
128
- system prompt and the first user message stay outside the mirror and are always sent. A
129
- system-prompt section, `## Editable context`, teaches the model the format.
130
-
131
- **Editing.** The model edits the mirror with the bash tool (python3, `sed -i`). The edit
132
- and write tools keep a copy that goes stale when the plugin regenerates the file, so the
133
- protocol tells the model to avoid them on the mirror. Deleting a block drops the message.
134
- New text under a tool result replaces its output and keeps the call. New text under an
135
- assistant header replaces the reply and turns its tool results into notes. A header copied
136
- with `id=new-NAME` inserts a note. Replacing the whole file with text that has no block
137
- headers replaces everything after the first user message with one notes block. When a
138
- bash, edit, write or apply_patch call writes the mirror, the plugin appends a verdict to
139
- its output (accepted, or the reason for refusal); a heuristic detects bash writes. A
140
- `[CLM]` note on the next request reports what was applied.
141
-
142
- **Commit.** OpenCode has no end-of-turn hook, so the plugin reads the mirror at the start
143
- of the next request. If the file differs from the last render, the plugin parses it and
144
- applies it. It refuses a file whose line 1 no longer parses or names another document, a
145
- file with duplicate or unknown block ids, and a file the edit gate rejects; the context
146
- then stays as it was.
147
-
148
- **Edit gate.** Every gate accepts an edit that keeps the context the same size or smaller.
149
- For growth: `fit` accepts it while the editable context stays within budget − reserve
150
- minus the system prompt, tool schemas, pinned text and continuity notes, and accepts everything while the budget is
151
- unknown; `shrink` rejects it; `none` applies no size check.
32
+ The package holds two plugins: the server plugin (`index.ts`: mirror, edits, budget,
33
+ `/clm`, `/clm-compact`) and the TUI plugin (`tui.ts`: the `/clm` panel). `opencode plugin`
34
+ writes the spec to both files. By hand, add it to both `plugin` lists; options go on the
35
+ `opencode.json` entry only, and the TUI plugin reads them from there:
152
36
 
153
- **Projection checkpoints.** An accepted edit becomes a revision. The checkpoint stores the
154
- number of flattened raw messages it replaces, their OpenCode message ids, and a SHA-256
155
- digest of them, with tool-result content excluded so OpenCode's prune does not invalidate
156
- it. A pruned tool output inside an accepted revision goes out with the revision's text.
157
- Each later request sends the projected messages plus the raw messages added since.
158
- When the stored prefix no longer matches (a revert, for example), the plugin drops the
159
- revision, sends the raw history, and tells the model. Compaction is the exception (see
160
- Compaction).
161
-
162
- **Budget tiers.** Token estimates are chars/4 × `estimateFactor` × a calibration factor
163
- learned from the provider's reported input sizes (never below 1). The estimate covers the
164
- system prompt, tool schemas, pinned task, editable context, continuity text and notices.
165
- Until a size is known, the `[CLM BUDGET]` note names what the estimate leaves out. Reminders fire once per tier, as `[CLM BUDGET]` notes, at each
166
- `remindAt` fraction and at budget − reserve. Requests are never blocked.
167
-
168
- **Observation cap.** When set, each tool result in the sent context keeps at most
169
- `characters` characters (the head fraction from the start, the rest from the end) plus a
170
- marker stating how much was cut. The stored output stays complete.
171
-
172
- **Overflow guard.** When the estimated request exceeds budget − reserve, the guard
173
- replaces new tool results, oldest first, with a note naming the tool, call id, size and a
174
- file in `withheld/` that holds the full output (or, if saving fails, a pointer to the
175
- session history), until the estimate fits. User and
176
- assistant messages stay untouched, and no tool runs again. `guard: "off"` disables it.
177
-
178
- **Continuity.** Annotations (see Tools) let the model shorten or delete a block while a
179
- pin, a continuity note or a recall copy keeps what later work needs. The plugin sends
180
- active annotations as a user-role note after the conversation, and warns the model when they exceed
181
- 8,000 tokens.
182
-
183
- **Compaction.** CLM replaces compaction: the model shrinks its own context by editing the
184
- mirror. Set `"compaction": { "auto": false }` in `opencode.json` while CLM is on, and keep
185
- auto-compaction only as a fallback for a session that outgrows the window anyway.
186
-
187
- When OpenCode compacts:
188
- 1. The plugin applies the accepted revision to the history OpenCode summarizes, so the
189
- summary reflects the edited context. It makes no commit or render.
190
- 2. It appends an instruction to the compaction prompt: copy every pin and continuity
191
- annotation, listed after it, into the summary verbatim.
192
- 3. When a revision is active and OpenCode reports the finished compaction (the `session.compacted` event or the
193
- `experimental.compaction.autocontinue` hook), the next request rebases: the summary
194
- becomes the new baseline, the revision number moves on, and the model gets no
195
- dropped-revision note. Pins and continuity annotations carry over unchanged, and
196
- `events.jsonl` records a `compacted` event.
197
-
198
- OpenCode's title, summary and compaction agents get no protocol text.
199
-
200
- ## State
201
-
202
- Each session has a directory `<mirrorDir>/clm-<session id>/` (mode 0700; files 0600):
203
-
204
- | file | content |
205
- |---|---|
206
- | `LIVE_CONTEXT.md` | the mirror |
207
- | `state.json` | enabled flag, revision, active checkpoint, measured fixed overhead and budget decision |
208
- | `annotations.jsonl` | continuity annotations |
209
- | `events.jsonl` | one line per request, edit, reset, notice and error |
210
- | `revisions/rN.md` | the mirror text of each accepted revision |
211
- | `withheld/` | tool outputs held back by the overflow guard |
212
- | `requests/nN.json` | transformed requests, with `dumpRequests` only |
213
-
214
- The plugin deletes session directories untouched for 7 days when it opens another
215
- session. The default `mirrorDir` lies inside the project; add `.opencode/clm/` to
216
- `.gitignore`.
217
-
218
- ## Limitations
219
-
220
- - Status, budget and edit outcomes appear as text, toasts and `events.jsonl`. pi-clm's
221
- TUI viewer, timeline and diff are not ported: OpenCode server plugins cannot draw panels.
222
- - No per-session settings panel; `/clm on|off|reset` are the only per-session switches.
223
- - Model limits and the system-prompt size reach the plugin one request late. On the
224
- first request of a process the model window does not yet cap the budget and the
225
- estimate omits the system prompt; with `budget: "window"` that request has no budget
226
- reading. `/clm-compact` before the first request reports about 0 tokens.
227
- - Built-in tool descriptions are measured, but not their parameter schemas, so
228
- calibration attributes that size to undercounting.
229
- - A checkpoint ignores changes to stored tool output inside the prefix it covers. An
230
- output rewritten by another plugin or an SDK client goes out with the new text, while
231
- the mirror and estimate keep the revision's.
232
- - Hooks fail open: if the transform throws, the request goes out with the raw history and
233
- an error toast.
234
- - The calibration factor lives in memory and restarts at 1 with each process.
235
- - A subagent (task) session gets its own mirror and state.
236
- - Not ported from pi-clm: branch-aware restore, the `max_tokens` clamp lift, cancelling
237
- Pi's own compaction, and the `oneToolPerTurn` and `sizeTrailer` switches.
238
-
239
- ## Testing
240
-
241
- No model has run through this package. Its tests are unit tests, a load smoke test and a
242
- mock-server end-to-end test (see Development).
243
-
244
- The integration suite (`test/e2e`, 10 tests) drives the real OpenCode binary
245
- (1.18.34, pinned in CI) against a scripted OpenAI-compatible mock, with temporary HOME
246
- and XDG directories. It covers: plugin load and command registration (`debug config`,
247
- `/clm path`, `/clm-compact`); the mirror written and re-rendered each turn; an accepted
248
- edit whose text reaches the next request; a `shrink` gate refusal and the note the model
249
- sees; budget nudges at 50% and at budget − reserve; auto-compaction (the summary carries
250
- the edited text and the summarizer gets the pin instruction; the next request rebases onto
251
- the summary with no drop note, and a pin survives); receipts
252
- from `tool.execute.after`; the observation cap; and a second `opencode run --session`
253
- resuming the revision and mirror. Not covered: the overflow guard, the continuity tools
254
- and a manual `/compact`.
255
-
256
- The server-side suffix-cache work is experimental and unreleased.
257
-
258
- ## Development
259
-
260
- - `bun test`: unit tests.
261
- - `bun run typecheck`: `tsc --noEmit`.
262
- - `scripts/smoke.sh`: offline, no model. Checks the `npm pack` file list, that OpenCode
263
- loads the plugin from `file://` and registers `/clm`, `/clm-compact` and the skills
264
- path with no plugin error in its logs, and how `@opencode-ai/plugin` resolves from the
265
- repo, a bare tarball and an offline `npm install`.
266
- - `bun run test:e2e`: the integration suite above (about 30-55 s). Needs the `opencode`
267
- binary (`OPENCODE_BIN` overrides it; `OPENCODE_CLM_E2E_KEEP=1` keeps the temp tree) and
268
- npm registry access, because OpenCode installs `@opencode-ai/plugin` into its temporary
269
- config directory.
270
- - CI (`.github/workflows/ci.yml`) runs on pull requests and pushes to `main`: frozen
271
- install, typecheck, `bun test`, `npm pack --dry-run`, `scripts/smoke.sh --strict` and the
272
- integration suite against `opencode-ai@1.18.34`.
273
- - Commit messages follow [Conventional Commits](https://www.conventionalcommits.org)
274
- (`feat:`, `fix:`, `docs:`, `ci:`, `test:`, `refactor:`, `chore:`; `!` for breaking
275
- changes). `pre-commit install` adds a commit-msg hook that checks them.
276
-
277
- ## Releasing
278
-
279
- Releases come from Conventional Commits through [git-cliff](https://git-cliff.org)
280
- (`cliff.toml`). `feat` bumps minor; `fix` and any commit except `chore` and `style` bump
281
- patch; a breaking change bumps minor below 1.0.0. v0.1.0 is a single commit,
282
- `feat: initial release`.
283
-
284
- 1. Actions → "Prepare release" → Run workflow on `main` (tick `dry_run` to preview).
285
- It computes the version (`git-cliff --bumped-version`), bumps `package.json` if needed,
286
- commits `chore(release): vX.Y.Z`, tags, pushes and dispatches "Release".
287
- 2. "Release" checks the tag against `package.json`, runs CI on the tag, publishes to npm
288
- through trusted publishing (OIDC, provenance, no token), then creates the GitHub
289
- Release with git-cliff notes.
37
+ ```jsonc
38
+ // opencode.json
39
+ { "plugin": [["opencode-clm", { "budget": "64k" }]] }
40
+ // tui.json
41
+ { "plugin": ["opencode-clm"] }
42
+ ```
290
43
 
291
- Preview locally: `git-cliff --bumped-version` and `git-cliff --unreleased --strip header`.
292
- Notes for 0.1.1 and later live in GitHub Releases; CHANGELOG.md holds 0.1.0.
44
+ ## Quick start
45
+
46
+ | command | what it does |
47
+ |---------|--------------|
48
+ | `/clm` | open the panel: **overview** (context size per request + every accepted edit) <br><img src="https://raw.githubusercontent.com/bcmyguest/opencode-clm/main/.github/images/overview.png" alt="The overview page: context size per request, with the requests after which the model edited its context" width="720"> <br> **input** (what the next request contains) · **edits** (per-revision side-by-side diff) <br><img src="https://raw.githubusercontent.com/bcmyguest/opencode-clm/main/.github/images/edits.png" alt="The edits page: a tool result before and after the model shortened it" width="720"> |
49
+ | `/clm overview` / `input` / `edits` / `settings` | open the panel on that page (`timeline` and `edit` also work); without the TUI plugin, print it as text |
50
+ | `/clm status` | a toast: on or off, revision, last request size, budget, fixed overhead, last outcome |
51
+ | `/clm config` | open **settings**; `/clm config <setting> <value>` changes one, `/clm config reset` drops this session's changes <br><img src="https://raw.githubusercontent.com/bcmyguest/opencode-clm/main/.github/images/settings.png" alt="The settings page: sizes, files, and every setting" width="720"> |
52
+ | `/clm-compact [instructions]` | ask the model to compact its own context now; anything you add (e.g. what to keep) is passed along. The result shows on the **edits** page |
53
+ | `/clm on` / `off` / `reset` / `path` | enable, use raw context, discard the accepted revision, show the mirror's path |
54
+ | `/clm budget [value]` | show or change the budget, the same as `/clm config budget` |
55
+
56
+ With the TUI plugin, typed `/clm …` lines run in the TUI and cost no model turn, and Tab
57
+ completes their subcommands, setting names and values;
58
+ `/clm reset` is handed to the server plugin, also without a turn. The right of the
59
+ session prompt shows `clm <size> / <budget> · r<revision>` (`~` before the size marks an
60
+ estimate the provider has not confirmed; `clm off · r<revision>` while CLM is off).
61
+
62
+ In the panel: `1–4` or `Tab` switch pages, `← →` step through the overview's markers or
63
+ the edits page's revisions, `z` zooms the chart, `Enter` opens the selection, `r`
64
+ reloads, `q` closes.
65
+
66
+ ## Benchmarks
67
+
68
+ These numbers come from one machine (AMD Strix Halo, gfx1151, Vulkan) running
69
+ Qwen3.8-Flash-Next (UD-IQ4_XS) through lemonade, on a llama.cpp build with an
70
+ unreleased patch that ports the paper's
71
+ [Suffix Cache Reuse](https://github.com/facebookresearch/context-language-models/tree/main/suffix_cache_reuse)
72
+ (an SGLang patch) to llama.cpp's hybrid models. On a stock server, an edit re-prefills
73
+ everything after the first changed token.
74
+
75
+ **GSM8K, 50 test problems, edited prompt.** Each problem is primed with an 8-shot prompt
76
+ holding three stale worked examples, then asked again with that block replaced by a
77
+ one-line note, mirroring a CLM edit. Temperature 0, thinking off.
78
+
79
+ | | reuse after the edit | full prefill |
80
+ |---|---|---|
81
+ | accuracy | 48/50 | 49/50 |
82
+ | median tokens prefilled | 23 | 1,362 |
83
+ | median prompt time | 0.51 s | 5.02 s |
84
+ | median request time | 3.1 s | 7.2 s |
85
+
86
+ **A live OpenCode session** with opencode-clm 0.2.0 (48k budget, auto-compaction off)
87
+ read and summarised every file under `src/` and `test/` of this repository and wrote its
88
+ notes: 49 requests, 16 accepted edits, 0 rejected. The server reused cache after 23 edits
89
+ and prefilled 11,240 tokens in total, where a prefix-only cache would have prefilled
90
+ 214,585 (95% less); requests of 20–48k tokens prefilled 34–3,523 tokens each.
91
+
92
+ Flash-Next was not trained for CLM, so it makes more edit mistakes than the paper's
93
+ trained models. Hosted APIs are untested.
94
+
95
+ ## Docs
96
+
97
+ - [How it works](docs/how-it-works.md) — the mirror, what runs without the model, the panel, model and server support, safety.
98
+ - [Configuration](docs/configuration.md) — every setting (editing, budget, reserve, reminders, gate, guard, compaction, cap, steering, one-tool, trailer, compact-prompt, reasoning), plugin options and environment variables.
99
+ - [Architecture](docs/architecture.md) — modules, session files, design notes, known limitations.
100
+ - [Development](docs/development.md) — setup, checks, the integration suites, releasing.
101
+
102
+ ## Citation
103
+
104
+ If you use opencode-clm in your research, please cite
105
+ [Context Language Models](https://arxiv.org/abs/2609.37725):
106
+
107
+ ```bibtex
108
+ @article{shao2026context,
109
+ title = {Context Language Models},
110
+ author = {Shao, Rulin and Shen, Shannon Zejiang and Yin, Junjie Oscar and Li, Yuetai and
111
+ Wang, Minheng and Ivison, Hamish and Poovendran, Radha and Lambert, Nathan and
112
+ Xiao, Teng and Lewis, Mike and Yih, Wen-tau and Zettlemoyer, Luke and Koh, Pang Wei},
113
+ journal = {arXiv preprint arXiv:2609.37725},
114
+ year = {2026}
115
+ }
116
+ ```
293
117
 
294
118
  ## Credits
295
119
 
296
120
  - [pi-clm](https://github.com/lolipopshock/pi-clm) 1.0.0 (MIT, Copyright 2026 Emanuel
297
- Casco): the design and most of the code derive from it. Model-facing text taken from
298
- pi-clm, adapted: the compaction prompt (`src/compact.ts`), the `clm-context` skill, the
299
- budget notices, the mirror rejection and receipt messages, and the overflow and
300
- observation notes. `steering/house-brief.md` is byte-identical to pi-clm's. Written for
301
- this package: the system-prompt protocol section (`src/presentation.ts`), the edit-gate
302
- refusal note, and the plugin's own receipts, commands and tool descriptions.
303
- [NOTICE](NOTICE) lists the files; [LICENSE](LICENSE) carries pi-clm's notice.
304
- - Context Language Models, [arXiv 2609.37725](https://arxiv.org/abs/2609.37725), and
305
- [facebookresearch/context-language-models](https://github.com/facebookresearch/context-language-models)
306
- (CC BY-NC 4.0). This package copies no text from that repository (normalized 5-gram
307
- check: no shared span over 6 tokens). The `fit` / `shrink` edit gate and the default
308
- 25/50/75% reminder steps follow its harness design, and the edit-cost advice in the
309
- skill, inherited from pi-clm, covers the same points as the harness prompt in different
310
- words. This package is not licensed under CC BY-NC and is not endorsed by its authors.
311
-
312
- ## AI assistance
313
-
314
- Claude Code (Claude Opus) wrote the code and documentation in this repository. The
315
- maintainer has not hand-reviewed them.
121
+ Casco): the design and most of the code derive from it, the `/clm` panel included, and
122
+ most model-facing text is adapted from it. [NOTICE](NOTICE) lists the files.
123
+ - [facebookresearch/context-language-models](https://github.com/facebookresearch/context-language-models)
124
+ (CC BY-NC 4.0): this package copies no text from it; the `fit` / `shrink` edit gate and
125
+ the default 25/50/75% reminder steps follow its harness design. This package is not
126
+ licensed under CC BY-NC and is not endorsed by its authors.
127
+ - Claude Code (Claude Opus) wrote the code and documentation; the maintainer has not
128
+ hand-reviewed them.
316
129
 
317
130
  ## License
318
131