# 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

Flag | Default | Description
--- | --- | ---
`--tokenizer` | `heuristic` | `heuristic` (offline, zero deps) or `anthropic` (billing-grade `count_tokens`)
`--pricing` | `claude-opus-4-8` | Model pricing to use (see pricing catalog)
`--margin` | `0.02` | TOST indifference margin (max tolerable mean score drop)
`--alpha` | `0.05` | Significance level for the non-inferiority test
`--record` | off | Append corpus-aggregate savings to the local savings ledger
`--corpus` | bundled corpus | Run on a custom corpus dir (e.g. from `distil ingest`)
`--savings-only` | off | Report 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

Flag | Default | Description
--- | --- | ---
`--trajectory, -t` | bundled sample | Path to a trajectory JSON file
`--tokenizer` | `heuristic` | `heuristic` or `anthropic` (billing-grade)
`--pricing` | `claude-opus-4-8` | Model pricing to use
`--output-tokens-per-turn` | `0` | Assumed output tokens per turn (for output cost accounting)
`--record` | off | Append 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

Flag | Default | Description
--- | --- | ---
`--trajectory, -t` | bundled sample | Path to a trajectory JSON file
`--strategy` | `distil` | Strategy to certify: `distil`, `aggressive`, `naive`, `none`
`--runner` | `deterministic` | `deterministic` (offline, uses ground-truth markers) or `anthropic` (live model, requires key)
`--margin` | `0.02` | TOST indifference margin
`--alpha` | `0.05` | Significance 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

Flag | Default | Description
--- | --- | ---
`--trajectory, -t` | bundled sample | Path 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

Flag | Default | Description
--- | --- | ---
`--trajectory, -t` | bundled sample | Path to a trajectory JSON file
`--tokenizer` | `heuristic` | `heuristic` 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 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

Flag | Default | Description
--- | --- | ---
`--tokenizer` | `heuristic` | `heuristic` or `anthropic`
`--pricing` | `claude-opus-4-8` | Model pricing to use
`--control-fraction` | `0.2` | Fraction 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 leaderboard

Shows cumulative savings from all runs recorded via `--record` flags on `savings` and `bench`. Local-first; no data leaves the machine unless you opt in to community sharing (not currently enabled).

### Flags

Flag | Default | Description
--- | --- | ---
`--html` | off | Render your savings ledger as a self-contained HTML page at this path

    $ 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 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

Flag | Default | Description
--- | --- | ---
`--host` | `127.0.0.1` | Interface to bind on
`--port` | `8788` | Port to listen on
`--upstream` | `https://api.anthropic.com` | Real LLM API base URL to forward to
`--lossless-only` | off | Policy mode: lossless strategies only — no lossy output-shaping, no tool injection (`--expand`). The reversible Tier-1 digest still runs. Use for subscription / OAuth sessions.
`--verbatim` | off | Skip 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-output` | off | Enable 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.
`--expand` | off | Inject the `distil_expand` tool so the model can pull digested blocks back on demand
`--shadow` | off | Shadow-mode sampling rate (0–1): re-run a fraction of requests uncompressed to measure live decision-change rate
`--session-delta` | off | Enable cross-turn cache-delta encoding (deduplicates repeated stable blocks across the session)
`--async` | off | Use the async aiohttp backend (`distil/aproxy.py`) for high-concurrency streaming. Requires `pip install 'distil-llm[async]'`. Same compression behavior; async event loop handles thousands of concurrent sessions.
`--pricing` | `claude-opus-4-8` | Model used to price the genuine dollar savings recorded to the ledger
`--no-record` | off | Do 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 8 response headers (not all appear on every request):

- `x-distil-compressed: 1` — compression was applied
- `x-distil-tokens-saved: <n>` — heuristic estimate of tokens saved
- `x-distil-expanded: 1` — present when `--expand` fired and a digest was resolved
- `x-distil-cache-refs: <n>` — total cache-delta references (with `--session-delta`)
- `x-distil-cache-delta: <n>` — delta-encoded references (with `--session-delta`)
- `x-distil-cache-tokens-saved: <n>` — tokens saved by cache-delta (with `--session-delta`)
- `x-distil-output-shaping: light|aggressive` — present when output shaping fired
- `x-distil-shadow: sampled` — present when this request was sampled for shadow-mode comparison

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 `ANTHROPIC_BASE_URL` into the child process's environment, runs your command to completion, then tears the proxy down — flushing genuine savings to your ledger. No code change, no manual env wiring, no leftover server.

    # Run any base-url-honoring agent with compression transparently applied
    $ distil wrap -- claude -p "summarize this repo"
    distil wrap → proxy http://127.0.0.1:54xxx (upstream https://api.anthropic.com)
      → ANTHROPIC_BASE_URL=http://127.0.0.1:54xxx
      → recording genuine savings → distil leaderboard
    # ... your command runs, every request compressed ...

    # Lossless-only policy mode (no tool injection, digest still runs — for subscription / OAuth)
    $ distil wrap --lossless-only -- my-agent --task build

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.

### Flags

Flag | Default | Description
--- | --- | ---
`--host` | `127.0.0.1` | Bind address for the ephemeral proxy
`--upstream` | `https://api.anthropic.com` | Real LLM API base URL to forward to
`--env-var` | `ANTHROPIC_BASE_URL` | Environment variable to point at the proxy in the child process
`--lossless-only` | off | Policy mode: lossless strategies only — no lossy output-shaping, no tool injection (`--expand`). The reversible Tier-1 digest still runs. Use for subscription / OAuth sessions.
`--verbatim` | off | Skip the Tier-1 digest; Tier-0 only. Interactive-safe, lower savings.
`--shape-output` | off | Generation-side verbosity shaping (gated by `--lossless-only`)
`--pricing` | `claude-opus-4-8` | Model used to price genuine dollar savings recorded to the ledger
`--no-record` | off | Do not record genuine savings to the local ledger
`--expand` | off | Inject the `distil_expand` tool so the model can pull digested blocks back on demand
`--session-delta` | off | Enable cross-turn cache-delta encoding

## 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

Flag | Default | Description
--- | --- | ---
`--input` | bundled fixture | Path 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

Flag | Default | Description
--- | --- | ---
`--input` | required | Path to the JSONL log file (Anthropic or OpenAI request format)
`--out` | `./ingested-corpus` | Output directory where the trajectory will be written
`--provider` | `anthropic` | `anthropic` or `openai` — selects the input format
`--model` | `claude-opus-4-8` | Model 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

Flag | Default | Description
--- | --- | ---
`--iterations` | `200` | Number 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

Flag | Default | Description
--- | --- | ---
`--host` | `127.0.0.1` | Interface to bind on. Pass `0.0.0.0` for network-accessible deployments.
`--port` | `8789` | Port to listen on.
`--upstream` | `https://api.anthropic.com` | Real LLM API base URL (set once at startup, cannot be overridden per-request).
`--pricing` | `claude-opus-4-8` | Model pricing key for per-tenant dollar accounting.
`--lossless-only` | off | Policy mode: lossless strategies only — no lossy output-shaping, no tool injection (`--expand`). The reversible Tier-1 digest still runs. Use for subscription / OAuth sessions.
`--verbatim` | off | Skip the Tier-1 digest; Tier-0 only. Interactive-safe, lower savings.

    $ 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 (priority order): `x-distil-tenant` header → anonymized key hash (`anon-<sha256[:8]>`) → `"default"`. 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 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

Flag | Default | Description
--- | --- | ---
`--out` | `distil-keep-transformer` | Output directory. Receives `model.onnx`, tokenizer files, and `metrics.json`.
`--base-model` | `google/bert_uncased_L-2_H-128_A-2` | HuggingFace model ID to fine-tune. Swap for `distilbert-base-uncased` for higher accuracy at larger size.
`--epochs` | `3` | Number 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:

- `model.onnx` — exported ONNX graph (inputs: `input_ids`, `attention_mask`)
- `tokenizer.json`, `tokenizer_config.json`, `vocab.txt` — tokenizer for `TransformerKeepModel.from_pretrained`
- `metrics.json` — held-out accuracy / F1 from the training run

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

Flag | Default | Description
--- | --- | ---
`--corpus` | bundled corpus | Custom corpus dir (e.g. from `distil ingest` on benchmark traces)
`--runner` | `deterministic` | `deterministic` (offline, structural equivalence) or `anthropic` (live model, requires API key)
`--out` | off | Write 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

Flag | Default | Description
--- | --- | ---
`--external` | — | `module:function[:Name]` — register a real compressor (`list[str]→list[str]` over per-turn block texts), measured on the identical axes. Repeatable.
`--corpus` | bundled corpus | Custom corpus dir (e.g. ingested benchmark traces)
`--runner` | `deterministic` | `deterministic` (offline) or `anthropic` (live model)
`--pricing` | `claude-opus-4-8` | Model pricing for the cache-aware cost model
`--tokenizer` | `heuristic` | `heuristic` or `anthropic` (billing-grade)
`--margin` | `0.02` | TOST non-inferiority margin
`--alpha` | `0.05` | Significance level for the non-inferiority test
`--html` / `--out` | off | Render 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. See Benchmark → the equivalence dial.

### Flags

Flag | Default | Description
--- | --- | ---
`--targets` | `1.0,0.97,0.95,0.90,0.80` | Comma-separated equivalence targets in (0,1]
`--corpus` | bundled corpus | Custom corpus dir
`--runner` | `deterministic` | `deterministic` or `anthropic` (live model)
`--samples` | `3` | Majority-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

Flag | Default | Description
--- | --- | ---
`--alpha` | `0.05` | Risk target: max tolerable decision-change rate
`--delta` | `0.05` | LTT failure probability; confidence is 1−δ (ignored by CRC)
`--method` | `ltt` | `ltt` (high-probability bound) or `crc` (expected-rate bound)
`--corpus` | bundled corpus | Calibration corpus dir (use your own traffic via `distil ingest`)
`--runner` | `deterministic` | `deterministic` or `anthropic` (live model)
`--samples` | `3` | Majority-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

Flag | Default | Description
--- | --- | ---
`--corpus` | bundled corpus | Corpus dir of traffic to learn from. Use `distil ingest` to convert real logs first.
`--promote-to` | off (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 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

Flag | Default | Description
--- | --- | ---
`--dir` | required | Directory containing `submissions.jsonl` (one signed aggregate per line)
`--keys` | off | Path to a JSON file mapping `instance_id` → HMAC key. Submissions with no matching key are rejected.
`--html` | off | Write 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.

## 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