A transparent proxy that gives Claude Code rolling context compression — old messages get automatically summarized while recent messages stay fully verbatim. You never hit the context wall, and you never lose important details. Zero config.
Repo: NodeNestor/claude-rolling-context
What's inside
A transparent proxy that gives Claude Code rolling context compression — old messages get automatically summarized while recent messages stay fully verbatim. You never hit the context wall, and you never lose important details.
Zero config. Uses your existing Claude Code auth. No API key needed. Just install and forget.
Claude Code's built-in
/compactreplaces your entire conversation with a lossy summary. After a few compactions, you're summarizing a summary of a summary. This plugin only compresses old messages — recent context stays untouched.
It's also a cost story: every token you carry in context gets re-billed on every turn (at cache-read rates), so an unmanaged session's input cost grows with the square of its length. Capping the prefix makes it linear — the math works in relative units and holds for every model, and it matters more the bigger the context window, not less.
/compact vs Rolling Context/compact (built-in) | Rolling Context | |
|---|---|---|
| What gets compressed | Everything | Only old messages |
| Recent context | Summarized (lossy) | Kept verbatim |
| When it runs | Manual or near the context limit | Automatic, background |
| Latency impact | Blocks until done | Zero — async |
| After multiple compressions | Summary of summary of summary | Fresh rolling merge each time |
| Input cost over a long session | Grows with the square of session length | Grows linearly |
| Original transcript | Replaced | Preserved (JSONL unchanged) |
No price cards needed — the argument works in relative units that hold for every Claude model. Take the model's fresh-input-token rate as 1×. The API bills:
| Operation | Relative cost |
|---|---|
| Fresh input tokens | 1× |
| Prompt-cache read | 0.1× |
| Prompt-cache write | 1.25× (5-min TTL) / 2× (1-hour TTL) |
| Output tokens | ~5× |
Claude Code re-sends the entire conversation on every turn. Even with caching working perfectly, each turn costs prefix size × 0.1. So a session's total input cost is the sum of the prefix over all turns:
0.1× again on every single turn.TARGET and TRIGGER, so total cost grows linearly.The cache-miss blast radius matters even more in interactive use. The prompt cache has a TTL. Read a diff, think for a while, get coffee — and the next turn re-writes the whole prefix at 1.25×. At a 900K prefix, one cold turn bills the equivalent of ~1.1M fresh input tokens. With the prefix capped at ~100K, the identical cold turn is ~9× cheaper. Compression doesn't just shrink the average turn — it caps the worst one.
What compression itself costs: each cycle re-writes the new (much smaller) prefix once, and in native mode the summarization request is itself a cache read — a few hundred fresh tokens, measured (see below). Ballpark: sessions that accumulate past ~100K of context — a couple of hours of real work — come out ahead, and the gap compounds from there. Short sessions are a wash; don't expect magic on a 20-minute task.
On Pro/Max subscriptions none of this is dollars, but the same math applies in a different currency: rate-limit accounting weights cache reads far below fresh input, so the identical curves decide how fast you burn your 5-hour window.
Honest note: if cost were the only goal, lowering Claude Code's auto-compact threshold (
CLAUDE_CODE_AUTO_COMPACT_WINDOW) buys a similar spend curve for free. What it can't buy is quality under repetition: built-in compaction replaces the whole conversation with a lossy summary every time it fires — at a low threshold it fires often, and you're soon working from a summary of a summary of a summary. The rolling design exists so aggressive compression doesn't cost you the session: recent work stays verbatim, and old work lives in one continuously-merged timeline instead of N generations of loss.
Claude Code ──HTTPS_PROXY──► Rolling Context MITM (:5590) ──► core (:5588) ──► Anthropic API
│
├─ context < 100K tokens? pass through unchanged
│
└─ context > 100K tokens?
1. summarize old messages in the background
(native mode: your session's own model,
served almost entirely from prompt cache)
2. keep ~40K tokens of recent messages verbatim
3. inject compressed context on next request
4. never blocks, never adds latency
How it attaches: the plugin sets HTTPS_PROXY (and NODE_EXTRA_CA_CERTS), not ANTHROPIC_BASE_URL. A non-anthropic ANTHROPIC_BASE_URL trips Claude Code's Remote Control / GrowthBook gate; routing through HTTPS_PROXY keeps the destination api.anthropic.com, so the gate stays untouched. A small MITM front-end terminates TLS with a locally generated CA (trusted via NODE_EXTRA_CA_CERTS) so bodies stay visible for compression; everything that is not api.anthropic.com (or your configured endpoint) is blind-tunnelled untouched.
Instead of replacing everything, this plugin:
~/.claude/projects/Run these two commands inside Claude Code:
/plugin marketplace add https://github.com/NodeNestor/nestor-plugins
/plugin install rolling-context
Restart your terminal and start a new Claude Code session. On the first start, the plugin configures HTTPS_PROXY + NODE_EXTRA_CA_CERTS and starts the proxy. Since those env vars only take effect on the next terminal, restart your terminal once more — after that, everything works automatically. No pip install needed — pure Python stdlib (a local CA is generated with cryptography, which Claude Code already ships).
Linux / macOS:
git clone https://github.com/NodeNestor/claude-rolling-context.git ~/claude-rolling-context
cd ~/claude-rolling-context
bash install.sh
Windows (PowerShell):
git clone https://github.com/NodeNestor/claude-rolling-context.git $HOME\claude-rolling-context
cd $HOME\claude-rolling-context
powershell -ExecutionPolicy Bypass -File install.ps1
The installer configures HTTPS_PROXY + NODE_EXTRA_CA_CERTS and registers the plugin. Restart your terminal and you're done. Requires Python 3.7+ (no pip install needed — pure stdlib).
When the message array exceeds the trigger threshold:
BEFORE (hit 100K trigger):
[msg1] [msg2] [msg3] ... [msg60] [msg61] ... [msg100]
|<——————————————— ~105K tokens ——————————————>|
AFTER (compressed):
[rolling summary] [ack] [msg61] ... [msg100]
|<— ~5K summary —>| |<—— verbatim ————————>|
NEXT CYCLE (grows back to 100K, triggers again):
[rolling summary] [ack] [msg61] ... [msg140]
|<——————————————— ~105K tokens ——————————————>|
→ new summary merges old summary + msg61-msg100
→ keeps msg101-msg140 verbatim
The summary preserves a structured record of everything that happened:
Goals evolve naturally across rolling compressions — the latest request stays prominent while completed goals move to the previous section. User instructions are never lost.
By default the proxy doesn't build a separate summarization request. It clones the exact request Claude Code just sent — same model, system prompt, and tools, with the conversation truncated at the cut point — and appends one user message asking for the summary (the same way Claude Code's own /compact works). Two big wins:
Setting ROLLING_CONTEXT_MODEL pins a different summarizer model (the request shape stays native, but a different model means no prompt-cache reuse). If the session's model answers the compaction request with a 200 and no text — on claude-fable-5 a safety classifier can return stop_reason: refusal with no content, deterministically for that conversation — the proxy logs the stop reason and retries once on ROLLING_CONTEXT_FALLBACK_MODEL instead of cooling the conversation down for nothing (#11). Configuring any ROLLING_CONTEXT_SUMMARIZER_* variable switches to a standalone flattened request instead — see below.
Summarization can run on a completely separate endpoint — any Anthropic-format API, or any OpenAI-compatible one (Ollama, LM Studio, vLLM, OpenRouter, DeepSeek, Groq, ...):
# Separate Anthropic API key (billed there instead of your subscription)
export ROLLING_CONTEXT_SUMMARIZER_KEY=sk-ant-api03-...
# Local model via Ollama / LM Studio / vLLM (OpenAI-compatible)
export ROLLING_CONTEXT_SUMMARIZER_URL=http://127.0.0.1:11434
export ROLLING_CONTEXT_SUMMARIZER_FORMAT=openai
export ROLLING_CONTEXT_MODEL=qwen3:8b # required for openai format
# OpenRouter (or any hosted OpenAI-compatible API)
export ROLLING_CONTEXT_SUMMARIZER_URL=https://openrouter.ai/api
export ROLLING_CONTEXT_SUMMARIZER_FORMAT=openai
export ROLLING_CONTEXT_SUMMARIZER_KEY=sk-or-...
export ROLLING_CONTEXT_MODEL=deepseek/deepseek-chat
Point Claude Code at your endpoint the usual way and install as normal. The hook
chains it — ANTHROPIC_BASE_URL stays your endpoint, the MITM front-end
intercepts that host, and your endpoint is stored as ROLLING_CONTEXT_UPSTREAM
— so both the chat traffic and the background compaction go there. No extra
configuration.
Third-party endpoints implement the /v1/messages shape to varying depth. Native
mode clones the request Claude Code just sent, which can include cache_control
breakpoints and tool_choice; if your endpoint rejects one of those, the proxy
FAQ
rolling-context is a Claude Code plugin with hand-picked skills for development work, indexed on Flowy. Install it with the command on its page. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.
Is this plugin yours?
Claim it with GitHubSubmit a pluginPromote it