Autocompact
Claude Code-style autocompact for OpenCode V2 with a per-session threshold: /autocompact 500k compacts a session and its children once the live context reaches that many tokens.
0
1,165
近 7 天 1.2k
38.8
生态多维模型
1 天前
2026-10-19
快速安装与配置
opencode.json写入当前项目的 opencode.json,只对这个仓库生效。
opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["@hacky.software/opencode-autocompact@0.1.7"]
}写入 ~/.config/opencode/opencode.json,对所有项目生效。
~/.config/opencode/opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["@hacky.software/opencode-autocompact@0.1.7"]
}若你要在本地改造这个插件,先装到项目里再从本地路径引用。
shell
pnpm add -D @hacky.software/opencode-autocompactOpenCode 启动时会通过内嵌运行时自动加载 npm 依赖并缓存至本地目录,无需手动在全局环境执行安装。
Claude Code's autocompact, with a knob. An OpenCode V2 plugin that compacts a session before the model's real context limit — at a number you choose, per session.
/autocompact 500k # compact this session (and its children) at 500k tokens
/autocompact 500000 # same, plain count
/autocompact 1m # suffix form
/autocompact # report the effective threshold and the model's limit
/autocompact off # revert this session (and descendants) to normal auto
Tested against OpenCode 2.0.24.
Why
OpenCode already compacts automatically when a session approaches the model's context limit, but that behaviour is configured globally and only in terms of the limit itself:
{
"compaction": {
"auto": true,
"keep": { "tokens": 15000 },
"buffer": 20000 // tokens kept free below the model limit
}
}
There is no per-session setting, and on a large-context model (256K, 1M, …) the
default kicks in very late. Sometimes you want to trim a session much earlier —
cheaper requests, more headroom for big tool results, a shorter tail for the
summarizer, or simply a predictable ceiling. /autocompact 500k says exactly
that, for one session, without touching anyone else's config.
What it does
- Per-session thresholds.
/autocompact <n>records a token ceiling for the session it was run in. - Inheritance. The threshold applies to that session's children and
subagents, resolved by walking the
parentIDchain. - Early compaction. Once the session's live context reaches the threshold, the plugin asks OpenCode to compact, so it happens well below the model limit.
- Opt-out.
/autocompact offstops the plugin for that session and its descendants, falling back to OpenCode's normal auto-compaction. - Zero footprint by default. With no threshold set for a session or any of its ancestors, the plugin does nothing at all.
- Visible when set. When a threshold applies, a small chip joins the prompt footer's status row (next to OpenCode's own context indicator), and a side panel shows the numbers in detail.
Install
opencode plugin add @hacky.software/opencode-autocompact@0.1.7
OpenCode 2.0.32 packaging note: TUI entries installed from npm are loaded with a dynamic
import(), which resolves the plugin's own bundledsolid-js. That second Solid instance renders once but does not react, so the footer chip stays hidden and the side panel never refreshes. Point the config at a local checkout instead (below) — the host transpiles local TUI entries against its own runtime, so slots and keymaps stay live.
Or add it to opencode.json directly — string form, or the object form to pass
options:
// ~/.config/opencode/opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugins": [
{
"package": "@hacky.software/opencode-autocompact",
"options": {
"minCheckIntervalMs": 2000,
"compactionTimeoutMs": 300000,
"debugEvents": false
}
}
]
}
To run from a checkout instead, point the config at the directory (the loader
does not install dependencies for local-path entries, so run bun install once
inside it):
{
"plugins": [{ "package": "/path/to/opencode-autocompact" }]
}
Usage
| Command | Effect |
|---|---|
/autocompact 500k |
Set the threshold to 500,000 tokens for this session and its children. |
/autocompact 500000 |
Same, plain count. Accepts k/m suffixes, underscores, and a space before the suffix (1.5m, 250_000). |
/autocompact |
Report the effective threshold and the current model's limit.context. |
/autocompact off |
Disable the plugin for this session and its descendants (overrides an inherited threshold from an ancestor). |
A value at or above the model's limit.context is refused (must be lower than the model limit), since the point is to compact earlier. The command is silent
in the TUI; its outcome is written to the log (see below).
How it works
The plugin has two halves: a command that records thresholds in plugin storage, and a watcher that reacts to the session event stream. When a model call finishes, the watcher recomputes the session's live context size; if it has reached the effective threshold, it asks OpenCode to compact the session, and OpenCode runs that at the next safe point.
Measuring "how full" the session is
Session.Info.tokens and the session.usage.updated event carry cumulative
session usage — they keep climbing across every request and never tell you how
big the current context is.
The live context size is instead the prompt size of the newest model call, which OpenCode records on each assistant message:
used = tokens.input + tokens.cache.read + tokens.cache.write
The watcher reads that from ctx.session.context({ sessionID }) and compares it
to the effective threshold. (This is the same measure OpenCode's own tooling uses
for context occupancy.)
Triggering compaction
When used >= threshold, the watcher calls ctx.session.compact({ sessionID }).
Compaction is admitted immediately and runs at the next safe point, and repeated
requests while one is pending merge — so the session is trimmed before it ever
nears the real limit.
Inheritance and off
Thresholds live in plugin storage under autocompact/threshold/<sessionID> as
either { kind: "limit", threshold } or { kind: "off" }. The effective
threshold for a session is resolved by walking up the parentID chain:
- the nearest
limitwins; - an
offmarker anywhere on the path stops the walk and disables the plugin for that branch (so/autocompact offon a child beats a limit inherited from its parent); - nothing found → the plugin stays out of the way.
Resolutions are memoised per session and invalidated whenever a command writes.
Guards and lifecycle
- Coalescing — usage events are frequent; checks are coalesced per session
(
minCheckIntervalMs). - In-flight guard — while a compaction is running, further requests for that
session are skipped. The guard is released by the
session.compaction.ended/.failedevents, withcompactionTimeoutMsas a backstop if those are missed (e.g. a reload mid-compaction). - Deletion —
session.deletedclears the session's stored threshold and memoised resolution.
Configuration
Options are passed in the plugin entry's options object:
| Option | Default | Meaning |
|---|---|---|
enabled |
true |
Master switch. When false the plugin loads but does nothing. |
minCheckIntervalMs |
2000 |
Coalescing window between usage-driven checks for one session. |
compactionTimeoutMs |
300000 |
Releases the in-flight guard if compaction events are missed. |
debugEvents |
false |
Log every raw event (payload verification aid). |
Feedback and logs
The command produces no chat output. Its result is appended to
<data>/opencode/log/autocompact.log under the [autocompact] prefix, e.g.:
compaction threshold set to 5k for ses_… and its children (model limit 131.1k)
compaction requested (ses_…) — used 7686 >= threshold 5000
TUI
The plugin also ships a CLI (TUI) half:
- Footer chip — a contribution to
prompt.footer.status, appended after OpenCode's own context indicator (the built-in readout is never replaced). It readsautocompact <used>/<threshold>for a session with a threshold, orautocompact offwhere the plugin was switched off. Sessions with nothing set show no chip at all. - Side panel —
Autocompact: open side panel(command palette) docks a panel namedautocompact.statusshowing the mode, the threshold, whether it is the session's own or inherited, the live context size, and the model's limit.
Both are fed by a small RPC: the server half owns the threshold and answers
status; /autocompact emits updated so the chip and panel refresh the moment
you set or clear a threshold. The chip also follows the session event stream —
it refreshes on session.usage.updated and on both compaction edges — so the
live context number tracks each turn and drops back down after a compaction,
inline with OpenCode's own context readout. A short poll while the chip or panel
is on screen is the fallback if an event is missed.
Development
bun install
bun test # 38 unit tests
bun run typecheck
If a checkout sits outside OpenCode's watched config directories, edits may not be picked up automatically — restart the service:
opencode2 service restart
Limitations
- The threshold is validated against the model limit only when set. If you switch
a session to a model with a smaller limit, re-run
/autocompact. - Every plugin location receives the event stream, so more than one instance may request compaction for the same session. Requests merge in OpenCode, so this is harmless; the in-flight guard de-duplicates within a single instance.
- Detection depends on the session emitting
session.usage.updatedand on the assistanttokensshape; enabledebugEventsif a runtime change stops it.
License
MIT
同类生态推荐
Jev Compaction
opencode-jev-compaction
opencode plugins that shrink context by deleting provably-stale tool calls and truncating the rest, deterministically first, with an optional local Laya backend.
Compaction Meter
opencode-compaction-meter
OpenCode TUI plugin: how many times the session has compacted, tool calls per cycle, room after each restart, and whether the last summary was cut off. Spots compaction thrash while you work.
Context Pruner
opencode-context-pruner
Continuous verbatim context pruning for OpenCode, powered by TypeSafe Jev. Port of fast-jev-compaction adapted to OpenCode's context hook.