How it works
The compression loop — stable IDs, the compress tool, summaries, and cache awareness.
cmx is a local gateway. Your harness talks to it exactly like it talks to the
model provider; cmx forwards to the real upstream, transparently managing
context along the way.
harness ──▶ cmx gateway (127.0.0.1:17322) ──▶ model provider │ ├─ TUI: cmx └─ Web dashboard (127.0.0.1:17323)-
Stable message IDs
On every proxied request, older messages get tagged with stable markers:
xml <cmx-id-m0001> …original message content… </cmx-id-m0001>The most recent messages — the “tail” you configured with
keep_recent_tokens— are left byte-identical, which is what keeps your provider’s prompt cache hitting. -
The compress tool
cmxadvertises acompresstool to the model (adding it only if your harness hasn’t already defined one). When the model judges that a span of earlier messages is stale — old tool outputs, abandoned approaches, long logs — it calls:json { "ids": ["m0003-m0009"], "reason": "stale exploration replaced by newer findings" } -
Interception + summarization
The compress call is stripped from the response — your harness never sees it. Instead,
cmxasks the same provider (or a cheapersummarizer_model) to distill the span into dense factual bullets: decisions, file paths, commands, errors, outcomes. -
Rewrite on the next turn
Next turn, covered messages are replaced:
xml <cmx-id-compressed>[Summary cX of m0003-m0009 — earlier content compressed]- user wants X; constraints Y- tried A (failed: …); working from B- next: C</cmx-id-compressed>Overlapping compressions nest naturally: a later summary that covers an older summary substitutes the older text in place.
What gets protected
- The recent tail (last
keep_recent_tokensof context) — never compressed - The final message of every request (the current turn)
- Messages using protected tools (
task,skill,todowrite,todoread,write,editby default) - Exact code and error content the model still needs — the tool description tells the model not to compress anything it still depends on
Nudges, not force
When context grows past min_context_tokens, cmx appends a small system
reminder listing compressible IDs every nudge_frequency requests. The model
decides. No summarization happens without an explicit compress call.
Cache economics
Every rewrite invalidates the provider’s prompt cache prefix once — that’s a
real cost. Because cmx only rewrites when the model asks, and keeps the
tail pristine, the one-time rewrite cost is repaid by the smaller context
within a couple of turns.
Protocol support
| OpenAI-style | Anthropic-style | |
|---|---|---|
| Endpoint | /v1/chat/completions | /v1/messages |
| Streaming (SSE) | ✅ | ✅ |
| Tool calls | ✅ | ✅ |
| Usage/caching stats | ✅ | ✅ |
Last updated Sep 1, 2026