aither-kvcache 2.4.0__tar.gz → 2.4.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. aither_kvcache-2.4.2/PKG-INFO +861 -0
  2. aither_kvcache-2.4.2/README.md +821 -0
  3. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/__init__.py +8 -1
  4. aither_kvcache-2.4.2/aither_kvcache/kvtransfer/align.py +448 -0
  5. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/kvtransfer/capture.py +214 -5
  6. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/kvtransfer/fit.py +57 -2
  7. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/kvtransfer/geometry.py +45 -7
  8. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/kvtransfer/pack.py +135 -4
  9. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/kvtransfer/rope.py +18 -2
  10. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/kvtransfer/transfer.py +163 -15
  11. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/triattention/calibration.py +27 -4
  12. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/vllm/backend.py +19 -6
  13. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/vllm/engine.py +1 -1
  14. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/vllm/kv_warmth_client.py +2 -2
  15. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/vllm/plugin.py +3 -3
  16. aither_kvcache-2.4.2/aither_kvcache.egg-info/PKG-INFO +861 -0
  17. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache.egg-info/SOURCES.txt +1 -0
  18. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/pyproject.toml +1 -1
  19. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/tests/test_triattention.py +33 -1
  20. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/tests/test_vllm_plugin.py +9 -1
  21. aither_kvcache-2.4.2/turboquant/__init__.py +127 -0
  22. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/turboquant/bench.py +116 -17
  23. aither_kvcache-2.4.0/PKG-INFO +0 -658
  24. aither_kvcache-2.4.0/README.md +0 -618
  25. aither_kvcache-2.4.0/aither_kvcache.egg-info/PKG-INFO +0 -658
  26. aither_kvcache-2.4.0/turboquant/__init__.py +0 -76
  27. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/LICENSE +0 -0
  28. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/block_selector.py +0 -0
  29. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/eviction_advisor.py +0 -0
  30. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/fused_kv_update.py +0 -0
  31. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/hybrid_quantizer.py +0 -0
  32. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/kvcache_graph.py +0 -0
  33. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/kvtransfer/__init__.py +0 -0
  34. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/kvtransfer/mapper.py +0 -0
  35. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/persistence.py +0 -0
  36. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/triattention/__init__.py +0 -0
  37. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/triattention/attention.py +0 -0
  38. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/triattention/cache.py +0 -0
  39. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/triattention/config.py +0 -0
  40. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/triattention/encoder.py +0 -0
  41. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/triattention/scorer.py +0 -0
  42. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/triattention/spectral.py +0 -0
  43. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/vllm/__init__.py +0 -0
  44. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/vllm/cache.py +0 -0
  45. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/vllm/eviction_plugin.py +0 -0
  46. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/vllm/hooks.py +0 -0
  47. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/vllm/isolation_status_endpoint.py +0 -0
  48. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/vllm/sitecustomize.py +0 -0
  49. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/vllm/strata_shadow_plugin.py +0 -0
  50. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache/vllm/tenant_isolation.py +0 -0
  51. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache.egg-info/dependency_links.txt +0 -0
  52. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache.egg-info/entry_points.txt +0 -0
  53. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache.egg-info/requires.txt +0 -0
  54. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/aither_kvcache.egg-info/top_level.txt +0 -0
  55. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/setup.cfg +0 -0
  56. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/tests/test_block_selector.py +0 -0
  57. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/tests/test_core.py +0 -0
  58. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/tests/test_fused.py +0 -0
  59. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/tests/test_hybrid_hooks.py +0 -0
  60. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/tests/test_kvcache_graph.py +0 -0
  61. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/tests/test_persistence.py +0 -0
  62. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/turboquant/codebook.py +0 -0
  63. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/turboquant/fused_attention.py +0 -0
  64. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/turboquant/gb10_fp8_rescue.py +0 -0
  65. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/turboquant/packing.py +0 -0
  66. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/turboquant/quantizer.py +0 -0
  67. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/turboquant/rotation.py +0 -0
  68. {aither_kvcache-2.4.0 → aither_kvcache-2.4.2}/turboquant/triton_ops.py +0 -0
@@ -0,0 +1,861 @@
1
+ Metadata-Version: 2.4
2
+ Name: aither-kvcache
3
+ Version: 2.4.2
4
+ Summary: KV cache tooling for LLM inference — TurboQuant (vector quantization), TriAttention (spectral compression), and cross-model KV transfer (skip prefill by converting one model's cache into another's)
5
+ Author: Aitherium
6
+ License-Expression: CC-BY-4.0
7
+ Project-URL: Paper, https://arxiv.org/abs/2504.19874
8
+ Project-URL: Repository, https://github.com/Aitherium/aitherkvcache
9
+ Project-URL: Changelog, https://github.com/Aitherium/aitherkvcache/releases
10
+ Keywords: kv-cache,quantization,llm,inference,compression,turboquant,triattention,spectral,vllm,attention,kv-transfer,cross-model,prefill,rope,mla
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: torch>=2.0
23
+ Requires-Dist: numpy
24
+ Provides-Extra: triton
25
+ Requires-Dist: triton>=2.0; extra == "triton"
26
+ Provides-Extra: scipy
27
+ Requires-Dist: scipy; extra == "scipy"
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest; extra == "dev"
30
+ Provides-Extra: vllm
31
+ Requires-Dist: vllm>=0.15; extra == "vllm"
32
+ Provides-Extra: transfer
33
+ Requires-Dist: transformers>=4.40; extra == "transfer"
34
+ Provides-Extra: all
35
+ Requires-Dist: triton>=2.0; extra == "all"
36
+ Requires-Dist: scipy; extra == "all"
37
+ Requires-Dist: pytest; extra == "all"
38
+ Requires-Dist: transformers>=4.40; extra == "all"
39
+ Dynamic: license-file
40
+
41
+ # aither-kvcache
42
+
43
+ <!-- aither-header:start GENERATED from the ecosystem registry. Edits here are overwritten; change the registry instead. -->
44
+
45
+ **[Docs](https://aitherium.github.io/aitherkvcache/)** · [Source](https://github.com/Aitherium/aitherkvcache) · `pip install aither-kvcache` · [The Aither World](https://aitherium.github.io/)
46
+
47
+ > **The Aither World** is an operating system for agents — a Linux you can hand to one, the runtimes it works in, and the tools it works with. [awnix](https://github.com/Aitherium/awnix) is the Linux underneath it; **aitherkvcache** is one of its 69 bricks — each installs on its own, runs offline, and needs no account. 7 more are in development and 15 are planned.
48
+ >
49
+ > **Start here:** Quantize the cache on one model you already serve and measure the headroom.
50
+
51
+ <!-- aither-header:end -->
52
+
53
+ Near-optimal KV cache compression for LLM inference. Two compression engines:
54
+
55
+ - **TurboQuant** — Vector quantization ([Zandieh et al., arXiv:2504.19874](https://arxiv.org/abs/2504.19874)).
56
+ 2-4 bit, 3.8-7.1× compression vs FP16. No calibration data. Works on streaming tokens.
57
+
58
+ - **TriAttention** *(v2.0)* — Spectral KV compression via trigonometric series.
59
+ Retains top RoPE frequency pairs, scores via trig series without materializing full K/V.
60
+ 14–26× compression at F=8–16. **Calibration-dependent — read this before using it:**
61
+ which frequency pairs carry the energy is a property of the model, and off-profile the
62
+ ranking degrades while reconstruction still looks fine. Measured on an *uncalibrated*
63
+ model at the F=12 default: cosine 0.91, but mean top-32 attention overlap **0.41** over
64
+ 64 query directions. Profiles ship for Qwen3.5, Nemotron, DeepSeek-R1 and Llama 3.1;
65
+ anything else now emits a `RuntimeWarning` instead of falling back silently.
66
+
67
+ - **KVTransfer** *(NEW in v2.4)* — Cross-model KV transfer. Convert one model's KV cache
68
+ into another model's so the receiving model **skips prefill entirely**. Per-(layer, head)
69
+ linear maps fitted by ridge; source layers chosen per target layer by held-out R².
70
+ Same model family only — the two models must share a tokenizer.
71
+
72
+ ## Installation
73
+
74
+ ```bash
75
+ pip install aither-kvcache # core library
76
+ pip install aither-kvcache[vllm] # + vLLM plugin (v0.15+)
77
+ pip install aither-kvcache[triton] # + fused GPU kernels
78
+ pip install aither-kvcache[transfer] # + cross-model KV transfer
79
+ pip install aither-kvcache[all] # everything
80
+ ```
81
+
82
+ ## Quick Start — TurboQuant
83
+
84
+ ```python
85
+ from aither_kvcache import TurboQuant
86
+
87
+ tq = TurboQuant(head_dim=128, bits=4, device="cuda")
88
+
89
+ packed, norms = tq.encode(kv_vectors) # [..., 128] float16 -> [..., 64] uint8 + [...] f32
90
+ decoded = tq.decode(packed, norms) # [..., 64] uint8 + [...] f32 -> [..., 128] float16
91
+ ```
92
+
93
+ ## Quick Start — TriAttention (v2.0+)
94
+
95
+ ```python
96
+ from aither_kvcache.triattention import TriAttention, TriAttentionConfig
97
+
98
+ # Configure: 12 frequency pairs, 4-bit coefficients → ~10× compression
99
+ config = TriAttentionConfig(
100
+ head_dim=128, num_freqs=12, coeff_bits=4,
101
+ num_kv_heads=8, num_query_heads=32,
102
+ rope_base=1_000_000.0, # Qwen3.5 RoPE base
103
+ )
104
+ tri = TriAttention(config, device="cuda")
105
+
106
+ # Encode K/V to spectral representation (pre-RoPE keys)
107
+ k_enc, v_enc = tri.encode_kv(keys, values)
108
+ # keys: [B, S, num_kv_heads, head_dim] → spectral: 26 bytes/token vs 256 FP16
109
+
110
+ # Decode: score via trig series, accumulate values
111
+ output = tri.decode_step(query, k_enc, v_enc, query_pos, key_positions)
112
+ ```
113
+
114
+ ### Qwen3.5 calibration profiles
115
+
116
+ ```python
117
+ from aither_kvcache.triattention.calibration import get_config_for_model
118
+
119
+ config = get_config_for_model("Qwen3.5-8B", coeff_bits=4)
120
+ # Per-layer frequency schedule: early layers get more frequencies,
121
+ # middle layers are most spectrally concentrated.
122
+ print(config.summary())
123
+ # TriAttention Config (qwen3.5)
124
+ # head_dim=128, num_freqs=12, coeff_bits=4
125
+ # heads: 32Q / 8KV (GQA 4:1)
126
+ # storage: 26 bytes/token (vs 256 FP16)
127
+ # compression: 9.8× per K/V tensor
128
+ ```
129
+
130
+ ### How it works
131
+
132
+ Transformer attention with RoPE is naturally a trigonometric series in position difference Δ = n − m:
133
+
134
+ ```
135
+ score(q, k, m, n) = (1/√d) Σᵢ [cᵢ cos(Δθᵢ) + sᵢ sin(Δθᵢ)]
136
+ ```
137
+
138
+ where `cᵢ = q₂ᵢk₂ᵢ + q₂ᵢ₊₁k₂ᵢ₊₁` (pair dot product) and `θᵢ = base^{-2i/d}` (RoPE frequency).
139
+
140
+ Most key energy concentrates in a few frequency pairs. By retaining only the top-F pairs (by
141
+ energy E_i = k₂ᵢ² + k₂ᵢ₊₁²) and quantizing coefficients to 4-bit, we store 26 bytes per token
142
+ instead of 256 — a ~10× reduction with bounded approximation error.
143
+
144
+ ### TriAttention compression ratios
145
+
146
+ | Mode | Coeff Bits | Bytes/Token | Compression vs FP16 |
147
+ |------|-----------|-------------|---------------------|
148
+ | F=12, int4 | 4 | 26 | **9.85×** |
149
+ | F=12, int8 | 8 | 38 | 6.74× |
150
+ | F=16, int4 | 4 | 34 | 7.53× |
151
+ | F=8, int4 | 4 | 18 | **14.2×** |
152
+
153
+ ## Quick Start — KVTransfer (v2.4+)
154
+
155
+ Prefill is the tax you pay before a model says anything, and a KV cache only works on the
156
+ model that produced it. Route a conversation to a different model and the accumulated
157
+ cache becomes dead weight. KVTransfer fits a map that converts one model's cache into
158
+ another's, so the receiving model can skip prefill.
159
+
160
+ ```bash
161
+ # 1. capture aligned KV from both models over one corpus
162
+ python -m aither_kvcache.kvtransfer.capture \
163
+ --source Qwen/Qwen3-0.6B --target Qwen/Qwen3-4B \
164
+ --out ./cap --corpus ./my-corpus --seq-len 256 --train-seqs 64 --val-seqs 24
165
+
166
+ # 2. fit the mapper pack
167
+ python -m aither_kvcache.kvtransfer.fit --capture ./cap --out ./pack --top-k 8
168
+
169
+ # 3. measure what the RECEIVING model does with a translated cache, and record it
170
+ python -m aither_kvcache.kvtransfer.transfer \
171
+ --pack ./pack --source Qwen/Qwen3-0.6B --target Qwen/Qwen3-4B \
172
+ --corpus ./held-out --sequences 24 --cuts 32 64 96 128 160 192 224 --record
173
+ ```
174
+
175
+ ```python
176
+ from aither_kvcache.kvtransfer import load_pack
177
+ from aither_kvcache.kvtransfer.transfer import translate_cache
178
+
179
+ pack = load_pack("./pack", live_source=src_geom, live_target=tgt_geom)
180
+ layers = translate_cache(src_k, src_v, pack, positions) # -> the target's KV cache
181
+ ```
182
+
183
+ ### Step 3 is not optional
184
+
185
+ `load_pack` **refuses** any pack that carries no downstream acceptance evidence. That is
186
+ the core design decision here, and it is not defensive programming — it is the only thing
187
+ standing between an interesting R² and a broken deployment.
188
+
189
+ A converted cache does not fail loudly. An approximate one makes the receiving model
190
+ produce fluent, on-topic, **confidently wrong** text: no exception, no error status, no
191
+ unhealthy process, nothing in a log. Every cheap signal is green.
192
+
193
+ So a pack must carry a measurement, and the measurement has **four arms**:
194
+
195
+ | arm | what it is |
196
+ |---|---|
197
+ | `reference` | the target prefills the context itself — the ceiling |
198
+ | `translated` | the target is handed the converted cache — the candidate |
199
+ | `control` | the map is run on a **different document** — catches a mapper ignoring its input |
200
+ | `nocontext` | no cache at all — the floor |
201
+
202
+ The control arm is the one that matters. A mapper that has quietly learned the target's
203
+ *average* key/value statistics scores respectably against `reference` alone. Without a
204
+ floor, "68% agreement" is unreadable — it could be excellent, or exactly what a dead
205
+ mapper gets.
206
+
207
+ A minimum sample size is enforced too. Top-1 agreement is a proportion, so a mean over a
208
+ few dozen positions has a standard error near ten percentage points — and once recorded it
209
+ is indistinguishable from a mean over ten thousand.
210
+
211
+ ### Preconditions that are definitional, not quality knobs
212
+
213
+ - **The two models must tokenize identically.** The map sends position *i* to position
214
+ *i*; different tokenizers mean row *i* is not the same token and the fit is regressing
215
+ misaligned data. Nothing downstream can see this — it reads as "this pair transfers
216
+ poorly" rather than "these rows do not correspond". Enforced by vocabulary digest, and
217
+ by comparing token ids per document at capture time.
218
+ - **The RoPE schedule must be exactly reproducible.** Keys carry a position rotation, so
219
+ the map is fitted in position-free space: stripped with the *source* schedule, re-applied
220
+ with the *target's* (not a no-op — the two models often disagree on `rope_theta`).
221
+ `default`, `linear` and `yarn` are implemented; anything else is refused rather than
222
+ approximated.
223
+
224
+ `check_pair()` separates definitional refusals from merely-unproven regimes — mismatched
225
+ KV-head counts, differing head dimension, cross-family pairs. The latter are recorded as
226
+ flags and decided by measurement, because a gate keyed on "heads must match" would refuse
227
+ the very experiment that tests whether heads need to match.
228
+
229
+ ### Latent attention (MLA)
230
+
231
+ Models such as DeepSeek V2/V3/V4 cache a compressed latent plus a decoupled RoPE key
232
+ rather than per-head K and V. That is a different cache **layout**, not an obstacle — the
233
+ latent is dense, and often smaller than a conventional cache for the same context.
234
+ `KVGeometry.roles()` returns `("c", "kr")` for those models, and only `kr` carries a
235
+ rotation because the latent is position-free by construction.
236
+
237
+ The latent is captured at the compression projection rather than from `past_key_values`:
238
+ HuggingFace materialises per-head K/V before caching, so reading the cache would yield
239
+ tensors a real serving engine never stores, and a mapper fitted to them could not drive a
240
+ production deployment while looking entirely correct end to end.
241
+
242
+ ## vLLM Integration
243
+
244
+ ### Native kv-cache-dtype (recommended)
245
+
246
+ With the [TQ-patched vLLM fork](https://github.com/Aitherium/aitherkvcache), TurboQuant is a **native KV cache dtype**.
247
+ One flag, no hooks, no env vars:
248
+
249
+ ```bash
250
+ vllm serve your-model --kv-cache-dtype tq-t4nc
251
+ ```
252
+
253
+ Supported dtypes:
254
+
255
+ | Dtype | Bits | Compression | Notes |
256
+ |-------|------|------------|-------|
257
+ | `tq-t4nc` | 4 | 3.8x | **Recommended** — best quality/compression tradeoff |
258
+ | `tq-t3nc` | 3 | 4.9x | More aggressive |
259
+ | `tq-t35nc` | 3.5 | 4.4x | Hybrid split-group quantization |
260
+ | `tq-t2nc` | 2 | 7.1x | Maximum compression |
261
+
262
+ Production Docker example:
263
+
264
+ ```yaml
265
+ services:
266
+ vllm:
267
+ image: aither-vllm-tq:latest
268
+ command: >
269
+ python -m vllm.entrypoints.openai.api_server
270
+ --model your-model
271
+ --kv-cache-dtype tq-t4nc
272
+ --gpu-memory-utilization 0.85
273
+ --max-model-len 40960
274
+ --compilation-config '{"cudagraph_mode":"piecewise","max_cudagraph_capture_size":16}'
275
+ --max-num-seqs 16
276
+ --enable-prefix-caching
277
+ ```
278
+
279
+ **Boundary layer protection**: First/last 2 layers auto-use FlashAttn (`auto`)
280
+ to preserve embedding quality and output mixing.
281
+
282
+ **Production results** (RTX 5090, Nemotron-8B-AWQ, `tq-t4nc`):
283
+
284
+ | Metric | Value |
285
+ |--------|-------|
286
+ | KV cache | **250,928 tokens** (19.1 GiB) |
287
+ | Max concurrency (40K ctx) | 6.1x simultaneous |
288
+ | CUDA graphs | 10 piecewise, 6s capture |
289
+ | Model load | 6.4 GiB, 15s |
290
+
291
+ ### Plugin mode (stock vLLM, v0.15+)
292
+
293
+ For stock vLLM without the TQ fork:
294
+
295
+ ```bash
296
+ pip install aither-kvcache[vllm]
297
+ vllm serve your-model --attention-backend CUSTOM
298
+ ```
299
+
300
+ ### Hook-based integration (legacy, v0.9.1+)
301
+
302
+ For older vLLM or when you need monkey-patching:
303
+
304
+ ```python
305
+ import os
306
+ os.environ["AITHER_TQ_MODE"] = "tq4-primary"
307
+ os.environ["AITHER_TQ_BITS"] = "4"
308
+
309
+ from aither_kvcache.vllm import apply_tq_patches, apply_tq_hooks
310
+ apply_tq_patches(bits=4) # BEFORE vLLM starts
311
+
312
+ from vllm import LLM
313
+ llm = LLM(model="your-model", gpu_memory_utilization=0.90)
314
+ apply_tq_hooks() # AFTER model loads
315
+ ```
316
+
317
+ ### Hybrid modes (tq35/tq25)
318
+
319
+ Split-group quantization with QJL residual encoding:
320
+
321
+ ```python
322
+ from aither_kvcache import HybridTurboQuant
323
+ htq = HybridTurboQuant(head_dim=128, mode="tq35", device="cuda")
324
+ htq.calibrate_uniform()
325
+ packed = htq.encode(kv_vectors)
326
+ decoded = htq.decode(packed)
327
+ ```
328
+
329
+ | Mode | Avg Bits | Strategy |
330
+ |------|----------|----------|
331
+ | tq35 | 3.5 | 50% dims @ 4-bit + 50% @ 3-bit (MSE + QJL) |
332
+ | tq25 | 2.5 | 25% dims @ 3-bit + 75% @ 2-bit (MSE + QJL) |
333
+
334
+ ### Zero graph breaks (v1.0+)
335
+
336
+ All modes register `torch.library.custom_op` for zero-graph-break decode.
337
+ Requires PyTorch 2.4+. Falls back to `@torch.compiler.disable` on older versions.
338
+
339
+ ## Where This Fits
340
+
341
+ ### Custom inference loop
342
+
343
+ If you manage your own KV cache, drop `encode()` where you write and `decode()` where you read:
344
+
345
+ ```python
346
+ from aither_kvcache import TurboQuant
347
+
348
+ tq = TurboQuant(head_dim=128, bits=4, device="cuda")
349
+
350
+ # Write to cache: compress
351
+ packed, norms = tq.encode(key_proj) # [batch, heads, 128] -> [batch, heads, 64] uint8
352
+
353
+ # Read from cache: decompress
354
+ key_restored = tq.decode(packed, norms) # -> [batch, heads, 128] float16
355
+ ```
356
+
357
+ ### Paged KV cache
358
+
359
+ Works with block-structured caches (like vLLM's). Handles arbitrary batch dimensions:
360
+
361
+ ```python
362
+ # Compress a block of 16 tokens across 8 heads
363
+ block = cache[block_idx] # [16, 8, 128]
364
+ packed, norms = tq.encode(block) # [16, 8, 64] uint8 + [16, 8] f32
365
+ restored = tq.decode(packed, norms) # [16, 8, 128]
366
+ ```
367
+
368
+ ### Zero-buffer fused attention
369
+
370
+ Compute attention directly from compressed data without ever decompressing:
371
+
372
+ ```python
373
+ from aither_kvcache.fused_attention import TQPagedAttention
374
+
375
+ attn = TQPagedAttention(tq, num_query_heads=32)
376
+ output = attn.forward(
377
+ query, k_packed, k_norms, v_packed, v_norms,
378
+ block_tables, context_lens,
379
+ )
380
+ ```
381
+
382
+ The math: rotate the query forward once, dot-product in the rotated domain against
383
+ codebook-decoded values, accumulate weighted values in the rotated domain, rotate back
384
+ once. Two matrix multiplies total regardless of context length.
385
+
386
+ Uses fused Triton kernels on GPU (Ampere through Blackwell). Falls back to PyTorch reference on CPU.
387
+ Set `AITHER_TQ_FORCE_TRITON=1` on Blackwell (SM_120) GPUs -- validated on RTX 5090 at 26 tok/s.
388
+
389
+ ### Research / benchmarking
390
+
391
+ ```python
392
+ tq = TurboQuant(head_dim=128, bits=4)
393
+ print(tq.validate(num_vectors=50000))
394
+ ```
395
+
396
+ ```bash
397
+ python -m turboquant.bench
398
+ ```
399
+
400
+ ## Compression Ratios
401
+
402
+ For head_dim=128:
403
+
404
+ | Bits | Bytes/vector | vs FP16 | vs FP8 |
405
+ |------|-------------|---------|--------|
406
+ | 4 | 68 | 3.8x | 1.9x |
407
+ | 3 | 52 | 4.9x | 2.5x |
408
+ | 2 | 36 | 7.1x | 3.6x |
409
+
410
+ ## Validated MSE
411
+
412
+ | Bits | MSE | Theory Lower | Theory Upper | Ratio to LB |
413
+ |------|-----|-------------|-------------|-------------|
414
+ | 4 | 0.0095 | 0.0039 | 0.0184 | 2.4x |
415
+ | 3 | 0.0345 | 0.0156 | 0.0736 | 2.2x |
416
+ | 2 | 0.1175 | 0.0625 | 0.2945 | 1.9x |
417
+
418
+ ## Algorithm
419
+
420
+ 1. **Normalize**: extract L2 norm, project onto unit sphere
421
+ 2. **Rotate**: multiply by a fixed random orthogonal matrix (data-oblivious). Makes each coordinate ~N(0, 1/d).
422
+ 3. **Quantize**: each coordinate via precomputed Lloyd-Max codebook
423
+ 4. **Pack**: indices into uint8 bytes
424
+ 5. **Store**: packed bytes + float32 norm
425
+
426
+ Decoding reverses steps 4-1.
427
+
428
+ ## API Reference
429
+
430
+ ```python
431
+ class TurboQuant:
432
+ def __init__(self, head_dim=128, bits=4, seed=42, device="cuda", ...)
433
+ def encode(self, x: Tensor) -> Tuple[Tensor, Tensor]
434
+ def decode(self, packed: Tensor, norms: Tensor) -> Tensor
435
+ def validate(self, num_vectors=10000) -> dict
436
+ def benchmark(self, num_vectors=32768) -> dict
437
+ def compression_ratio(self) -> float
438
+ def memory_report(self, seq_len, num_layers=32, num_kv_heads=8) -> dict
439
+
440
+ class HybridTurboQuant:
441
+ def __init__(self, head_dim=128, mode="tq35", seed=42, device="cuda")
442
+ def calibrate_uniform(self, num_kv_heads=1)
443
+ def calibrate(self, sample_vectors: Tensor)
444
+ def encode(self, x: Tensor) -> Tensor # packed only (norms embedded)
445
+ def decode(self, packed: Tensor) -> Tensor
446
+ def validate(self, num_vectors=10000) -> dict
447
+ def compression_ratio(self) -> float
448
+
449
+ @staticmethod
450
+ def packed_dim_for_mode(head_dim: int, mode: str) -> int
451
+
452
+ class TQPagedAttention:
453
+ def __init__(self, tq: TurboQuant, num_query_heads: int)
454
+ def forward(self, query, k_packed, k_norms, v_packed, v_norms,
455
+ block_tables, context_lens, block_size=16) -> Tensor
456
+ ```
457
+
458
+ ## Graph-Aware KV Cache Eviction (v1.1+)
459
+
460
+ Standard KV cache eviction (LRU/FIFO) doesn't know the difference between your system
461
+ prompt and throwaway generation tokens. `KVCacheGraph` builds a relationship graph over
462
+ physical KV cache blocks so eviction decisions understand what the blocks actually mean.
463
+
464
+ ### Quick Start
465
+
466
+ ```python
467
+ from aither_kvcache import KVCacheGraph, GraphEvictionAdvisor, EdgeType
468
+
469
+ # 1. Create the graph — protect system prompt blocks from eviction
470
+ graph = KVCacheGraph(protected_sources={"system", "tools"})
471
+
472
+ # 2. Register blocks as they enter the KV cache
473
+ graph.add_block(0, "system", importance=0.95, token_range=(0, 16))
474
+ graph.add_block(1, "system", importance=0.90, token_range=(16, 32))
475
+ graph.add_block(2, "user", importance=0.60, token_range=(32, 48))
476
+ graph.add_block(3, "assistant", importance=0.30, token_range=(48, 64))
477
+
478
+ # 3. Feed attention patterns — edges form automatically
479
+ graph.on_attention_step([0, 1, 2, 3]) # track co-attendance
480
+ graph.on_temporal_sequence([2, 3]) # sequential generation
481
+ graph.on_prefix_hit("req_42", [0, 1]) # prefix cache reuse
482
+
483
+ # 4. Ask who to evict (system blocks are structurally protected)
484
+ victims = graph.suggest_eviction(n_blocks=2)
485
+ # -> returns least-connected, lowest-importance, non-protected blocks
486
+
487
+ # 5. Ask what to prefetch from cold tier
488
+ graph.on_spill([3]) # block 3 moved to DDR5
489
+ prefetch = graph.suggest_prefetch(active_block_idxs=[0, 1, 2])
490
+ # -> returns spilled blocks that are graph-neighbors of active set
491
+ ```
492
+
493
+ ### Background Advisor (zero decode-path overhead)
494
+
495
+ For hot inference loops where you can't afford graph queries on the decode path:
496
+
497
+ ```python
498
+ from aither_kvcache import GraphEvictionAdvisor
499
+
500
+ advisor = GraphEvictionAdvisor(graph, interval=0.5, max_stale=2.0)
501
+ advisor.start() # background thread recomputes rankings every 0.5s
502
+
503
+ # Hot decode path — lock-free, zero overhead:
504
+ candidates = advisor.get_eviction_candidates(n=16) # pre-computed list or None
505
+ prefetch = advisor.get_prefetch_candidates([0, 1], n=8) # graph neighbor lookup
506
+
507
+ advisor.stop()
508
+ ```
509
+
510
+ The advisor pre-computes eviction rankings on a background thread. The decode path reads
511
+ an atomically-swapped reference — no lock, no mutex, no blocking. If the ranking goes
512
+ stale (>2s), returns None and the caller falls back to FIFO.
513
+
514
+ ### How Eviction Scoring Works
515
+
516
+ The `suggest_eviction()` method scores every non-protected, non-spilled block:
517
+
518
+ ```
519
+ score = age × 0.01 # older = more evictable
520
+ − degree × 5.0 # more graph connections = keep
521
+ − edge_weight × 2.0 # stronger edges = keep
522
+ − importance × 20.0 # higher importance = keep
523
+ − hit_count × 3.0 # more prefix cache hits = keep
524
+ ```
525
+
526
+ Protected source labels are excluded entirely — they cannot be eviction candidates.
527
+
528
+ ### Six Edge Types
529
+
530
+ | Edge Type | Created By | Meaning |
531
+ |-----------|-----------|---------|
532
+ | `PREFIX_SHARE` | `on_prefix_hit()` | Blocks reused across requests |
533
+ | `CO_ATTEND` | `on_attention_step()` | Blocks frequently attended together |
534
+ | `SEMANTIC` | `add_block(embedding=...)` | Similar key vector embeddings (cosine > 0.8) |
535
+ | `TEMPORAL` | `on_temporal_sequence()` | Consecutive in same generation |
536
+ | `SPILL_LINK` | `on_spill()` / `on_warm()` | Hot ↔ cold tier tracking |
537
+
538
+ ### Integration with Any Inference Engine
539
+
540
+ The graph has no vLLM dependency. It works with any paged KV cache:
541
+
542
+ 1. Call `add_block()` when blocks are allocated
543
+ 2. Call `remove_block()` when blocks are freed
544
+ 3. Call `on_attention_step()` with active block indices each decode step
545
+ 4. Call `suggest_eviction()` when you need to free VRAM
546
+ 5. Call `suggest_prefetch()` to warm cold-tier blocks preemptively
547
+
548
+ ### API
549
+
550
+ ```python
551
+ class KVCacheGraph:
552
+ def __init__(self, protected_sources={"system"}, coattend_threshold=3,
553
+ semantic_threshold=0.8)
554
+ def add_block(self, block_idx, source_label, importance, token_range,
555
+ embedding=None) -> KVBlockNode
556
+ def remove_block(self, block_idx) -> None
557
+ def add_edge(self, source, target, edge_type, weight=1.0) -> Optional[KVEdge]
558
+ def on_attention_step(self, active_block_idxs: List[int]) -> None
559
+ def on_prefix_hit(self, request_id: str, block_idxs: List[int]) -> None
560
+ def on_spill(self, block_idxs: List[int]) -> None
561
+ def on_warm(self, block_idxs: List[int]) -> None
562
+ def on_temporal_sequence(self, block_idxs: List[int]) -> None
563
+ def suggest_eviction(self, n_blocks, protect_sources=None) -> List[int]
564
+ def suggest_prefetch(self, active_block_idxs, max_suggestions=16) -> List[int]
565
+ def neighbors(self, block_idx, edge_type=None, max_depth=1) -> Set[int]
566
+ def subgraph(self, block_idxs) -> Dict
567
+ def get_stats(self) -> Dict
568
+
569
+ class GraphEvictionAdvisor:
570
+ def __init__(self, graph=None, interval=0.5, max_stale=2.0, eviction_batch=256)
571
+ def start(self) -> None
572
+ def stop(self) -> None
573
+ def get_eviction_candidates(self, n: int) -> Optional[List[int]]
574
+ def get_prefetch_candidates(self, active_block_idxs, n=8) -> Optional[List[int]]
575
+ def get_stats(self) -> Dict
576
+
577
+ def reorder_by_ranking(block_indices: List[int], ranked: List[int]) -> List[int]
578
+ ```
579
+
580
+ ## Benchmarks
581
+
582
+ ### KV Cache Memory by Model (at 32K context)
583
+
584
+ | Model | Layers | KV Heads | FP16 | FP8 | TQ4 (4-bit) | TQ3 (3-bit) | TQ2 (2-bit) |
585
+ |-------|--------|----------|------|-----|-------------|-------------|-------------|
586
+ | Llama 3.1 8B | 32 | 8 | 4.0 GB | 2.0 GB | **1.1 GB** | 0.8 GB | 0.6 GB |
587
+ | Mistral 7B v0.3 | 32 | 8 | 4.0 GB | 2.0 GB | **1.1 GB** | 0.8 GB | 0.6 GB |
588
+ | Qwen2.5 14B | 40 | 8 | 5.0 GB | 2.5 GB | **1.3 GB** | 1.0 GB | 0.7 GB |
589
+ | Llama 3.1 70B | 80 | 8 | 10.0 GB | 5.0 GB | **2.7 GB** | 2.0 GB | 1.4 GB |
590
+ | Qwen2.5 72B | 80 | 8 | 10.0 GB | 5.0 GB | **2.7 GB** | 2.0 GB | 1.4 GB |
591
+
592
+ ### KV Cache Memory by Context Length (Llama 3.1 8B)
593
+
594
+ | Context | FP16 | FP8 | TQ4 | TQ3 | TQ2 |
595
+ |---------|------|-----|-----|-----|-----|
596
+ | 8K | 1.0 GB | 512 MB | **272 MB** | 208 MB | 144 MB |
597
+ | 32K | 4.0 GB | 2.0 GB | **1.1 GB** | 0.8 GB | 0.6 GB |
598
+ | 128K | 16.0 GB | 8.0 GB | **4.3 GB** | 3.3 GB | 2.3 GB |
599
+
600
+ ### Decode Throughput (RTX 5090, Llama 3.1 8B)
601
+
602
+ | Integration | Single Request | 5x Concurrent | CUDA Graphs |
603
+ |-------------|---------------|---------------|-------------|
604
+ | Hook mode (recommended) | **40 tok/s** | 120 tok/s | 7/7 captured |
605
+ | Plugin mode (CUSTOM backend) | 23.6 tok/s | 120 tok/s | 7/7 captured |
606
+ | Baseline (FP8, no TQ) | 45 tok/s | 130 tok/s | 7/7 captured |
607
+
608
+ Hook mode reaches ~89% of baseline FP8 throughput while storing 3.8x more KV cache blocks.
609
+
610
+ ### Max Context Window (RTX 5090 32GB, single model)
611
+
612
+ Shows maximum tokens that fit in KV cache VRAM after model weights.
613
+
614
+ | Model | Weights | FP8 | TQ4 | TQ3 | TQ2 |
615
+ |-------|---------|-----|-----|-----|-----|
616
+ | Llama 3.1 8B (util=0.90) | ~5 GB | 353K | **665K** | 869K | 1.26M |
617
+ | Qwen2.5 14B (util=0.90) | ~9 GB | 247K | **466K** | 609K | 880K |
618
+ | Llama 3.1 70B (util=0.90) | ~37 GB | N/A | N/A | N/A | N/A |
619
+
620
+ 70B requires multi-GPU or offloading — KV savings still apply per-GPU.
621
+
622
+ ### Quantization Quality (head_dim=128, 50K vectors)
623
+
624
+ | Mode | Avg Bits | MSE | Compression vs FP16 | Compression vs FP8 |
625
+ |------|----------|-----|---------------------|---------------------|
626
+ | TQ4 | 4.0 | 0.0095 | 3.8x | 1.9x |
627
+ | tq35 | 3.5 | 0.0130 | 4.4x | 2.2x |
628
+ | TQ3 | 3.0 | 0.0345 | 4.9x | 2.5x |
629
+ | tq25 | 2.5 | 0.0520 | 5.8x | 2.9x |
630
+ | TQ2 | 2.0 | 0.1175 | 7.1x | 3.6x |
631
+
632
+ All MSE values within 2.7x of the information-theoretic lower bound (matches paper).
633
+
634
+ Run `python -m aither_kvcache.bench` to reproduce on your hardware.
635
+
636
+ ## Quickstart Notebook
637
+
638
+ See [`notebooks/vllm_quickstart.ipynb`](notebooks/vllm_quickstart.ipynb) for a step-by-step
639
+ walkthrough covering installation, validation, vLLM integration, and graph-aware eviction.
640
+
641
+ ## Reference
642
+
643
+ ```bibtex
644
+ @article{zandieh2025turboquant,
645
+ title={TurboQuant: Online Vector Quantization with Near-optimal Distortion Rate},
646
+ author={Zandieh, Amir and Daliri, Majid and Hadian, Majid and Mirrokni, Vahab},
647
+ journal={arXiv preprint arXiv:2504.19874},
648
+ year={2025}
649
+ }
650
+ ```
651
+
652
+ ## Benchmarks
653
+
654
+ Measured results live in [BENCHMARKS.md](BENCHMARKS.md): kernel numbers, and the
655
+ distilled `aither-code-embed-0.6b` scored against general-purpose embedders on real
656
+ documents (p@1 0.893 vs 0.821 for Qwen3-Embedding-0.6B and nomic-embed-text-v1.5, on 26
657
+ real document chunks and 28 queries). Rerun the embedder comparison on your own corpus
658
+ with `awembed compare`.
659
+
660
+ ## Community
661
+
662
+ - [GitHub Discussions](https://github.com/Aitherium/aitherkvcache/discussions) — Questions, ideas, show & tell
663
+ - [GitHub Issues](https://github.com/Aitherium/aitherkvcache/issues) — Bug reports and feature requests
664
+
665
+ ## License
666
+
667
+ CC BY 4.0
668
+
669
+ ## vLLM Integration (upstream)
670
+
671
+ Native integration via [TQ-patched fork](https://github.com/Aitherium/aitherkvcache).
672
+ Upstream PR: [vllm-project/vllm#39008](https://github.com/vllm-project/vllm/pull/39008).
673
+
674
+ ```bash
675
+ # TQ fork (works now):
676
+ vllm serve your-model --kv-cache-dtype tq-t4nc
677
+
678
+ # Stock vLLM (plugin mode):
679
+ pip install aither-kvcache[vllm]
680
+ vllm serve your-model --attention-backend CUSTOM
681
+ ```
682
+
683
+ <!-- aitherium-ecosystem:start -->
684
+ ## Aitherium open-source ecosystem
685
+
686
+ This repo is one piece of a connected set. All public, MIT/BSL-licensed:
687
+
688
+ | repo | what it is | pages |
689
+ |---|---|---|
690
+ | [awrecover](https://github.com/Aitherium/awrecover) | Labelled snapshots with an all-or-nothing restore | [docs](https://aitherium.github.io/awrecover/) |
691
+ | [awshare](https://github.com/Aitherium/awshare) | Publish an artifact and fetch it back verified | [docs](https://aitherium.github.io/awshare/) |
692
+ | [awseal](https://github.com/Aitherium/awseal) | Sign an artifact so a stranger can verify it | [docs](https://aitherium.github.io/awseal/) |
693
+ | [awnode](https://github.com/Aitherium/awnode) | Lightweight local gateway — your apps to backends you chose | [docs](https://aitherium.github.io/awnode/) |
694
+ | [awnix](https://github.com/Aitherium/awnix) | A bootable, immutable Linux base for agent-run machines | [docs](https://aitherium.github.io/awnix/) |
695
+ | [awdk](https://github.com/Aitherium/awdk) | Build AI agent fleets — 3 lines, any backend | [docs](https://aitherium.github.io/awdk/) |
696
+ | [awskills](https://github.com/Aitherium/awskills) | Free agent skills, scripts & automations | [docs](https://aitherium.github.io/awskills/) |
697
+ | [AitherZero](https://github.com/Aitherium/AitherZero) | PowerShell 7+ automation framework | [docs](https://aitherium.github.io/AitherZero/) |
698
+ | [awgit](https://github.com/Aitherium/awgit) | Semantic version control on top of git | [docs](https://aitherium.github.io/awgit/) |
699
+ | [awgraph](https://github.com/Aitherium/awgraph) | Code knowledge graph for AI agents | [docs](https://aitherium.github.io/awgraph/) |
700
+ | [aitherkvcache](https://github.com/Aitherium/aitherkvcache) | Near-optimal KV cache quantization | [docs](https://aitherium.github.io/aitherkvcache/) |
701
+ | [awrelay](https://github.com/Aitherium/awrelay) | Agent-to-agent messaging over any chat server | [docs](https://aitherium.github.io/awrelay/) |
702
+ | [awm](https://github.com/Aitherium/awm) | A small world model (LeWM JEPA + MLP) to bootstrap your own | [docs](https://aitherium.github.io/awm/) |
703
+ | [AitherConnect](https://github.com/Aitherium/AitherConnect) | Browser extension: federated AI search & desktop bridge | — |
704
+ | [homebrew-tap](https://github.com/Aitherium/homebrew-tap) | `brew tap aitherium/tap` | — |
705
+
706
+ Built by [Aitherium](https://aitherium.com).
707
+ <!-- aitherium-ecosystem:end -->
708
+
709
+ <!-- aither-ecosystem:start GENERATED from the ecosystem registry. Edits here are overwritten; change the registry instead. -->
710
+
711
+ ## The aw family
712
+
713
+ Standalone tools that share one idea: **replace something you would otherwise have to _trust_ with something you can _check_.**
714
+
715
+ Each installs on its own, works offline, and needs no account.
716
+
717
+ | | instead of trusting | you check |
718
+ |---|---|---|
719
+ | [awdk](https://github.com/Aitherium/awdk) | a framework's idea of how your agents should run | one loop you can read, pointed at a backend you already pay for |
720
+ | [awskills](https://github.com/Aitherium/awskills) | that an agent knows your procedure | the procedure written down, versioned, and loadable by any agent |
721
+ | [awpack](https://github.com/Aitherium/awpack) | that the pack you want shipped inside somebody's SDK, under whatever licence that SDK happens to carry | the pack as its own versioned artifact, with its own licence, that any agent runtime can install |
722
+ | [awm](https://github.com/Aitherium/awm) | that memory stayed in its lane | tenant:user:project scopes, so a write cannot cross a boundary |
723
+ | [awdesk](https://github.com/Aitherium/awdesk) | that the agent is somewhere behind a browser tab | a tray icon, a face on your desktop, and the decision card that pops when it needs you |
724
+ | [awnode](https://github.com/Aitherium/awnode) | a vendor's cloud with every prompt | a local gateway routing to backends you chose |
725
+ | [awgraph](https://github.com/Aitherium/awgraph) | that grep found everything | an AST + tree-sitter call graph an agent can traverse |
726
+ | [awgit](https://github.com/Aitherium/awgit) | that no one else is editing this file | a lease, refused at commit time if you do not hold it |
727
+ | [awdelphi](https://github.com/Aitherium/awdelphi) | one agent's confident take on a decision | the round trace, the anonymity, and who dissents |
728
+ | [awclassify](https://github.com/Aitherium/awclassify) | a filename, a folder, or whoever last touched it | doc_type, visibility, audience and topics, with the evidence lines that decided each |
729
+ | [awdecide](https://github.com/Aitherium/awdecide) | a hosted classifier's probability that never learns whether it was right | the decision, its probability, and the calibration curve from your own resolved outcomes |
730
+ | [awtoll](https://github.com/Aitherium/awtoll) | that your tooling is saving you context | the measured token cost of each tool call, and what the alternative cost |
731
+ | [awseal](https://github.com/Aitherium/awseal) | that the artifact came from who you think | an Ed25519 seal — the key that verifies is not the key that forges |
732
+ | [awshare](https://github.com/Aitherium/awshare) | that the download is intact | content-addressed bundles, verified on fetch |
733
+ | [awsuite](https://github.com/Aitherium/awsuite) | that an agent holding your mailbox will not send on its own | every send, draft, upload and create returns a dry-run until confirm is true |
734
+ | [awpermit](https://github.com/Aitherium/awpermit) | that an admitted agent will only do what its owner meant | an Ed25519 permit naming the agent, the principal, the door, the actions and the cap |
735
+ | [awnest](https://github.com/Aitherium/awnest) | that there is a person on the other end | a verdict with evidence, where "we could not tell" is not "yes" |
736
+ | [awrena](https://github.com/Aitherium/awrena) | a leaderboard someone can edit, and votes nobody counted | a scored duel with both answers kept, and a result bound to them |
737
+ | [awnboard](https://github.com/Aitherium/awnboard) | a share link anyone who sees it can use | an invitation addressed to one person, for one gate, revocable |
738
+ | [awnix](https://github.com/Aitherium/awnix) | that the box is what you left it as | an immutable image you built, with atomic rollback |
739
+ | [awrecover](https://github.com/Aitherium/awrecover) | that the restore worked | a restore that fully lands or does not land at all |
740
+ | [awstorage](https://github.com/Aitherium/awstorage) | a du you ran last month, and a peers file that says 3 TB free | an inventory snapshot per node with a diff since the last one, and each tree classified re-fetchable or not |
741
+ | [awrelay](https://github.com/Aitherium/awrelay) | a SaaS in the middle of your agents | findings, alerts and coordination over your own transport |
742
+ | [awask](https://github.com/Aitherium/awask) | that anyone read the paragraph where you asked | the ask itself, with a button that steers the session that raised it |
743
+ | [awmail](https://github.com/Aitherium/awmail) | a mailbox somebody else can read | mail your agents send and receive over your own server |
744
+ | [awdiscord](https://github.com/Aitherium/awdiscord) | a self-bot on someone's account, or a bot that acts without asking | slash commands, rate limits, and approval buttons only your operators can press |
745
+ | [awswarm](https://github.com/Aitherium/awswarm) | that a model either fits your GPU or it doesn't run at all | a placement plan and an acquisition-probability estimate before you spend on a run |
746
+ | [awfind](https://github.com/Aitherium/awfind) | one vendor's idea of the web | results from whichever providers you configured |
747
+ | [awbrowse](https://github.com/Aitherium/awbrowse) | that the page said what you were told | the render, the DOM and the requests it made |
748
+ | [awvoice](https://github.com/Aitherium/awvoice) | that a cloud vendor may hold your audio | a transcript and a wav from a service you host |
749
+ | [awvision](https://github.com/Aitherium/awvision) | a filename and a caption somebody wrote | what a model actually reports about the pixels |
750
+ | [awscreen](https://github.com/Aitherium/awscreen) | a selector that was true when the page was written | the elements actually rendered, by what they look like |
751
+ | [awbeads](https://github.com/Aitherium/awbeads) | that a layout your users built survives the next deploy | the arrangement as data you can read back, diff, and hand to another surface |
752
+ | [awbonsai](https://github.com/Aitherium/awbonsai) | that inference always means a request left the machine | a WebGPU model answering on the tab's own GPU, with a consent record logged before it ever loaded |
753
+ | [gawbbonet](https://github.com/Aitherium/gawbbonet) | the model to keep a 300-message campaign coherent by itself | campaign facts recalled from scoped memory you can list and edit |
754
+ | **aitherkvcache** _(you are here)_ | a vendor's quantisation defaults | sub-byte KV cache kernels you can benchmark yourself |
755
+ | [awrtifact](https://github.com/Aitherium/awrtifact) | a hand-rolled split script and a hand-edited worker manifest | byte-verified parts in a release, served with Range + CORS, sizes asserted by a live gate |
756
+ | [AitherZero](https://github.com/Aitherium/AitherZero) | a pile of scripts nobody has numbered | numbered, discoverable automation with declarative playbooks |
757
+ | [AitherConnect](https://github.com/Aitherium/AitherConnect) | what a page tells your browser to do | a federated search and desktop bridge you host |
758
+ | [awreason](https://github.com/Aitherium/awreason) | a confident paragraph | the phases it went through, and every tool call it made to get there |
759
+ | [awrecurse](https://github.com/Aitherium/awrecurse) | that everything you pasted in was actually read | which slices it opened, and what it concluded from each |
760
+ | [awprism](https://github.com/Aitherium/awprism) | the first explanation that fits | the ranked alternatives, and the observation that separates them |
761
+ | [awrepl](https://github.com/Aitherium/awrepl) | what the agent believes the value is | the value, printed from the live session |
762
+ | [awreport](https://github.com/Aitherium/awreport) | that the report you pasted carried no token in it | a redacted report, and the duplicate it merged into instead of filing twice |
763
+ | [awresearch](https://github.com/Aitherium/awresearch) | a summary of pages nobody opened | every claim against the source it came from |
764
+ | [awfocus](https://github.com/Aitherium/awfocus) | twelve terminal tabs and a bad memory | one command that names every session, finds any transcript, and opens or steers the one you want |
765
+ | [awgym](https://github.com/Aitherium/awgym) | that a world model learned anything from the games it saw | transitions captured from real play, fed back, and the retrodiction score falling on grids it never saw |
766
+ | [awpredict](https://github.com/Aitherium/awpredict) | a model because it trained without erroring | its prediction against a self-updating lookup, on the rows that are actually novel |
767
+ | [awevolve](https://github.com/Aitherium/awevolve) | that your optimisation loop is finding anything | every version it kept, the score that version earned, and the edit that produced it |
768
+ | [awsh](https://github.com/Aitherium/awsh) | that you already know the name of the command | what it decided your line meant, before it acts on it |
769
+ | [awmine](https://github.com/Aitherium/awmine) | that a session's lesson survived the session | a row per outcome, a candidate per lesson, and the transcript line each one came from |
770
+ | [awrise](https://github.com/Aitherium/awrise) | that a scheduled agent ran at all, and ran exactly once | a durable record of every wake -- fired, skipped, overlapped or timed out -- each with its reason |
771
+ | [awkno](https://github.com/Aitherium/awkno) | that the docs site is up, or that you remember the family | the whole ecosystem in your terminal, with no network at all |
772
+ | [awwall](https://github.com/Aitherium/awwall) | that a service only talks to the hosts you think it talks to | an explicit egress allowlist, where a denial names the rule that denied it |
773
+ | [awembed](https://github.com/Aitherium/awembed) | a general-purpose embedder that has never seen your code | a held-out split of whole directories, scored teacher vs student vs int8 |
774
+ | [awtax](https://github.com/Aitherium/awtax) | a closed tax app's sealed file you can never read again | a plain, provider-neutral schema of every figure, with the page it came from |
775
+ | [awsettings](https://github.com/Aitherium/awsettings) | that you will remember to re-approve the same thing on every box you work from | one profile, unioned rather than overwritten, with the credentials left behind |
776
+ | [awavatar](https://github.com/Aitherium/awavatar) | a cloud 3D vendor's opaque task id | a manifest with a sha256, a licence and a rig-audit verdict per file |
777
+
778
+ [**awnix**](https://github.com/Aitherium/awnix) is the ground floor — A Linux you can hand to an agent — immutable base, capabilities included.
779
+
780
+ ## The Aitherium ecosystem
781
+
782
+ Every repository here is public. Each publishes an `aither-manifest.json` beside its page, so any surface can read every sibling's — the network is browsable from any node in it.
783
+
784
+ | repo | what it is | pages |
785
+ |---|---|---|
786
+ | [awdk](https://github.com/Aitherium/awdk) | Build AI agent fleets — 3 lines, any backend, local or cloud | [docs](https://aitherium.github.io/awdk/) |
787
+ | [awskills](https://github.com/Aitherium/awskills) | Portable agent skills — self-contained procedures an agent loads on demand | [docs](https://aitherium.github.io/awskills/) |
788
+ | [awpack](https://github.com/Aitherium/awpack) | First-party agent packs — the ones we build, versioned and installable on their own | [docs](https://aitherium.github.io/awpack/) |
789
+ | [awm](https://github.com/Aitherium/awm) | A portable, scoped agent memory | [docs](https://aitherium.github.io/awm/) |
790
+ | [awdesk](https://github.com/Aitherium/awdesk) | Aither World Desk -- the desktop body of AitherOS Online: tray, avatars, decision cards, the Living Desktop as an overlay | [docs](https://aitherium.github.io/awdesk/) |
791
+ | [awnode](https://github.com/Aitherium/awnode) | A lightweight local gateway — bridges your apps to the AI backends you chose | [docs](https://aitherium.github.io/awnode/) |
792
+ | [awrun](https://github.com/Aitherium/awrun) | A priority-aware queue and dispatcher for agentic runs and ad-hoc CI builds. It also judges whether the runner pool is big enough for the queue it is draining, and can ask a host to grow it -- reserving capacity is zero-sum, so a saturated pool needs more of it, not a different share of it | [docs](https://aitherium.github.io/awrun/) |
793
+ | [awgraph](https://github.com/Aitherium/awgraph) | A semantic code graph for agents — AST + tree-sitter, call graphs | [docs](https://aitherium.github.io/awgraph/) |
794
+ | [awgit](https://github.com/Aitherium/awgit) | Semantic version control on top of git — edit-ops and leases | [docs](https://aitherium.github.io/awgit/) |
795
+ | [awdelphi](https://github.com/Aitherium/awdelphi) | Anonymous multi-round expert panels — a converged answer with a trace | [docs](https://aitherium.github.io/awdelphi/) |
796
+ | [awclassify](https://github.com/Aitherium/awclassify) | Classify any document -- what it is, who may read it, who it is for, what it is about | [docs](https://aitherium.github.io/awclassify/) |
797
+ | [awdecide](https://github.com/Aitherium/awdecide) | One typed-decision contract -- choice / score / bool with a probability -- over a ladder of backends you already run (rules, tiny local models, an LLM's logprobs), fail-closed, with a Brier ledger that resolves every decision against its outcome | [docs](https://aitherium.github.io/awdecide/) |
798
+ | [awtoll](https://github.com/Aitherium/awtoll) | What every tool call costs you in context, measured from your own transcripts | [docs](https://aitherium.github.io/awtoll/) |
799
+ | [awseal](https://github.com/Aitherium/awseal) | Sign an artifact so a stranger can verify it | [docs](https://aitherium.github.io/awseal/) |
800
+ | [awshare](https://github.com/Aitherium/awshare) | Publish an artifact and fetch it back verified | [docs](https://aitherium.github.io/awshare/) |
801
+ | [awsuite](https://github.com/Aitherium/awsuite) | Your Google Workspace as agent tools, and no write happens without a yes | [docs](https://aitherium.github.io/awsuite/) |
802
+ | [awdit](https://github.com/Aitherium/awdit) | An append-only audit trail whose gaps are DETECTABLE | [docs](https://aitherium.github.io/awdit/) |
803
+ | [awbac](https://github.com/Aitherium/awbac) | Role-based access control that fails closed and explains itself | [docs](https://aitherium.github.io/awbac/) |
804
+ | [awiam](https://github.com/Aitherium/awiam) | Who is this caller? A directory and session store that fails honestly | [docs](https://aitherium.github.io/awiam/) |
805
+ | [awtunnel](https://github.com/Aitherium/awtunnel) | Reach a service that has no public address | [docs](https://aitherium.github.io/awtunnel/) |
806
+ | [awpermit](https://github.com/Aitherium/awpermit) | Let an agent through your door with a scope, a spend cap, and someone accountable | [docs](https://aitherium.github.io/awpermit/) |
807
+ | [awnest](https://github.com/Aitherium/awnest) | Prove there is a human before you let them into the nest | [docs](https://aitherium.github.io/awnest/) |
808
+ | [awrena](https://github.com/Aitherium/awrena) | Put two agents head to head and get a verdict you can check | [docs](https://aitherium.github.io/awrena/) |
809
+ | [awnboard](https://github.com/Aitherium/awnboard) | A front gate you can put in front of anything, and hand someone the key to | [docs](https://aitherium.github.io/awnboard/) |
810
+ | [awnix](https://github.com/Aitherium/awnix) | A Linux you can hand to an agent — immutable base, capabilities included | [docs](https://aitherium.github.io/awnix/) |
811
+ | [awrecover](https://github.com/Aitherium/awrecover) | Labelled snapshots with an all-or-nothing restore | [docs](https://aitherium.github.io/awrecover/) |
812
+ | [awstorage](https://github.com/Aitherium/awstorage) | Every drive on every node, indexed, classified and diffed -- so you can see what you own before you delete it | [docs](https://aitherium.github.io/awstorage/) |
813
+ | [awrelay](https://github.com/Aitherium/awrelay) | Portable agent messaging — findings, alerts, coordination | [docs](https://aitherium.github.io/awrelay/) |
814
+ | [awask](https://github.com/Aitherium/awask) | Your agent asks you a question — and acts on your answer | [docs](https://aitherium.github.io/awask/) |
815
+ | [awmail](https://github.com/Aitherium/awmail) | Give an agent an email address — send, and actually receive | [docs](https://aitherium.github.io/awmail/) |
816
+ | [awdiscord](https://github.com/Aitherium/awdiscord) | Put any agent on Discord as a real bot, with an operator in the loop | [docs](https://aitherium.github.io/awdiscord/) |
817
+ | [awnet](https://github.com/Aitherium/awnet) | The agentic web — agents host a mesh, and agents join one | [docs](https://aitherium.github.io/awnet/) |
818
+ | [awswarm](https://github.com/Aitherium/awswarm) | Run one model too big for any single GPU across a pool of small ones | [docs](https://aitherium.github.io/awswarm/) |
819
+ | [awfind](https://github.com/Aitherium/awfind) | A portable search client — query, results, ranking | [docs](https://aitherium.github.io/awfind/) |
820
+ | [awbrowse](https://github.com/Aitherium/awbrowse) | A portable browser client — navigate, console, network, DOM, screenshot | [docs](https://aitherium.github.io/awbrowse/) |
821
+ | [awvoice](https://github.com/Aitherium/awvoice) | Hear and speak — transcribe audio, synthesize a voice | [docs](https://aitherium.github.io/awvoice/) |
822
+ | [awvision](https://github.com/Aitherium/awvision) | See an image — describe it, ask it a question, compare two | [docs](https://aitherium.github.io/awvision/) |
823
+ | [awscreen](https://github.com/Aitherium/awscreen) | See this machine — what is on screen, and where to click it | [docs](https://aitherium.github.io/awscreen/) |
824
+ | [awkit](https://github.com/Aitherium/awkit) | Render an agent panel from a tool result — one component, any React app | [docs](https://aitherium.github.io/awkit/) |
825
+ | [awbeads](https://github.com/Aitherium/awbeads) | A spatial canvas for a page — arrange things, connect them, and keep the arrangement | [docs](https://aitherium.github.io/awbeads/) |
826
+ | [awbonsai](https://github.com/Aitherium/awbonsai) | Run a real model in the visitor's own browser — no server round trip, no upload | [docs](https://aitherium.github.io/awbonsai/) |
827
+ | [awknowledge](https://github.com/Aitherium/awknowledge) | How to run a coding agent so the result survives — the laws, with evidence | [docs](https://aitherium.github.io/awknowledge/) |
828
+ | [awbrain](https://github.com/Aitherium/awbrain) | Your history as a wiki of linked markdown — claims pinned to the evidence | [docs](https://aitherium.github.io/awbrain/) |
829
+ | [gawbbonet](https://github.com/Aitherium/gawbbonet) | GobboNet campaigns with a real agent brain — scoped memory, graph recall | [docs](https://aitherium.github.io/gawbbonet/) |
830
+ | **aitherkvcache** _(you are here)_ | Near-optimal KV cache quantization for LLM inference — sub-byte compression | [docs](https://aitherium.github.io/aitherkvcache/) |
831
+ | [awrtifact](https://github.com/Aitherium/awrtifact) | Deliberately chunk artifacts into GitHub release assets — the productized aitherkvcache mirror lane | [docs](https://aitherium.github.io/awrtifact/) |
832
+ | [AitherZero](https://github.com/Aitherium/AitherZero) | PowerShell 7+ automation framework — numbered, self-describing scripts | [docs](https://aitherium.github.io/AitherZero/) |
833
+ | [AitherConnect](https://github.com/Aitherium/AitherConnect) | Browser extension — federated AI search, page context, and the Living OS overlay | [docs](https://aitherium.github.io/AitherConnect/) |
834
+ | [awreason](https://github.com/Aitherium/awreason) | A portable reasoning client — sessions, phases, thoughts, and the chain that produced the answer | [docs](https://aitherium.github.io/awreason/) |
835
+ | [awrecurse](https://github.com/Aitherium/awrecurse) | Answer a question over a context far larger than the window — recursively, with the trace kept | [docs](https://aitherium.github.io/awrecurse/) |
836
+ | [awprism](https://github.com/Aitherium/awprism) | Turn a failure into ranked hypotheses — and say what would confirm each one | [docs](https://aitherium.github.io/awprism/) |
837
+ | [awrepl](https://github.com/Aitherium/awrepl) | A REPL an agent can actually use — state that survives between turns | [docs](https://aitherium.github.io/awrepl/) |
838
+ | [awreport](https://github.com/Aitherium/awreport) | File a bug report that has already scrubbed your secrets and collapsed the duplicate | [docs](https://aitherium.github.io/awreport/) |
839
+ | [awresearch](https://github.com/Aitherium/awresearch) | Ask a research question, get a cited report you can check | [docs](https://aitherium.github.io/awresearch/) |
840
+ | [awfocus](https://github.com/Aitherium/awfocus) | See, search and steer every Claude session from one command | [docs](https://aitherium.github.io/awfocus/) |
841
+ | [awgym](https://github.com/Aitherium/awgym) | An ARC training gym — a game a world model can watch, and six roles that play through it | [docs](https://aitherium.github.io/awgym/) |
842
+ | [awpredict](https://github.com/Aitherium/awpredict) | Predict what your environment does next, and how surprised you were | [docs](https://aitherium.github.io/awpredict/) |
843
+ | [awevolve](https://github.com/Aitherium/awevolve) | Point an agent at a file and a command that scores it, and let it improve | [docs](https://aitherium.github.io/awevolve/) |
844
+ | [awsh](https://github.com/Aitherium/awsh) | Your terminal answers you -- type a question where a command would go | [docs](https://aitherium.github.io/awsh/) |
845
+ | [awmine](https://github.com/Aitherium/awmine) | Mine what your agents did -- outcomes, lessons and procedures out of the transcripts they left behind | [docs](https://aitherium.github.io/awmine/) |
846
+ | [awrise](https://github.com/Aitherium/awrise) | Wake an agent on a schedule, let it do one thing, and put it back to sleep | [docs](https://aitherium.github.io/awrise/) |
847
+ | [awkno](https://github.com/Aitherium/awkno) | The man page for the Aither World — every brick, stack and law, offline | [docs](https://aitherium.github.io/awkno/) |
848
+ | [awwall](https://github.com/Aitherium/awwall) | Say what a workload may reach, and watch everything else fail closed | [docs](https://aitherium.github.io/awwall/) |
849
+ | [awrouter](https://github.com/Aitherium/awrouter) | OpenRouter for your own fleet: pick a model backend by cost/latency/ capability, fail over, fit the context window, stream. Standalone, OpenAI-compatible, no Aither-specifics required to be valuable | [docs](https://aitherium.github.io/awrouter/) |
850
+ | [awembed](https://github.com/Aitherium/awembed) | Train an embedding model that knows your corpus, and prove it beats the big one | [docs](https://aitherium.github.io/awembed/) |
851
+ | [awtax](https://github.com/Aitherium/awtax) | Turn any tax PDF -- returns, W-2, 1099, statements, even scans -- into structured data you can check | [docs](https://aitherium.github.io/awtax/) |
852
+ | [awflow](https://github.com/Aitherium/awflow) | A deterministic workflow runtime — chain agent calls with journal replay and budget control | [docs](https://aitherium.github.io/awflow/) |
853
+ | [awsettings](https://github.com/Aitherium/awsettings) | Your agent's permissions and config, following you to the next machine | [docs](https://aitherium.github.io/awsettings/) |
854
+ | [awavatar](https://github.com/Aitherium/awavatar) | One character spec in, a rigged, animated, multi-style avatar pack out | [docs](https://aitherium.github.io/awavatar/) |
855
+
856
+ **Built on** [REA (Reverse Engineer Anything)](https://github.com/morluto/rea) · [llama.cpp](https://github.com/ggml-org/llama.cpp) · [vLLM](https://github.com/vllm-project/vllm) · [ComfyUI](https://github.com/comfyanonymous/ComfyUI) · [CentOS Stream](https://www.centos.org/centos-stream/) · [Podman](https://github.com/containers/podman) · [Docker](https://github.com/moby/moby) · [LanceDB](https://github.com/lancedb/lancedb) · [WireGuard](https://www.wireguard.com/) · [FFmpeg](https://ffmpeg.org/) · [Blender + Rigify](https://www.blender.org/) · [headroom](https://github.com/headroomlabs-ai/headroom) · [SANA](https://github.com/NVlabs/Sana) · [Hunyuan3D](https://github.com/Tencent-Hunyuan/Hunyuan3D-2.1) · [repowise](https://github.com/repowise-dev/repowise) · [Playwright](https://github.com/microsoft/playwright) · [Chromium](https://www.chromium.org/) · [Next.js](https://github.com/vercel/next.js) · [React](https://github.com/facebook/react).
857
+
858
+ <div id="aither-constellation" data-self="aitherkvcache"></div>
859
+ <script src="aither-constellation.js"></script>
860
+
861
+ <!-- aither-ecosystem:end -->