compression with a quality contract

CLI Reference

Every subcommand, its flags, and a real sample output. All commands work offline with zero API key — the bundled corpus is self-contained.

Global flag: distil --version prints the installed version.
Default trajectory: when --trajectory is omitted, the bundled sre-disk-incident sample trajectory is used.

distil bench

The corpus-wide CI gate. Iterates over all 7 trajectories, prices four strategies, runs the TOST non-inferiority gate on each, and confirms aggressive lossy compression is still rejected. Exits 0 only if every trajectory passes.

Flags

FlagDefaultDescription
--tokenizerheuristicheuristic (offline, zero deps) or anthropic (billing-grade count_tokens)
--pricingclaude-opus-4-8Model pricing to use (see pricing catalog)
--margin0.02TOST indifference margin (max tolerable mean score drop)
--alpha0.05Significance level for the non-inferiority test
--recordoffAppend corpus-aggregate savings to the local savings ledger
--corpusbundled corpusRun on a custom corpus dir (e.g. from distil ingest)
--savings-onlyoffReport token savings only; skip the decision-equivalence gate (for real-trace corpora without DECISION labels)
$ 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) losslessly; 5761 tokens prunable.

GATE: PASS — every trajectory certified non-inferior; aggressive rejected on all.

distil savings

Price four compression strategies on a single trajectory and show per-strategy cost, savings percentage, and cache hit tokens. The key result: naive compress + cache costs more than baseline because it busts the prefix cache.

Flags

FlagDefaultDescription
--trajectory, -tbundled samplePath to a trajectory JSON file
--tokenizerheuristicheuristic or anthropic (billing-grade)
--pricingclaude-opus-4-8Model pricing to use
--output-tokens-per-turn0Assumed output tokens per turn (for output cost accounting)
--recordoffAppend this run to the local savings ledger
$ distil savings --pricing claude-opus-4-8
model claude-opus-4-8   |   4 turns   |   tokenizer=heuristic (≈, not billing-grade)

strategy                               $ / run   vs baseline  cache hits
------------------------------------------------------------------------
baseline (no cache, no compress)       0.01524          0.0%           0
cache only                             0.01115         26.8%       1,028
naive compress + cache                 0.01691        -11.0%           0
distil (cache-aware lossless)          0.01019         33.1%       1,028
------------------------------------------------------------------------
distil cuts $0.01524 -> $0.01019 per run (33.1% cheaper), losslessly.
note: naive compression costs $0.01691 — 66% MORE than distil despite fewer tokens,
      because it busts the prefix cache.

distil certify

Run the TOST non-inferiority gate on a single trajectory and strategy. Exits 0 on PASS, 1 on FAIL. Use this as the unit-level quality check; use bench for the corpus-wide gate.

Flags

FlagDefaultDescription
--trajectory, -tbundled samplePath to a trajectory JSON file
--strategydistilStrategy to certify: distil, aggressive, naive, none
--runnerdeterministicdeterministic (offline, uses ground-truth markers) or anthropic (live model, requires key)
--margin0.02TOST indifference margin
--alpha0.05Significance level
$ 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)

$ distil certify --strategy aggressive
certifying strategy 'aggressive' on 'sre-disk-incident' (runner=deterministic)

  turn 0: DIVERGED
      baseline:   use_tool(bash, {"cmd":"df -h /"})
      compressed: use_tool(bash, {"cmd":"ls /"})
  turn 1: DIVERGED
  turn 2: DIVERGED
  turn 3: DIVERGED

decision-equivalence match rate: 0.0%
TOST non-inferiority (margin=0.02, alpha=0.05): mean diff=-1.000, p=1.0000

VERDICT: FAIL  (NOT certified — would degrade quality)

distil prune

Causal ablation: for each context block, remove it and replay the trajectory. Blocks that never change a decision are causally inert — provably free to drop.

Flags

FlagDefaultDescription
--trajectory, -tbundled samplePath to a trajectory JSON file
$ 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).

distil compress

Apply the distil strategy to a trajectory turn by turn and report the per-turn token reduction and overall reversibility status.

Flags

FlagDefaultDescription
--trajectory, -tbundled samplePath to a trajectory JSON file
--tokenizerheuristicheuristic or anthropic
$ distil compress
trajectory 'sre-disk-incident'  (4 turns, tokenizer=heuristic)

turn    before     after   saved
   0      1824      1312   28.1%
   1      1956      1401   28.4%
   2      2108      1518   28.0%
   3      2340      1689   27.8%

 ALL      8228      5920   28.1%

reversible: yes (Tier-0/1) — 3 blocks digested, originals recoverable locally

distil verify

Byte-fidelity gate: confirms every Tier-0/1 compression across the corpus is byte-reversible, and that frozen history never mutates between turns (append-only invariant). Exits 0 only if all checks pass.

No flags. Runs across the full bundled corpus.

$ distil verify
byte-fidelity gate — reversibility + append-only across the corpus

  sre-disk-incident        reversible + append-only: ok
  coding-bugfix            reversible + append-only: ok
  support-refund           reversible + append-only: ok
  research-synthesis       reversible + append-only: ok
  data-analysis-sql        reversible + append-only: ok
  devops-rollback          reversible + append-only: ok
  finance-reconcile        reversible + append-only: ok

FIDELITY: PASS — Tier-0/1 byte-reversible and history append-only across the corpus.

distil validate

Adversarial real-path gate. Where verify and bench check the bundled corpus, validate drives the compressor itself against a battery of diverse and hostile inputs — huge and unicode and deeply-nested tool output, malformed blocks, marker-injection (content that mimics distil's own << handle=… >> stubs), and secret-looking strings — and asserts the load-bearing guarantees hold on every one:

This is the layer that catches real-traffic bugs a green unit suite misses. Runs in CI on every push; exits non-zero on any violation.

$ distil validate
distil validate — adversarial real-path invariant harness

VALIDATE: PASS — 60/60 checks across 12 adversarial cases (reversibility · reject-if-bigger · recency · fail-open · content-free).

distil holdout

Holdout A/B savings measurement. Partitions the corpus into a control group (held out, not counted toward the headline) and a treatment group, reports savings with a bootstrap 95% confidence interval.

Flags

FlagDefaultDescription
--tokenizerheuristicheuristic or anthropic
--pricingclaude-opus-4-8Model pricing to use
--control-fraction0.2Fraction of corpus held out as control group
$ distil holdout
holdout A/B savings measurement (deterministic partition + bootstrap CI)

  treatment savings: 27.4% [95% CI: 24.1%–30.8%]
  control group mean savings: 26.1% (held out, not counted toward the headline)

distil reset

Archives the savings ledger to savings.jsonl.reset-<utc-timestamp> (non-destructive — history stays on disk for audit) so the statusline and distil stats restart from zero on current accounting (records booked only after a confirmed upstream 2xx). Use it when a ledger is dominated by pre-1.10 records, whose savings may be overstated — distil stats warns when that is the case. --shadow also archives and resets the decision-equivalence counter.

$ distil reset
savings ledger archived → ~/.distil/savings.jsonl.reset-20260705-213313Z
  651 runs, 114,079,320 tokens saved (643 pre-1.10 records) — kept for audit, no longer counted
fresh start: all new records use post-1.10 accounting (booked only after upstream 2xx).

distil leaderboard

Shows cumulative savings from all runs recorded via --record flags on savings and bench, plus genuine traffic recorded by distil proxy/wrap. Local-first; no data leaves the machine unless you opt in to community sharing (not currently enabled). Aliased as distil stats — both names run the identical command. If the ledger contains pre-1.10 records (booked before upstream success — savings may be overstated), the output says so and points to distil reset.

Flags

FlagDefaultDescription
--htmloffRender your savings ledger as a self-contained HTML page at this path
--jsonoffMachine-readable output: the full savings summary plus decision-equivalence/shadow-sample counts when shadow data exists
$ distil leaderboard
distil savings ledger — ~/.local/share/distil/ledger.jsonl

runs recorded:        12
total tokens saved:   42,816
total dollars saved:  $0.51234

by trajectory:
  corpus-aggregate             $0.38112
  sre-disk-incident            $0.13122

(local-first; community sharing is opt-in and not enabled.)

distil dissect

Everything Distil knows about one wrap session, in a single report — or a picker when no session id is given. Leads with a plain-language "what happened", then drills into savings by model and by mechanism (digest vs cache-delta), the digest inventory (blocks by kind, largest folds, re-fold churn, restore recoverability), billed usage captured from API responses with a heuristic-calibration figure, latency by path (the --expand buffering tax as a measured number), and a "worth your attention" anomaly list that auto-detects silent-failure signatures (proxy bypass, a shadow that is configured but recording nothing, an expand path that never intercepts). Session telemetry is content-free (sizes, hashes, token counts — never prompt or response text) and written fail-open, off the request path. Optional --transcript correlation names tools/files/prompts by joining the session with the agent's own log; everything else stays content-free.

$ distil dissect            # pick a recent session
$ distil dissect s4821-3 --html report.html
$ distil dissect --serve       # localhost portal, all sessions

distil proxy

HTTP proxy that applies Distil compression to every LLM API request passing through it. Drop-in for any client that honours a base_url parameter — Anthropic SDK, OpenAI SDK, LiteLLM, LangChain, etc. As real traffic flows through it, the actual per-request token reduction is accumulated into your local ledger (see distil leaderboard) — genuine savings, numbers only, never content.

Flags

FlagDefaultDescription
--host127.0.0.1Interface to bind on
--port8788Port to listen on
--upstreamhttps://api.anthropic.comReal LLM API base URL to forward to
--lossless-onlyoffPolicy mode: Tier-0 verbatim only — no lossy output-shaping, no tool injection (--expand), no Tier-1 digest stubs. Folds directly into verbatim (no separate --verbatim needed). Use for subscription / OAuth sessions.
--verbatimoffSkip the Tier-1 digest; Tier-0 only (JSON minify + collapse exact-duplicate runs). Interactive-safe, lower savings. Use where distil_expand recovery is unavailable.
--shape-outputoffEnable generation-side verbosity shaping: light (conservative) or aggressive. Injects a role:"system" directive before the request. Gated by --lossless-only: shaping is skipped when --lossless-only is set. No subscription key detection.
--expandoffInject the distil_expand tool so the model can pull digested blocks back on demand
--shadowoff (direct use; distil wrap defaults to 0.02)Shadow-mode sampling rate (0–1): re-run a fraction of requests uncompressed to measure live decision-equivalence. --shadow 0 disables; --shadow 1.0 = full-sampling validation (~3× tokens — prove equivalence in minutes, then drop back).
--session-deltaoffEnable cross-turn cache-delta encoding (deduplicates repeated stable blocks across the session)
--asyncoffUse the async aiohttp backend (distil/aproxy.py) for high-concurrency streaming. Requires pip install 'distil-llm[async]'. Async event loop handles thousands of concurrent sessions. Note: the async backend supports lossless / verbatim / output-shaping, but not --expand, --session-delta, or --shadow yet — pass those on the standard (sync) proxy, which handles typical agent concurrency. Combining them with --async prints a notice and ignores them.
--pricingclaude-opus-4-8Model used to price the genuine dollar savings recorded to the ledger
--no-recordoffDo not record genuine savings to the local ledger
$ distil proxy --port 8788 --upstream https://api.anthropic.com
distil proxy listening on http://127.0.0.1:8788
  → upstream: https://api.anthropic.com
  → recording genuine savings → distil leaderboard

Point your SDK at the proxy:

# Anthropic SDK
client = anthropic.Anthropic(base_url="http://localhost:8788")

# OpenAI-compatible client
client = openai.OpenAI(base_url="http://localhost:8788/v1")

# LiteLLM
response = litellm.completion(api_base="http://localhost:8788", ...)

The proxy adds up to 9 response headers (not all appear on every request):

All other paths and HTTP methods are forwarded unchanged.

See Adapters for the full story on in-process vs. proxy adoption.

distil wrap

The zero-config way to route an existing agent or CLI through Distil. distil wrap starts the proxy on an ephemeral local port, injects the right env var into the child process's environment, runs your command to completion, then tears the proxy down — flushing genuine savings to your ledger and printing the Proof Ledger on exit. No code change, no manual env wiring, no leftover server.

Per-agent presets — when the command name is claude, codex, gemini, or aider, distil auto-selects the env var and upstream endpoint for that agent. A preset: <agent> detected → <VAR> line confirms the selection at startup. Explicit --env-var and --upstream always override the preset. cursor-agent is deliberately omitted — its env var is undocumented upstream; use --env-var to configure it manually.

# claude → ANTHROPIC_BASE_URL auto-set
$ distil wrap -- claude -p "summarize this repo"
distil wrap → proxy http://127.0.0.1:54xxx (upstream https://api.anthropic.com)
  preset: Claude Code detected → ANTHROPIC_BASE_URL
  → ANTHROPIC_BASE_URL=http://127.0.0.1:54xxx

# codex → OPENAI_BASE_URL auto-set; gemini → GOOGLE_GEMINI_BASE_URL
$ distil wrap --expand -- codex
$ distil wrap --expand -- gemini

# Lossless-only policy mode (subscription / OAuth)
$ distil wrap --lossless-only -- my-agent --task build

# Any other agent — specify the env var explicitly
$ distil wrap --env-var MY_BASE_URL --upstream https://api.example.com -- my-agent

Everything after -- is the command and its arguments, run verbatim. The child's exit code is propagated. Use --env-var to point a different variable at the proxy (e.g. an OpenAI-compatible tool), and the same --upstream, --lossless-only, --verbatim, --shape-output, --pricing and --no-record flags as distil proxy. On clean exit (and Ctrl-C), the Proof Ledger is printed to stderr.

Flags

FlagDefaultDescription
--host127.0.0.1Bind address for the ephemeral proxy
--upstreamhttps://api.anthropic.comReal LLM API base URL to forward to
--env-varANTHROPIC_BASE_URLEnvironment variable to point at the proxy in the child process
--lossless-onlyoffPolicy mode: Tier-0 verbatim only — no lossy output-shaping, no tool injection (--expand), no Tier-1 digest stubs. Folds directly into verbatim (no separate --verbatim needed). Use for subscription / OAuth sessions.
--verbatimoffSkip the Tier-1 digest; Tier-0 only. Interactive-safe, lower savings.
--shape-outputoffGeneration-side verbosity shaping (gated by --lossless-only)
--pricingclaude-opus-4-8Model used to price genuine dollar savings recorded to the ledger
--no-recordoffDo not record genuine savings to the local ledger
--expandoffInject the distil_expand tool so the model can pull digested blocks back on demand
--shadow0.02 (2%, opt-out)Fraction of requests re-issued uncompressed to measure live decision-equivalence. --shadow 0 disables; --shadow 1.0 = full-sampling validation (~3× tokens — proves equivalence fast, use then drop back). See status line for how to read the de segment.
--session-deltaoffEnable cross-turn cache-delta encoding

Proof Ledger (automatic on wrap exit)

The Proof Ledger is printed automatically to stderr at the end of every distil wrap session (clean exit or Ctrl-C). It is silent when no requests were proxied. Opt out with DISTIL_NO_LEDGER=1.

  distil proof ledger — session 47m
    tokens   84,213 → 62,440   (25.9% smaller)
    cost     $0.42 → $0.31        calibrated to your billed usage (n=58, ±2.1%)
    shadow   0 decision changes    (n=12 A/B, 8 A/A — below verdict threshold, gathering)
    restore  100% recoverable    (3 digests, all handles live, TTL 14d)

All numbers come from the same on-disk sources as the leaderboard — no new estimators. The shadow line respects the verdict-threshold gates (VERDICT_MIN_AB=50, VERDICT_MIN_AA=30): below threshold it shows sample counts with a "gathering" label rather than claiming equivalence over thin evidence. The cost line shows "calibrated to your billed usage (n=N, ±X%)" once enough proxy traffic has accumulated to correct the heuristic; "estimated · calibrating (N/20 samples)" until then. The restore line checks that every handle written this session is still live (not expired past DISTIL_RESTORE_TTL_DAYS).


distil output-savings

Measure the realized output-token reduction from --shape-output. Reads a JSONL file of {"baseline": ..., "shaped": ...} pairs and reports the A/B result with a bootstrap 95% confidence interval.

Flags

FlagDefaultDescription
--inputbundled fixturePath to a JSONL file of {"baseline": ..., "shaped": ...} pairs
$ distil output-savings --input shaped_pairs.jsonl
output-token A/B — n=8 turns

  baseline mean output tokens:   487
  shaped   mean output tokens:   134

  reduction: 72.5%  [95% CI: 67.5%–77.1%]  (illustrative)
  answer preserved: 100%  (semantic match gate, n=8)

distil ingest

Convert a recorded Anthropic or OpenAI request log (JSONL) into a Distil trajectory. One input file produces one trajectory — there is no session grouping. Real-trace corpora have no DECISION labels, so the offline gate is savings-only; certify quality live with distil certify --runner anthropic.

Flags

FlagDefaultDescription
--inputrequiredPath to the JSONL log file (Anthropic or OpenAI request format)
--out./ingested-corpusOutput directory where the trajectory will be written
--provideranthropicanthropic or openai — selects the input format
--modelclaude-opus-4-8Model name to tag the trajectory with (must be in the pricing catalog)
$ distil ingest --input prod.jsonl --out ./mycorpus
ingesting prod.jsonl → ./mycorpus

corpus written to ./mycorpus/

$ distil bench --corpus ./mycorpus --savings-only
corpus gate — savings-only (no DECISION labels)

  aggregate savings: 28.3%  [95% CI: 25.1%–31.6%]
  note: certify with --runner anthropic for a live quality gate.

distil perf

Throughput benchmark: measures raw distil-compression rate and in-process adapter latency. Runs a tight loop of compress() calls with the bundled trajectory and reports throughput (ops/sec) and p50/p95/p99 latency.

Flags

FlagDefaultDescription
--iterations200Number of compression iterations to run
$ distil perf
distil performance benchmark

  compressor throughput:   ~27,000 distil-compressions/sec
  in-process adapter p50:  0.006 ms
  in-process adapter p95:  0.011 ms
  in-process adapter p99:  0.018 ms

  (measured on Apple M-series, CPython 3.12, bundled sre-disk-incident trajectory)

distil gateway

Managed multi-tenant HTTP gateway with per-tenant token and dollar accounting, a live auto-refreshing dashboard at /distil/dashboard, and a JSON stats API at /distil/stats. Extends the basic proxy with tenant identification and savings attribution. Default port is 8789 (distinct from distil proxy's 8788).

Flags

FlagDefaultDescription
--host127.0.0.1Interface to bind on. Pass 0.0.0.0 for network-accessible deployments.
--port8789Port to listen on.
--upstreamhttps://api.anthropic.comReal LLM API base URL (set once at startup, cannot be overridden per-request).
--pricingclaude-opus-4-8Model pricing key for per-tenant dollar accounting.
--lossless-onlyoffPolicy mode: Tier-0 verbatim only — no lossy output-shaping, no tool injection (--expand), no Tier-1 digest stubs. Folds directly into verbatim (no separate --verbatim needed). Use for subscription / OAuth sessions.
--verbatimoffSkip the Tier-1 digest; Tier-0 only. Interactive-safe, lower savings.
--admin-tokenunset (env DISTIL_GATEWAY_TOKEN)Bearer token required for /distil/stats and /distil/dashboard. Mandatory for those routes on non-loopback binds — without it, /distil/* is disabled entirely rather than left open.
--trust-tenant-headeroffHonor the client-supplied x-distil-tenant header for accounting. Off by default: tenant identity is derived from the credential hash, never a client-writable header, so no caller can book its traffic under another tenant's line.
$ distil gateway --port 8789 --upstream https://api.anthropic.com
distil gateway listening on http://127.0.0.1:8789
  dashboard: http://127.0.0.1:8789/distil/dashboard
  → upstream: https://api.anthropic.com

Tenant identification: by default, a stable anonymized key hash (anon-<sha256(credential)[:8]>) derived from x-api-key or authorization, falling back to "default" when no credential is present. The client-supplied x-distil-tenant header is ignored unless the operator opts in with --trust-tenant-header — otherwise any caller could write that header and book its usage under a different tenant's accounting line. Raw API keys are never stored or logged.

$ curl -s http://127.0.0.1:8789/distil/stats | python3 -m json.tool
{
  "tenants": [
    {
      "tenant": "team-search",
      "requests": 142,
      "tokens_saved": 52416,
      "dollars_saved": 0.026208,
      "pct_saved": 28.44
    }
  ],
  "totals": {
    "requests": 142,
    "tokens_saved": 52416,
    "dollars_saved": 0.026208,
    "pct_saved": 28.44
  }
}

See Deploy & Security → Managed gateway for the full deployment guide including multi-tenant setup and security model.

distil gateway keys

Issue, list, and revoke dsk- gateway keys for inbound auth. Keys are stored hashed (SHA-256) — the gateway never keeps the raw secret. Auth fails closed: a bad or missing key returns 401. The upstream (Anthropic / OpenAI key) is never exposed to callers.

Key auth is active when at least one key has been issued, or when the gateway starts with --require-keys. Without keys and without --require-keys, the default anonymous hash-based tenant IDs still work.

# Issue a key for a tenant (prints the dsk- secret once — store it)
$ distil gateway keys issue --tenant team-search
Issued key for team-search:
  dsk-a3f9c2e18b4d7a...  (shown once — copy it now)

# List all issued keys (shows tenant, key prefix, created, last-used)
$ distil gateway keys list

# Revoke a key by its dsk- prefix
$ distil gateway keys revoke dsk-a3f9c2e1

# Start gateway requiring a key on every request
$ distil gateway --require-keys --upstream https://api.anthropic.com

# Per-tenant rate and quota limits (gateway-wide defaults)
$ distil gateway --tenant-rpm 60 --tenant-daily-tokens 1000000 \
    --upstream https://api.anthropic.com

gateway keys flags

FlagDefaultDescription
gateway --require-keysoffForce key auth even before any keys are issued.
gateway --tenant-rpm0 (unlimited)Gateway-wide requests-per-minute cap per tenant.
gateway --tenant-daily-tokens0 (unlimited)Gateway-wide daily input-token cap per tenant.
keys issue --tenant <name>requiredTenant label to associate with the new key.
keys revoke <prefix>requiredFirst hex characters of the key to revoke (as shown by keys list).

distil train-transformer

Fine-tune a token-classification transformer (default: google/bert_uncased_L-2_H-128_A-2, ~4 MB) for line keep/drop and export it to ONNX. Requires the train extras: pip install 'distil-llm[train]'. The resulting checkpoint is specific to your corpus text distribution — retrain on your own traces for best production results.

Default keep-model is the logistic classifier. The LogisticKeepModel (built-in, zero deps, 96.4% acc / 0.98 F1) is the default for all users. Run train-transformer only when you have a corpus of real traces and want to upgrade to the ONNX transformer adapter.

Flags

FlagDefaultDescription
--outdistil-keep-transformerOutput directory. Receives model.onnx, tokenizer files, and metrics.json.
--base-modelgoogle/bert_uncased_L-2_H-128_A-2HuggingFace model ID to fine-tune. Swap for distilbert-base-uncased for higher accuracy at larger size.
--epochs3Number of training epochs.
$ pip install 'distil-llm[train]'

$ distil train-transformer --out ./my-keep-model
Epoch 1/3  train_loss=0.4821
Epoch 2/3  train_loss=0.2134
Epoch 3/3  train_loss=0.1589
Exported ONNX to ./my-keep-model/model.onnx
Accuracy=0.9630  F1=0.9812
Load with: TransformerKeepModel.from_pretrained('./my-keep-model/model.onnx', './my-keep-model')

Output layout in --out directory:

A demo checkpoint trained on the bundled corpus (96.3% acc / 0.98 F1) is attached to the v0.1.0 release. See Techniques → Keep-model codec for the full design.


distil eval

The certified compression frontier — the proof artifact no competitor publishes. Sweeps compression aggressiveness levels, measures (token savings, decision-equivalence) per level over the corpus, and marks which are certified by the non-inferiority gate. Locates the cliff past which lossy compression starts dropping agent decisions, with distil sitting safely inside the certified region.

Flags

FlagDefaultDescription
--corpusbundled corpusCustom corpus dir (e.g. from distil ingest on benchmark traces)
--runnerdeterministicdeterministic (offline, structural equivalence) or anthropic (live model, requires API key)
--outoffWrite the raw curve as a timestamped JSONL file to this directory
$ distil eval
certified compression frontier  (runner=deterministic)

level                   savings   equiv  certified  curve
--------------------------------------------------------------------------
distil (cache-aware)       8.4%    100%    ✔ PASS   ██
truncate@1200              7.2%     79%       ✘ —    ██
truncate@700              20.0%     36%       ✘ —    ████
truncate@300              41.3%      0%       ✘ —    █████████
--------------------------------------------------------------------------

distil: 8.4% savings @ 100% decision-equivalence — certified.
certified ceiling: 8.4% savings (beyond this, lossy compression drops decisions and the gate rejects it).

See Research & Frontier → Certified compression frontier for the full design.


distil benchmark

Head-to-head against the competing technique families — sliding-window truncation, extractive importance pruning, abstractive summarization, naive minification — each a faithful reference implementation, all scored through the same decision-equivalence + non-inferiority gate and the same cache-aware cost model. Ranks by certified dollar savings; lossy methods that drop decisions are disqualified however much they saved. Register a real external tool to verify. See the Benchmark page for the standings and methodology.

Flags

FlagDefaultDescription
--externalmodule:function[:Name] — register a real compressor (list[str]→list[str] over per-turn block texts), measured on the identical axes. Repeatable.
--corpusbundled corpusCustom corpus dir (e.g. ingested benchmark traces)
--runnerdeterministicdeterministic (offline) or anthropic (live model)
--pricingclaude-opus-4-8Model pricing for the cache-aware cost model
--tokenizerheuristicheuristic or anthropic (billing-grade)
--margin0.02TOST non-inferiority margin
--alpha0.05Significance level for the non-inferiority test
--html / --outoffRender the standings as HTML / write raw results JSONL
$ distil benchmark
compression benchmark  (model=claude-opus-4-8, runner=deterministic, corpus gate)

technique                tok save  $ save  equiv  certified  reversible
---------------------------------------------------------------------------------
distil-causal               33.8%   37.4%   100%     ✔ PASS       lossy
truncate-tail               26.9%   33.0%    25%    ✘ fails       lossy
summarize                   19.7%   24.2%     0%    ✘ fails       lossy
distil-lossless              8.4%   10.3%   100%     ✔ PASS  byte-exact
extractive-prune             7.4%    9.0%    68%    ✘ fails       lossy
---------------------------------------------------------------------------------

LEADER (certified $ savings): distil-causal — 37.4% cheaper, 100% decision-equivalent.

distil frontier

The savings-vs-equivalence dial. 100% decision-equivalence is the certified-safe default; relax the target and Distil spends a bounded divergence budget (floor((1−target) × turns) turns) on the highest-value turns, falling back to byte-exact everywhere else. The trade is explicit and reported — never hidden. Trace the full curve with distil frontier.

Flags

FlagDefaultDescription
--targets1.0,0.97,0.95,0.90,0.80Comma-separated equivalence targets in (0,1]
--corpusbundled corpusCustom corpus dir
--runnerdeterministicdeterministic or anthropic (live model)
--samples3Majority-vote samples for the anthropic runner
$ distil frontier --corpus benchmarks/corpus_xl
savings-vs-equivalence dial  (runner=deterministic)

   target   achieved equiv  token savings   curve
----------------------------------------------------------------------
     100%             100%          58.1%   ████████████████
      95%             100%          58.1%   ████████████████
      80%              82%          62.9%   ██████████████████
----------------------------------------------------------------------

distil conformal

The Decision-Equivalence Risk Certificate (DERC). You choose a risk budget — a maximum decision-change rate α — and Distil certifies the most aggressive compression level whose risk is provably below it, distribution-free and finite-sample, via conformal risk control (Learn-Then-Test / Conformal Risk Control). Unlike the dial, this is a statistical guarantee with a confidence level, calibrated on your own traffic. See Research & Frontier → DERC.

Flags

FlagDefaultDescription
--alpha0.05Risk target: max tolerable decision-change rate
--delta0.05LTT failure probability; confidence is 1−δ (ignored by CRC)
--methodlttltt (high-probability bound) or crc (expected-rate bound)
--corpusbundled corpusCalibration corpus dir (use your own traffic via distil ingest)
--runnerdeterministicdeterministic or anthropic (live model)
--samples3Majority-vote samples for the anthropic runner
$ distil conformal --corpus benchmarks/corpus_xl --alpha 0.05
Decision-Equivalence Risk Certificate (DERC)

  method      : LTT  (Learn-Then-Test)
  risk target : α = 0.05  (max allowed decision-change rate)
  confidence  : 95%  (1 − δ)
  calibration : n = 320 turns,  runner = deterministic
----------------------------------------------------------------
  ✔ CERTIFIED  'lossless'  →  57.4% token savings

distil online

One self-distilling round: collects causal labels from your corpus (certified-safe drops discovered by the ablation engine), retrains the logistic keep-model, and promotes the new weights only if they pass the non-inferiority gate on every trajectory. Never-regressing by construction — a cycle that would degrade quality is silently discarded.

Flags

FlagDefaultDescription
--corpusbundled corpusCorpus dir of traffic to learn from. Use distil ingest to convert real logs first.
--promote-tooff (dry run)If certified, write the new weights as a LogisticKeepModel-compatible JSON file to this path.
$ distil online --corpus ./mycorpus --promote-to ./weights/keep_model.json
self-distilling round — keep-model learns from causal labels, gated by non-inferiority

  n_labels: 286
  accuracy: 0.873
  f1: 0.932
  certified: True
  promoted: True

See Research & Frontier → Self-distilling keep-model for the full loop design.


distil query-relevance

Query-aware salience, phase 2. Trains and certifies the learned semantic-relevance model from distil’s own expand flywheel — the content-free record of which digested block the agent pulled back, paired with the query live at digest time. It pins lines that answer the query without sharing a word with it (“what’s the retry limit?” → max_attempts = 5), on top of the phase-1 lexical keeps.

The model is additive-only (it can only widen the keep set, so reversibility and the decision-equivalence certificate are untouched) and gated: weights are promoted only if held-out recall beats the phase-1 lexical baseline at a precision floor. With no promoted weights, behavior is exactly phase 1. Collection runs automatically under distil wrap --expand; it stores only numeric feature vectors and expand outcomes — never a prompt, a line, or a query term.

Flags

FlagDefaultDescription
--min-samples200Minimum accumulated flywheel labels before a candidate is eligible for promotion.
$ distil query-relevance
query-aware salience (phase 2) — learn semantic line↔query relevance from the expand
flywheel; promote only if it beats the phase-1 lexical baseline (additive-only, safe)

  promoted: true
  recall: 0.910   baseline_recall: 0.520   precision: 0.880

distil federated-leaderboard

Build a verifiable federated savings leaderboard from HMAC-signed, content-free savings aggregates. Verifies each submission's signature and counts only certified savings toward headline totals — savings you can verify. No prompt or response text ever leaves the contributing instance.

Flags

FlagDefaultDescription
--dirrequiredDirectory containing submissions.jsonl (one signed aggregate per line)
--keysoffPath to a JSON file mapping instance_id → HMAC key. Submissions with no matching key are rejected.
--htmloffWrite a self-contained leaderboard HTML page to this path
$ distil federated-leaderboard \
    --dir ./submissions \
    --keys ./instance-keys.json \
    --html ./leaderboard.html
verifiable savings — 3 verified instance(s), 0 rejected

  totals (certified only): {'tokens_saved': 142816, 'dollars_saved': 0.071408, 'runs': 47, 'instances': 3}
  leaderboard html → ./leaderboard.html

See Research & Frontier → Verifiable federated telemetry for the signing model and ed25519 upgrade path.


distil certify-trajectories

The trajectory-level risk certificate — bounds end-to-end task degradation, not per-step decision-equivalence. Reads a JSONL of matched full/compressed task runs and certifies P(degradation risk ≤ alpha) ≥ 1-delta using Conformal Risk Control (Hoeffding–Bentkus), the invariant that transfers to real task success where per-step certificates (DERC) can't. See Concepts → The trajectory-level certificate for the full framing and honest assumptions.

Flags

FlagDefaultDescription
outcomesrequiredPath to a JSONL file of matched runs, one object per line: {"task_id": ..., "full_success": bool, "compressed_success": bool}
--alpha0.05Maximum end-to-end degradation risk to certify
--delta0.05Confidence budget — certificate holds at confidence 1−δ
--jsonoffMachine-readable output: the full certificate fields plus statement
$ distil certify-trajectories outcomes.jsonl --alpha 0.05 --delta 0.05
distil trajectory-risk certificate

  matched trajectories : 200
  observed degradation : 0.50%
  risk bound (1-δ)     : 3.20%
  certified (α=0.05, δ=0.05) : True

  With confidence 95%, compression degrades at most 5.0% of tasks the full
  context would have solved (observed 0.50% over 200 matched trajectories).
  Valid under: future trajectories exchangeable with calibration; loss =
  measured end-to-end task outcome; calibration held out from compressor
  tuning; recalibrate on drift

Refuses to certify (exit 1, not a false PASS) below min_n=20 matched trajectories — a certificate from a handful of samples is noise dressed up as a guarantee. Exits 0 only when certified is true.


distil onboard

One command to set up distil and learn to use it. Detects your environment — OS, package managers, agent CLIs (Claude Code / Codex / Gemini), how distil is installed, the optional anthropic extra, and whether you're on a flat-rate Claude subscription — then wires the savings status line and prints a next-steps guide tailored to what it found: how to route the detected agent (subscription-safe vs metered), validate outcomes with shadow mode, watch savings on the dashboard, run the test gate, and re-verify with distil doctor. --dry-run changes nothing; works on macOS and Windows.


distil default

Make distil the default for your agent so you don't type distil wrap every session. Writes a single managed, marked, backed-up, idempotent block to the shell rc distil detects for this machine — zsh (.zshrc), bash (.bashrc/.bash_profile), fish (config.fish), or PowerShell ($PROFILE) — using the correct syntax for each (alias / function / export / set -gx). An explicit $SHELL wins over file-existence guesses, and the command prints what it detected (shell, rc, agent, mode) rather than acting blind. --always-on instead installs a persistent proxy service (launchd / systemd) plus ANTHROPIC_BASE_URL so every base-URL-honoring SDK routes through distil — universal, but a daemon you keep alive and a single point of failure if it's down. --undo removes whichever is installed; --agent, --mode, --rc override the detected defaults. distil onboard offers it interactively.


distil offboard

Remove distil's footprint — the inverse of distil onboard. Undoes the shell default (the distil default alias/env block), stops and removes the always-on proxy service, and unwires the status line from Claude Code settings — asking before each (non-interactive without --yes removes nothing). Your savings ledger and shadow data are kept unless you pass --purge. It can't uninstall the running package itself, so it prints the exact uninstall command for how distil was installed (pipx / uv / pip). A foreign status line (one you set yourself) is left untouched.


distil dashboard

Live terminal dashboard of your cumulative savings — a framed panel with Unicode bars for token-trim and decision-equivalence, original → compressed tokens and cost, a recent-decisions strip, and per-trajectory bars. Uses the alternate screen (like htop): redraws in place and restores your prompt on exit. --once prints a single frame; --interval sets refresh seconds. On a flat-rate subscription the dollar figures are dropped automatically (DISTIL_SUBSCRIPTION overrides).


distil statusline

One compact line, designed to be a segment inside your own composite status line — every character earns its place:

# a proxy session is active (or was, within the last 4h)
distil · ▼75.0K −62% $0.31 · Σ27.0M

# no recent session — falls back to the lifetime figure
distil · Σ27.0M saved −50% $96.10

The status line opens with a mode chip showing which compression mode is active: ⬢ digest (neon cyan), ◇ lossless (green), or ▪ verbatim (dim). Example: distil · ⬢ digest · ▼5.7M · 39% smaller · total ▼460.9M · de 47/50.

is tokens saved and −N% the trim rate of the active scope — the current proxy session while one is live (last activity <4h ago), lifetime otherwise; Σ is the lifetime tokens-saved figure, shown as a compact suffix next to a live session or as the headline when idle. The dollar figure only appears on metered/PAYG billing (dropped entirely on a flat-rate subscription) and only when it's non-zero. Dropped by design: the orig→compressed pair (derivable from the trim %) and run counts. The de (decision-equivalence) segment appears as de n/50 while collecting shadow samples, then as de N.N% with a ✓/⚠/✗ verdict once 50 A/B samples + 30 A/A samples accrue (A/B = compressed-vs-original; A/A = same request replayed against itself — the sampling-noise baseline). Its color is alarm-only, not decoration — calm brand hue while ≥99%, warning under 99%, alarm under 95%. Full breakdown: distil stats / distil dashboard. Wire it with distil setup or the plugin.


distil shadow-stats

Report the live decision-equivalence measured by shadow mode on real traffic: the percentage of sampled requests where the agent's chosen next action was identical with vs without compression, and how many samples that's based on. Start sampling with distil wrap --shadow 0.1 -- claude.

Flags

FlagDefaultDescription
--jsonoffMachine-readable output: samples, changes, decision_change_rate, decision_equivalence

distil doctor

Diagnose a distil setup end-to-end: distil/Python version, the savings ledger (subscription-aware), shadow-validation status, an in-process proxy round-trip self-test (proves the proxy machinery works with no network), the optional anthropic extra and API key, and — for Claude Code — status-line wiring and subscription detection. Exits non-zero if any check fails, so it doubles as a setup gate.

Flags

FlagDefaultDescription
--no-coloroffDisable ANSI colors in the check list
--jsonoffMachine-readable output (CI-gateable): {"checks": [...], "ok": bool}, one object per check with name/status/detail/hint

distil setup

Wire the distil savings status line into Claude Code's settings.json in one step. Idempotent (no-op if already wired), never clobbers an existing status line without --force (which backs it up first), and preserves all other settings.


Full CI gate

$ make gate
# Runs: tests + corpus non-inferiority (distil bench) + byte-fidelity (distil verify)

pytest ... 181 passed in 4.2s
corpus gate: PASS
fidelity gate: PASS