{"id":51155962,"url":"https://github.com/jianzhichun/permafrost","last_synced_at":"2026-06-26T10:30:35.570Z","repository":{"id":363720202,"uuid":"1264596339","full_name":"jianzhichun/permafrost","owner":"jianzhichun","description":"Freeze Claude Code's prompt prefix so DeepSeek's automatic cache always hits — alignment proxy + coalescing + keepalive, installable as a CC plugin. Measured 64% cheaper on real Claude Code traffic.","archived":false,"fork":false,"pushed_at":"2026-06-10T04:54:55.000Z","size":108,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-10T05:20:43.096Z","etag":null,"topics":["cache-optimization","claude-code","claude-code-plugin","cost-optimization","deepseek","llm","prefix-cache","prompt-cache","proxy"],"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/jianzhichun.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-06-10T02:51:17.000Z","updated_at":"2026-06-10T04:55:44.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jianzhichun/permafrost","commit_stats":null,"previous_names":["jianzhichun/permafrost"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/jianzhichun/permafrost","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jianzhichun%2Fpermafrost","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jianzhichun%2Fpermafrost/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jianzhichun%2Fpermafrost/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jianzhichun%2Fpermafrost/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jianzhichun","download_url":"https://codeload.github.com/jianzhichun/permafrost/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jianzhichun%2Fpermafrost/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34813782,"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-06-26T02:00:06.560Z","response_time":106,"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":["cache-optimization","claude-code","claude-code-plugin","cost-optimization","deepseek","llm","prefix-cache","prompt-cache","proxy"],"created_at":"2026-06-26T10:30:33.896Z","updated_at":"2026-06-26T10:30:35.555Z","avatar_url":"https://github.com/jianzhichun.png","language":"Python","funding_links":[],"categories":["Source Catalog"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\u003cpre\u003e\n   ___  ___ ___ __  __  _   ___ ___  ___  ___ _____\n  | _ \\| __| _ \\  \\/  | /_\\ | __| _ \\/ _ \\/ __|_   _|\n  |  _/| _||   / |\\/| |/ _ \\| _||   / (_) \\__ \\ | |\n  |_|  |___|_|_\\_|  |_/_/ \\_\\_| |_|_\\\\___/|___/ |_|\n        freeze the prefix · melt the bill\n\u003c/pre\u003e\u003c/div\u003e\n\n\u003cp align=\"center\"\u003e\u003cstrong\u003eA Claude Code plugin that keeps DeepSeek's prompt cache hitting when Claude Code would otherwise bust it.\u003c/strong\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003ecache-stable passthrough proxy · deterministic tool order · env freeze+delta · cold-anchor coalescing · live hit-rate statusline · zero deps\u003c/p\u003e\n\n---\n\nPointing Claude Code at DeepSeek's Anthropic-compatible endpoint is cheap, and a\n**vanilla session already hits DeepSeek's cache ~90% on its own** — CC's system\nprompt is shared across users, so it stays warm. The cache breaks when your\n**tool list isn't stable**: MCP servers connect and reshuffle it, and because\ntools render *first* in the cached prefix, any reorder busts everything from\nbyte 0. Permafrost sits between CC and DeepSeek and rewrites the cache-relevant\nbytes so the `tools + system` anchor stays byte-identical turn after turn — then\nstreams the reply straight back.\n\n```\n  Claude Code ──Anthropic /v1/messages──▶ Permafrost ──▶ DeepSeek /anthropic\n   (unchanged)        127.0.0.1:8787     freeze prefix       (both speak Anthropic,\n                                          + record hits        no translation)\n```\n\n## Do you actually need it?\n\nWe ran **bare DeepSeek vs Permafrost head-to-head on the live API** and read\nDeepSeek's real cache tokens. The honest result is two-sided:\n\n| Your Claude Code session | bare DeepSeek | + Permafrost |\n|---|---:|---:|\n| Vanilla — stable tools, no MCP (10-turn task) | 89.6% hit | 89.6% — **no difference** |\n| Tool list churns — MCP servers reshuffle it | **33% hit** | **71% hit** |\n\n**If you run plain single-agent CC, you don't need this** — DeepSeek already does\nthe job. Permafrost earns its keep on the second row: tool churn busts the prefix\nat byte 0 and bare collapses to 33%; the deterministic sort holds it at 71%\n(reproduce: [`e2e/tool_order_ab.py`](e2e/tool_order_ab.py)). So it's for users with\n**MCP servers**, heavily **customized** setups whose anchor isn't the shared-warm\none, or **parallel subagent fan-outs** on cold anchors.\n\n**On cost:** DeepSeek is ~11× cheaper than Claude on pricing alone (cache-hit\ninput $0.0028 vs $0.30 /1M) — that's DeepSeek, not us, the moment you switch\nendpoints. Permafrost's *additional* contribution is keeping the cache hitting\nwhen it would otherwise bust (the 33% → 71% roughly halves the bill on a\ntool-churning workload; on a vanilla session it adds ~0%). Price-for-identical-\ntraffic, not a model-quality claim — `deepseek-v4-flash` is not Sonnet 4.6.\n\n## Quick start\n\n```bash\ngit clone https://github.com/jianzhichun/permafrost \u0026\u0026 cd permafrost\nexport ANTHROPIC_API_KEY=sk-your-deepseek-key\n./cli/permafrost wrap     # starts the proxy, sets env for the child only, execs claude\n```\n\n`wrap` sets `ANTHROPIC_BASE_URL` + `ENABLE_TOOL_SEARCH=true` for the child `claude`\nprocess only — it never touches your shell or `~/.claude/settings.json`.\n\n**As a plugin** (gives you `/permafrost:*` commands, statusline, auto-start hook):\n\n```\n/plugin marketplace add jianzhichun/permafrost\n/plugin install permafrost@permafrost\n```\n\n**Persistent:** copy the `env` block from [`settings.example.json`](settings.example.json)\ninto `~/.claude/settings.json`, run `permafrost up`, start `claude` normally. (CC\nreads its env once at launch — set these *before* it starts.)\n\n## What it does\n\nOn every `/v1/messages` request, the pipeline\n([`proxy/permafrost_align.py`](proxy/permafrost_align.py)) keeps the `tools+system`\nanchor byte-stable, then reads DeepSeek's real `prompt_cache_hit_tokens`:\n\n1. **sorts tools** deterministically — late-binding MCP servers can't reshuffle\n   position 0 of the prefix. *(This is the one that matters most — see above.)*\n2. **freezes the env block + emits deltas** — pins the first-seen env/context\n   block (cwd, date, `git status`) into the anchor; later turns send only changed\n   lines on the tail. `PERMAFROST_FREEZE_ENV=0` relocates the whole block instead.\n3. **strips Claude Code's TodoWrite reminder** — removes the non-semantic\n   `messages[]` system nudge before forwarding. `PERMAFROST_STRIP_TODOWRITE_REMINDERS=0` disables this.\n4. **strips `cache_control`** and **serializes canonically** — DeepSeek ignores\n   the markers; canonical bytes remove serialization drift.\n\nPlus three runtime features (depth in [`docs/HOW-IT-WORKS.md`](docs/HOW-IT-WORKS.md)):\n\n- **Cold-anchor coalescing** — parallel `Task` subagents sharing a cold prefix\n  would all pay the miss price (DeepSeek's write is async); one leader warms the\n  cache, followers wait for its first byte. Live: 0% → 73%. `PERMAFROST_COALESCE=0` off.\n- **Idle keepalive** (opt-in) — replays each conversation's last request,\n  unchanged in body *and headers*, after `PERMAFROST_KEEPALIVE_S` idle, so a long\n  think-gap doesn't lose the prefix to eviction. Live: 99.9% on replay.\n- **Diagnostics** — `/permafrost:status` `:doctor` `:benchmark`, a savings\n  statusline (`❄ 88% cache hit · $0.12 saved`), per-session + per-lineage stats,\n  and byte-level anchor diffs (how we caught CC's per-request `cch` nonce).\n\nThe full catalogue of CC cache-busters it defends against:\n[`docs/cache-busters.md`](docs/cache-busters.md).\n\n## Validation\n\n`e2e/run_full_suite.sh` drives headless `claude -p` through Permafrost against\n**real DeepSeek** across six phases (alignment, coalescing, keepalive+resume,\nwarm, sessions, anchor-diff) — latest run **15/15 passed**. That proves the\nmechanisms work end-to-end; the *value vs bare* is the head-to-head table above.\nWhat these runs taught us about DeepSeek's cache (it re-renders before caching;\ncache identity includes the client header fingerprint; it keys on tool order but\ntolerates the `cch` nonce) is in [`docs/e2e-findings.md`](docs/e2e-findings.md).\n\n\u003cdetails\u003e\u003csummary\u003e\u003cb\u003eOffline benchmark (no API key)\u003c/b\u003e\u003c/summary\u003e\n\nEmulator faithful to the live findings — caches the **rendered** request\n(`tools → system → messages`), unit-quantized, with params + header identity.\n12-turn CC-shaped conversation:\n\n| Scenario | `off` | `aggressive` |\n|---|---:|---:|\n| Tool churn + live git/env | **0%** hit | **88%** hit |\n\n`off` caches nothing (reshuffled tools bust byte 0); `aggressive` (sort) holds 88%.\n`python3 benchmarks/bench.py --turns 12` to reproduce; `--real` adds a live probe.\nDetails + the raw-byte-vs-rendered cross-check: [`benchmarks/RESULTS.md`](benchmarks/RESULTS.md).\n\u003c/details\u003e\n\n## Reference\n\n**Modes** (`PERMAFROST_MODE`): `aggressive` (default: sort + freeze + strip +\ncanonical) · `safe` (no content moved) · `off` (passthrough, still meters).\n\n**Env hardening** — set *before* launching `claude`:\n\n| Variable | Why |\n|---|---|\n| `ANTHROPIC_BASE_URL=http://127.0.0.1:8787` | route CC through Permafrost |\n| `ENABLE_TOOL_SEARCH=true` | **critical** — without it a custom base URL makes CC stop deferring tools and re-inline the whole set every turn |\n| `ANTHROPIC_MODEL` / `ANTHROPIC_SMALL_FAST_MODEL` | pin to one DeepSeek SKU (`claude-opus*`→v4-pro, `*sonnet/haiku*`→v4-flash) |\n\n**Config** (env, all optional):\n\n| Env | Default | Meaning |\n|---|---|---|\n| `PERMAFROST_PORT` | `8787` | listen port |\n| `PERMAFROST_UPSTREAM` | `…/anthropic` | upstream (any Anthropic-compatible endpoint) |\n| `PERMAFROST_FREEZE_ENV` | `1` | freeze env + delta (`0` = relocate whole block) |\n| `PERMAFROST_STRIP_TODOWRITE_REMINDERS` | `1` | remove Claude Code's non-semantic TodoWrite reminder from `messages[]` |\n| `PERMAFROST_COALESCE` / `_SETTLE_MS` | `1` / `2500` | coalescing + async-write settle |\n| `PERMAFROST_KEEPALIVE_S` | `0` (off) | idle-replay interval |\n| `PERMAFROST_PRICES` | V4 Flash | `\"hit,miss,output\"` USD/1M for the cost readout |\n\nThe proxy is zero-dependency stdlib Python, pools upstream connections (no\nper-request TLS), and refuses non-loopback clients on its `/permafrost/*` endpoints.\n\n## Tests\n\n```bash\n# offline (no key, in CI): alignment, proxy units, CC-fixture, emulator + 3 smokes\npython3 tests/test_alignment.py \u0026\u0026 python3 tests/test_proxy_units.py\npython3 tests/test_cc_fixture.py \u0026\u0026 python3 tests/test_emulator.py\nbash tests/proxy_smoke.sh \u0026\u0026 bash tests/coalesce_smoke.sh \u0026\u0026 bash tests/keepalive_smoke.sh\n\n# live (funded DEEPSEEK_API_KEY, a few cents):\nbash e2e/run_claude_code.sh    # one real CC task\nbash e2e/run_full_suite.sh     # every feature, asserted\npython3 e2e/tool_order_ab.py   # the decisive bare-vs-Permafrost test\n```\n\n## Credits\n\nGeneralizes techniques from **[DeepSeek-Reasonix](https://github.com/esengine/DeepSeek-Reasonix)**\n(prefix-cache discipline, `prompt_cache_hit_tokens` accounting) and\n**[Headroom](https://github.com/chopratejas/headroom)** (proxy interception,\ncanonical forwarding, the `ENABLE_TOOL_SEARCH` finding). Where Headroom's\nCacheAligner *detects* volatile content, Permafrost *rewrites* it. Compared to\nCCR / LiteLLM / Headroom / Reasonix: [`docs/landscape.md`](docs/landscape.md).\n\nMIT — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjianzhichun%2Fpermafrost","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjianzhichun%2Fpermafrost","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjianzhichun%2Fpermafrost/lists"}