Getting Started
Install, then run distil onboard — one command that detects your agent (Claude Code, Codex, Gemini CLI) and billing, wires the savings status line, and hands you the exact next steps. No code change. Prefer to kick the tyres first? distil bench certifies the numbers offline with no API key.
Install
Distil ships as a PyPI package (distil-llm) with a stdlib-only core — zero runtime dependencies. The corpus is bundled in every distribution.
distil onboard ensures you have everything — if you run it ephemerally it installs distil permanently, then wires the status line, routes your agent, and offers to make distil the default. One command (needs uv):
uvx --from distil-llm distil onboard # sets up everything — incl. a permanent install
Prefer pipx? pipx install distil-llm && distil onboard. Just want to see it prove itself first? distil bench runs the certified gate in ~10s, no API key. Everything else below is an alternative, not a requirement.
distil-llm but the command is distil (the bare distil name was taken on PyPI). So it's pipx install distil-llm → run distil …. pipx install distil installs the wrong thing.
pip install with error: externally-managed-environment (PEP 668). Every method below is isolated and safe.
Could not find a version that satisfies the requirement distil-llm (from versions: none)?
The package is on PyPI — that error means your pip/pipx is on a Python below the package floor. Distil supports Python 3.9+ (what macOS ships), so a current install just works; on an even older Python, let uv provision one: uvx --python 3.12 --from distil-llm distil bench (or uv tool install --python 3.12 distil-llm). Check yours with python3 --version.
0.25.1) instead of the latest?
Run pip index versions distil-llm — if the list stops short of the PyPI latest (or has gaps), your pip/pipx is resolving against a private/mirror index (Artifactory / CodeArtifact / Nexus) that hasn't synced the newest releases, or a <1.0 pin in a constraints file. Unblock now by forcing public PyPI:
pipx install --pip-args="--index-url https://pypi.org/simple/" distil-llmOr install a specific version (a pull-through mirror will fetch it on demand):
pipx install "distil-llm==1.6.2". To keep using the mirror, ask your platform team to sync distil-llm — it exists upstream. Check config with pip config list and env | grep -i pip.
uvx
Run straight from PyPI, no install step. Prereq: uv.
uvx --from distil-llm distil bench
pipx
Permanent install in its own venv — PEP 668-safe. Prereq: Python 3.9+, pipx (brew install pipx).
pipx install distil-llm distil certify
Homebrew
Installs into an isolated keg — doesn't touch your Python. Prereq: Homebrew and git (third-party taps are cloned with git — run brew install git if you see Error: Git is unavailable).
brew install dshakes/tap/distil distil bench
Docker
Reproducible image, ideal for CI or sandboxed environments. Prereq: Docker.
docker build -t distil . docker run distil bench
Zipapp (.pyz)
One portable executable — copy it anywhere. Prereq: Python 3.9+ (no install).
make pyz python dist/distil.pyz bench
pip
For embedding the library in your own project. Prereq: an active virtualenv.
python3 -m venv .venv && source .venv/bin/activate pip install distil-llm
distil proxy (or distil wrap -- <your-agent>) and point your SDK's baseURL at it. No code changes, any language. The CLI needs Python 3.9+; your app does not.
Use it on your agent — the 30-second path
Easiest: let distil onboard set you up and hand you the exact commands for your environment — it detects your agent and billing, wires the status line, and prints a guided tour:
distil onboard # one command: detects your setup, wires the status line, guides you
Or do it by hand. distil wrap launches your coding agent with its API traffic routed through compression — no config, no code change.
# Claude Code on a metered API key — saves real $$: distil wrap --expand -- claude # Claude Code on a Pro/Max subscription — flat-rate, ToS-safe (trims context, not $): distil wrap --lossless-only -- claude # Codex, Gemini CLI, or any agent — same pattern: distil wrap --expand -- codex
Then watch genuine, measured savings from your traffic (not estimates):
distil leaderboard # cumulative tokens + $ saved, from the local ledger distil dashboard # live terminal TUI — token-trim + decision-equiv bars, Ctrl-C to exit distil doctor # diagnose your setup: ledger, shadow, proxy self-test, wiring
Wire the status line in one step with distil setup. The status line and distil dashboard auto-detect a flat-rate Claude subscription — the per-token dollar figure is notional, so it's dropped and the token reduction leads (override with DISTIL_SUBSCRIPTION=0/1). Inside Claude Code, /distil-stats, /distil-shadow, /distil-dashboard, and /distil-doctor surface this on demand.
Tired of typing distil wrap each session? Make it the default — once:
distil default # managed shell alias so `claude` always routes through distil distil default --always-on # or a persistent proxy service covering every SDK distil offboard # later: remove distil's footprint (alias, service, status line) before uninstalling
distil default detects your shell (zsh / bash / fish / PowerShell) and billing mode, writes the right line to the rc file your shell actually reads, and tells you what it detected; distil default --undo reverses it. distil offboard is the clean inverse of onboarding — it undoes each piece (asking first), keeps your savings ledger unless --purge, and prints the right uninstall command. See the CLI reference for both.
Billing-grade tokenizer (optional)
The default tokenizer is an offline heuristic — compression ratios are robust, but absolute dollar figures are approximate. For billing-grade token counts and live-model certification, install the live extra:
# with pipx (isolated): pipx install 'distil-llm[live]' # or one-off with uvx: uvx --from 'distil-llm[live]' distil certify --runner anthropic export ANTHROPIC_API_KEY=sk-ant-… distil savings --tokenizer anthropic distil certify --runner anthropic
Validate it preserved your outcomes
Compression is only safe if your agent makes the same decision it would have on full context. --shadow proves that on your live traffic: it samples a fraction of requests and runs each one twice — once compressed, once with the full prompt — then compares the agent's chosen next action (the tool call it decides to make), not the prose. The two are decision-equivalent when those signatures match.
distil wrap --shadow 0.1 -- claude # one command: wraps your agent + shadows 10% distil shadow-stats # live decision-equivalence rate (or /distil-shadow)
The rate also shows in the status line once shadow has samples — read it as “of the requests I checked, N% produced the identical next action with vs without compression.” Start at 0.1; if equivalence holds high, dial compression up — if it dips, back off. Distil fails safe to full context.
Honest scope: this certifies next-action equivalence — a proxy, not end-to-end task success. On real SWE-bench Verified (E7) the proxy does not fully transfer once compression gets aggressive — which is exactly why you monitor the live rate and keep the gate conservative.
60-second quickstart
Three commands cover the core workflow. All run against the bundled multi-domain corpus — no API key required. Run them in order the first time: bench to confirm savings and the gate pass, certify to inspect a single strategy, prune to see what's actually free to drop.
1. Benchmark savings across 7 domains
distil bench is the corpus-wide CI gate. It prices four strategies, certifies Distil is non-inferior on every trajectory, and confirms the gate rejects the aggressive lossy strategy. Run this in CI to catch any regression.
$ distil bench corpus gate — 7 trajectories | model claude-opus-4-8 | tokenizer=heuristic domain trajectory $ saved distil aggr pruned --------------------------------------------------------------------------- ops/sre sre-disk-incident 33.1% PASS FAIL 615 coding coding-bugfix 28.7% PASS FAIL 736 support support-refund 32.6% PASS FAIL 765 research research-synthesis 25.7% PASS FAIL 809 data-analysis data-analysis-sql 18.1% PASS FAIL 965 devops devops-rollback 25.0% PASS FAIL 857 finance finance-reconcile 29.1% PASS FAIL 1014 --------------------------------------------------------------------------- aggregate: distil cuts $0.14212 -> $0.10402 (26.8% cheaper) reversibly; 5761 tokens causally prunable. GATE: PASS — every trajectory certified non-inferior; aggressive rejected on all.
2. Certify a strategy
Run the TOST non-inferiority gate on a single trajectory and strategy. Exits 0 on pass, 1 on fail — plug it directly into any CI pipeline.
$ distil certify --strategy distil certifying strategy 'distil' on 'sre-disk-incident' (runner=deterministic) turn 0: ok turn 1: ok turn 2: ok turn 3: ok decision-equivalence match rate: 100.0% TOST non-inferiority (margin=0.02, alpha=0.05): mean diff=+0.000, p=0.0000 VERDICT: PASS (certified non-inferior)
3. Discover causally inert blocks
distil prune ablates each context block, replays the trajectory, and identifies what never changed a decision. Those blocks are provably free to drop — not heuristically likely, provably safe.
$ distil prune causal ablation over 'sre-disk-incident' — what is free to drop? block occ tokens verdict doc-0 4 312 PRUNE (causally inert) doc-1 4 303 PRUNE (causally inert) obs-0 4 234 keep (changed a decision) obs-1 4 198 keep (changed a decision) system 4 218 keep (changed a decision) tokens provably free to drop: 615 across 2 block(s).
Drop-in adoption: wrap(client)
The fastest path to production compression — no changes to your call sites. Wrap your existing Anthropic client once and every subsequent messages.create call is transparently compressed and cache-pinned.
import anthropic from distil.adapters.anthropic import wrap # One-line drop-in — no call-site changes needed client = wrap(anthropic.Anthropic()) # Works exactly like the original client response = client.messages.create( model="claude-opus-4-8", max_tokens=1024, system="You are a helpful assistant.", messages=[{"role": "user", "content": "Analyse this log output…"}], )
The wrapper applies Tier-0 lossless transforms (JSON minification, run-length collapse) and Tier-1 reversible digests to large tool results. It also pins the stable system prefix for cache-control so repeated calls get the ~10× cache-read discount automatically.
messages.create(**kwargs) method. It imports nothing from the Anthropic SDK itself, so it also works in test environments where the SDK is not installed.
Alternative: provider proxy
Prefer a network-level approach that works with any SDK, framework, or language? See the Adapters page for distil proxy.
Use it on your workflow — recipes
Pick the row that matches you. Every command is real; watch it work with distil leaderboard (genuine cumulative savings) and the x-distil-* response headers.
Coding agents — Claude Code · Codex · Gemini CLI
Wrap the agent; its traffic routes through compression with zero code change.
# subscription/OAuth-safe (ToS-safe, no tool injection) distil wrap --lossless-only -- claude # interactive: model sees content un-digested (Tier-0 only) distil wrap --lossless-only --verbatim -- claude # PAYG: aggressive reversible digest; the model recovers detail on demand distil wrap --expand -- claude # coding sessions with re-reads: send the diff, not the whole file distil wrap --session-delta -- claude
Any SDK app — chatbots, RAG, agents, batch (non-coding)
# standalone proxy — point any base_url SDK at it, any language distil proxy distil proxy --upstream https://generativelanguage.googleapis.com # Google Gemini
# or in-process, no sidecar (LiteLLM / LangChain) from distil.integrations import litellm as distil_litellm distil_litellm.completion(model="claude-opus-4-8", messages=[...])
See it, prove it, get more out of it
| Goal | Command |
|---|---|
| Set up + a guided tour (start here) | distil onboard |
Make distil the default (no per-session wrap) | distil default · undo distil default --undo |
| Remove distil's footprint (before uninstalling) | distil offboard · clear data distil offboard --purge |
| Diagnose your setup (ledger, shadow, proxy self-test, wiring) | distil doctor |
| Wire the savings status line into Claude Code | distil setup |
| Watch genuine savings accumulate | distil leaderboard · live TUI distil dashboard |
| Live decision-equivalence on real traffic | distil wrap --shadow 0.1 -- claude → distil shadow-stats |
| Certify on your domain | distil ingest --input prod.jsonl --out ./mycorpus → distil conformal --corpus ./mycorpus |
| Let agents recover digested detail (MCP) | distil mcp — exposes distil_compress/_expand/_savings |
| Live savings in your Claude Code status line | install the plugins/distil plugin → distil statusline |
| Self-improving keep policy | distil learn / distil online (flywheel; only ever gets more conservative) |
--lossless-only (add --verbatim). PAYG / autonomous → default digest (add --expand). Coding sessions with re-reads → add --session-delta.
What to read next
- Concepts — why decision-equivalence beats byte-equivalence, how the certificate works, and why cache misses (not token size) dominate cost.
- Techniques — every compression technique in depth: cache stabilization, causal pruning, recoverable compression, cross-turn dedup, and more.
- Benchmark — the live head-to-head against real installed packages (LLMLingua-2, Headroom), graded by
claude-opus-4-8. - CLI Reference — every flag and sample output for all commands.