{"id":51204673,"url":"https://github.com/NodeNestor/claude-rolling-context","last_synced_at":"2026-07-16T12:01:06.325Z","repository":{"id":342429975,"uuid":"1173925549","full_name":"NodeNestor/claude-rolling-context","owner":"NodeNestor","description":"Rolling context compression for Claude Code — never hit the context wall. Auto-compresses old messages while keeping recent context verbatim. Zero config, zero latency. Works as a Claude Code plugin.","archived":false,"fork":false,"pushed_at":"2026-07-12T20:55:37.000Z","size":134,"stargazers_count":21,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-07-12T22:12:46.242Z","etag":null,"topics":["ai-agent","ai-coding","anthropic","claude","claude-code","claude-code-extension","claude-code-plugin","context-compression","context-management","context-window","llm-context","prompt-compression","rolling-context"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NodeNestor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-05T22:25:23.000Z","updated_at":"2026-07-12T20:55:44.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/NodeNestor/claude-rolling-context","commit_stats":null,"previous_names":["nodenestor/claude-rolling-context"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/NodeNestor/claude-rolling-context","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NodeNestor%2Fclaude-rolling-context","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NodeNestor%2Fclaude-rolling-context/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NodeNestor%2Fclaude-rolling-context/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NodeNestor%2Fclaude-rolling-context/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NodeNestor","download_url":"https://codeload.github.com/NodeNestor/claude-rolling-context/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NodeNestor%2Fclaude-rolling-context/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35542951,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-16T02:00:06.687Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agent","ai-coding","anthropic","claude","claude-code","claude-code-extension","claude-code-plugin","context-compression","context-management","context-window","llm-context","prompt-compression","rolling-context"],"created_at":"2026-06-28T02:33:05.920Z","updated_at":"2026-07-16T12:01:06.319Z","avatar_url":"https://github.com/NodeNestor.png","language":"Python","funding_links":[],"categories":["Coding-Assistant Token Savers"],"sub_categories":[],"readme":"# Rolling Context for Claude Code\n\n[![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)\n[![Python 3.7+](https://img.shields.io/badge/python-3.7+-blue.svg)](https://www.python.org)\n![Zero Dependencies](https://img.shields.io/badge/dependencies-zero-orange.svg)\n\nA 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.\n\n**Zero config.** Uses your existing Claude Code auth. No API key needed. Just install and forget.\n\n\u003e Claude Code's built-in `/compact` replaces 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.\n\nIt'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](#the-economics-why-capping-the-prefix-matters) works in relative units and holds for every model, and it matters more the bigger the context window, not less.\n\n## `/compact` vs Rolling Context\n\n| | `/compact` (built-in) | Rolling Context |\n|---|---|---|\n| What gets compressed | Everything | Only old messages |\n| Recent context | Summarized (lossy) | **Kept verbatim** |\n| When it runs | Manual or near the context limit | Automatic, background |\n| Latency impact | Blocks until done | Zero — async |\n| After multiple compressions | Summary of summary of summary | Fresh rolling merge each time |\n| Input cost over a long session | Grows with the square of session length | Grows linearly |\n| Original transcript | Replaced | Preserved (JSONL unchanged) |\n\n## The economics: why capping the prefix matters\n\nNo 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:\n\n| Operation | Relative cost |\n|---|---|\n| Fresh input tokens | `1×` |\n| Prompt-cache **read** | `0.1×` |\n| Prompt-cache **write** | `1.25×` (5-min TTL) / `2×` (1-hour TTL) |\n| Output tokens | `~5×` |\n\nClaude 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**:\n\n- **Unmanaged context** (big window, auto-compact only near the limit): the prefix grows every turn, so total cost grows with the *square* of session length. A 1M window doesn't fix this — it just lets the prefix run to 900K+ before anything stops it, and every one of those tokens costs `0.1×` again on every single turn.\n- **Rolling context**: the prefix is capped between `TARGET` and `TRIGGER`, so total cost grows *linearly*.\n\n**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.\n\n**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.\n\n**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.\n\n\u003e **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.\n\n## How It Works\n\n```\nClaude Code  ──►  Rolling Context Proxy (:5588)  ──►  Anthropic API\n                         │\n                         ├─ context \u003c 100K tokens? pass through unchanged\n                         │\n                         └─ context \u003e 100K tokens?\n                              1. summarize old messages in the background\n                                 (native mode: your session's own model,\n                                  served almost entirely from prompt cache)\n                              2. keep ~40K tokens of recent messages verbatim\n                              3. inject compressed context on next request\n                              4. never blocks, never adds latency\n```\n\nInstead of replacing everything, this plugin:\n\n1. **Keeps recent messages untouched** — recent context stays verbatim\n2. **Only compresses when needed** — triggers at 100K (real API token count), compresses old messages, grows naturally until next trigger\n3. **Merges summaries** — each compression cycle merges with the previous summary, building a rolling timeline\n4. **Never blocks** — compression runs in the background, applied on the next request\n5. **Full transcripts preserved** — Claude Code still saves everything to JSONL in `~/.claude/projects/`\n\n## Install\n\n### Option 1: Claude Code Plugin (recommended)\n\nRun these two commands inside Claude Code:\n\n```\n/plugin marketplace add https://github.com/NodeNestor/nestor-plugins\n/plugin install rolling-context\n```\n\nRestart your terminal and start a new Claude Code session. On the **first start**, the plugin configures `ANTHROPIC_BASE_URL` and starts the proxy. Since the env var only takes effect on the next terminal, **restart your terminal once more** — after that, everything works automatically. No pip install needed — pure Python stdlib.\n\n### Option 2: Manual install\n\n**Linux / macOS:**\n```bash\ngit clone https://github.com/NodeNestor/claude-rolling-context.git ~/claude-rolling-context\ncd ~/claude-rolling-context\nbash install.sh\n```\n\n**Windows (PowerShell):**\n```powershell\ngit clone https://github.com/NodeNestor/claude-rolling-context.git $HOME\\claude-rolling-context\ncd $HOME\\claude-rolling-context\npowershell -ExecutionPolicy Bypass -File install.ps1\n```\n\nThe installer configures `ANTHROPIC_BASE_URL` and registers the plugin. Restart your terminal and you're done. Requires Python 3.7+ (no pip install needed — pure stdlib).\n\n## How Compression Works\n\nWhen the message array exceeds the trigger threshold:\n\n```\nBEFORE (hit 100K trigger):\n  [msg1] [msg2] [msg3] ... [msg60] [msg61] ... [msg100]\n  |\u003c——————————————— ~105K tokens ——————————————\u003e|\n\nAFTER (compressed):\n  [rolling summary] [ack] [msg61] ... [msg100]\n  |\u003c— ~5K summary —\u003e|    |\u003c—— verbatim ————————\u003e|\n\nNEXT CYCLE (grows back to 100K, triggers again):\n  [rolling summary] [ack] [msg61] ... [msg140]\n  |\u003c——————————————— ~105K tokens ——————————————\u003e|\n  → new summary merges old summary + msg61-msg100\n  → keeps msg101-msg140 verbatim\n```\n\nThe summary preserves a structured record of everything that happened:\n\n- **Active Goal** — what the user is currently asking for, constraints, do/don't rules\n- **Previous Goals** — completed or shifted-away-from goals (kept brief)\n- **Timeline** — chronological numbered steps: every file change, decision, error, and user instruction\n- **Current State** — what's done, in progress, and next\n- **Key Details** — file paths, configs, decisions that must survive compression\n\nGoals evolve naturally across rolling compressions — the latest request stays prominent while completed goals move to the previous section. User instructions are never lost.\n\n### How the summary is generated (native mode)\n\nBy 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:\n\n- **It's a prompt-cache read.** The cloned prefix was just sent by the chat request, so the API serves it from cache. Measured in practice: a ~72K-token compression request cost ~400 fresh input tokens.\n- **It's genuine Claude Code session traffic.** Pro/Max subscription OAuth tokens are classified server-side — standalone requests that don't look like Claude Code get routed to the overage lane and rejected with 429. The cloned request passes because it *is* the session's own request shape.\n\nSetting `ROLLING_CONTEXT_MODEL` pins a different summarizer model (the request shape stays native, but a different model means no prompt-cache reuse). Configuring any `ROLLING_CONTEXT_SUMMARIZER_*` variable switches to a standalone flattened request instead — see below.\n\n### Using any API or a local model for compression\n\nSummarization can run on a completely separate endpoint — any Anthropic-format API, or any OpenAI-compatible one (Ollama, LM Studio, vLLM, OpenRouter, DeepSeek, Groq, ...):\n\n```bash\n# Separate Anthropic API key (billed there instead of your subscription)\nexport ROLLING_CONTEXT_SUMMARIZER_KEY=sk-ant-api03-...\n\n# Local model via Ollama / LM Studio / vLLM (OpenAI-compatible)\nexport ROLLING_CONTEXT_SUMMARIZER_URL=http://127.0.0.1:11434\nexport ROLLING_CONTEXT_SUMMARIZER_FORMAT=openai\nexport ROLLING_CONTEXT_MODEL=qwen3:8b   # required for openai format\n\n# OpenRouter (or any hosted OpenAI-compatible API)\nexport ROLLING_CONTEXT_SUMMARIZER_URL=https://openrouter.ai/api\nexport ROLLING_CONTEXT_SUMMARIZER_FORMAT=openai\nexport ROLLING_CONTEXT_SUMMARIZER_KEY=sk-or-...\nexport ROLLING_CONTEXT_MODEL=deepseek/deepseek-chat\n```\n\n## Architecture\n\nThe proxy is **fully stateless** — no sessions, no databases, no tracking. It works by hashing message content:\n\n1. When a response comes back from the API with a high token count, the proxy compresses the messages and stores the result keyed by content hashes\n2. On the next request, it hashes the incoming messages and checks for a matching compression\n3. If found, it swaps in the compressed version transparently\n\nThis means:\n- **Multiple conversations work automatically** — each conversation has unique content, unique hashes, no collision\n- **Subagents and branches just work** — the proxy doesn't care about sessions, only content\n- **No state to corrupt** — restart the proxy anytime, worst case is one extra compression cycle\n- **Claude Code sees nothing different** — the proxy is invisible, JSONL transcripts are unmodified\n\n## Configuration\n\nAll settings via environment variables (all optional — defaults work great):\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `ROLLING_CONTEXT_TRIGGER` | `100000` | Compress when context exceeds this many tokens |\n| `ROLLING_CONTEXT_TARGET` | `40000` | Keep this many tokens of recent messages after compression |\n| `ROLLING_CONTEXT_MODEL` | *(session model)* | Summarizer model; unset = the session's own model (prompt-cache hit) |\n| `ROLLING_CONTEXT_PORT` | `5588` | Proxy listen port |\n| `ROLLING_CONTEXT_UPSTREAM` | `https://api.anthropic.com` | Upstream API URL (chain to another proxy!) |\n| `ROLLING_CONTEXT_SUMMARIZER_URL` | *(upstream)* | Custom endpoint for summarization (local model, other API) |\n| `ROLLING_CONTEXT_SUMMARIZER_KEY` | *(uses Claude Code auth)* | API key for custom summarizer endpoint |\n| `ROLLING_CONTEXT_SUMMARIZER_FORMAT` | `anthropic` | `openai` = /v1/chat/completions for OpenAI-compatible endpoints |\n| `ROLLING_CONTEXT_FAILURE_COOLDOWN` | `300` | Seconds to wait before retrying after a failed compression |\n\n## Proxy Chaining\n\nAlready using another proxy (model router, API gateway, etc.)? Rolling Context auto-detects this and chains through it:\n\n```\nClaude Code  ──►  Rolling Context (:5588)  ──►  Your Proxy  ──►  Anthropic API\n```\n\nIf `ANTHROPIC_BASE_URL` is already set when you install, the plugin automatically saves it as `ROLLING_CONTEXT_UPSTREAM` and inserts itself in front. No manual config needed.\n\nYou can also set it explicitly:\n```bash\nexport ROLLING_CONTEXT_UPSTREAM=http://localhost:8080  # your existing proxy\n```\n\n## Health Check\n\n```bash\ncurl http://127.0.0.1:5588/health\n```\n\nReturns compression stats: how many compressions, tokens saved, etc.\n\n## Debug\n\n```bash\ncurl http://127.0.0.1:5588/debug/compressions\n```\n\nReturns the stored compression entries with their full summary content — useful for verifying what the rolling summary captured and whether user goals/instructions survived compression.\n\n## Uninstall\n\nRun the uninstall script — it handles both manual and marketplace installs, stops the proxy, cleans env vars, and removes all plugin registrations.\n\n**Linux / macOS:**\n```bash\ncd ~/claude-rolling-context \u0026\u0026 bash uninstall.sh\n```\n\n**Windows (PowerShell):**\n```powershell\ncd $HOME\\claude-rolling-context; powershell -ExecutionPolicy Bypass -File uninstall.ps1\n```\n\nIf you installed via marketplace and already deleted the repo, you can run it from the cache:\n```powershell\ncd $HOME\\.claude\\plugins\\cache\\rolling-context-marketplace\\rolling-context\\\u003cversion\u003e\npowershell -ExecutionPolicy Bypass -File uninstall.ps1\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNodeNestor%2Fclaude-rolling-context","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FNodeNestor%2Fclaude-rolling-context","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNodeNestor%2Fclaude-rolling-context/lists"}