How Compression Works
Understand Headroom's compression pipeline, automatic content routing, and how different content types are compressed.
Headroom automatically detects what kind of content you're sending and routes it to the right compressor. You don't need to configure anything -- just call compress() and the pipeline handles the rest.
The Pipeline
Every request flows through a short pipeline:
┌──────────────┐ ┌────────────────┐
│ CacheAligner │────>│ ContentRouter │
│ (off by │ │ │
│ default) │ │ Detect type & │
│ report drift │ │ route to best │
│ for cache │ │ compressor │
└──────────────┘ └────────────────┘- CacheAligner (detector-only, off by default) reports dynamic-prefix drift (dates, session context) so callers can keep the static prefix cacheable. It never rewrites your messages.
- ContentRouter inspects each content block and routes it to one compressor -- SmartCrusher for JSON arrays, CodeAwareCompressor for source code, LogCompressor for build output, and so on. This is where essentially all compression happens.
Content Type Detection
The router auto-detects content type by analyzing structure and patterns. No manual hints required.
| Content Type | Detection Signal | Compressor | Typical Savings |
|---|---|---|---|
| JSON arrays | Valid JSON with array elements | SmartCrusher | Varies with redundancy -- measured 26-54% on realistic (non-duplicate) tool-output arrays of 100-10,000 items; highly repetitive arrays compress far more. See benchmarks/compression_benchmark.py. |
| Source code | Syntax patterns, indentation, keywords | Kompress via the library compress()/HeadroomClient path (enable_code_aware defaults to False there); CodeAwareCompressor via headroom proxy (HEADROOM_CODE_AWARE_ENABLED defaults to on) | workload-dependent |
| Search results | file:line:content format | SearchCompressor | 80-95% (measured ~91% on a synthetic 40-file ripgrep-style corpus) |
| Build/test logs | Timestamps, log levels, pytest/npm markers | LogCompressor | 85-95% (measured ~93% on a synthetic 1,000-line log with clustered errors) |
| Diffs | Unified diff format | DiffCompressor | 60-80% (measured ~70% on a multi-file diff with default max_context_lines/max_hunks_per_file limits) |
| HTML | Tag structure | HTMLExtractor | 70-90% (module docstring; measured ~81% on a synthetic nav/ads/script-heavy page) |
| Tabular (CSV/TSV/markdown tables) | Delimited rows / table syntax | TabularCompressor | Varies with redundancy -- TabularCompressor bridges to SmartCrusher, so it inherits the same range (measured 26-28% on non-duplicate rows) |
| Structured config (YAML/TOML/INI) | Config syntax | ConfigCompressor | 40-70% (measured ~50% on a commented/blank-line-heavy YAML file) |
| Plain text | Text with no stronger signal | Kompress | workload-dependent |
| Anything else | Fallback chain, then passthrough if no safe saving is found | Kompress / passthrough | varies |
Quick Start
import { } from "headroom-ai";
const = [
{ : "system" as , : "You are a helpful assistant." },
{ : "user" as , : "Summarize this data" },
{ : "tool" as , : '{"results": [...]}', : "call_1" },
];
const = await ();
.(`Tokens saved: ${.tokensSaved}`);
.(`Compression ratio: ${.compressionRatio}`);Configuring the Compressor
import { } from "headroom-ai";
const = await (messages, {
: "gpt-4o",
: 50000,
});
.(`Before: ${.tokensBefore} tokens`);
.(`After: ${.tokensAfter} tokens`);
.(`Transforms: ${.transformsApplied.join(", ")}`);Structure Preservation
Headroom doesn't blindly truncate. It identifies what matters in each content type and preserves it:
| Content Type | What's Preserved | What's Compressed |
|---|---|---|
| JSON | Keys, brackets, booleans, nulls, short values, UUIDs | Long string values, whitespace |
| Code | Imports, function signatures, class definitions, types | Function bodies, comments |
| Logs | Timestamps, log levels, error messages, stack traces | Repeated patterns, verbose details |
| Text | High-entropy tokens (IDs, hashes), headers | Low-information content |
Real Compression Ratios
Compression ratio and latency both depend heavily on the shape of the input
(how redundant the data is, how large the payload is, and -- for Kompress --
what target_ratio is configured). There's no single number that holds
across workloads, so treat the ranges in the table above as directional and
reproduce them on your own traffic with the harnesses in
benchmarks/
(for example compression_benchmark.py, bench_transforms.py,
text_crusher_quality_eval.py). What stays constant across content types is
what's preserved:
| Content Type | What's Preserved |
|---|---|
| JSON (large arrays) | All keys, structure |
| Source code (Python) | Signatures, imports |
| Search results | Relevant matches |
| Build logs | Errors, stack traces |
| Plain text | High-entropy tokens |
Compressing multiple documents
The public compress() API accepts an LLM message list. Put documents in
separate messages or call it once per independent request; this preserves the
same message shape you will send to the provider:
from headroom import compress
messages = [
{"role": "user", "content": "Compare these documents."},
{"role": "tool", "tool_call_id": "doc_1", "content": first_document},
{"role": "tool", "tool_call_id": "doc_2", "content": second_document},
]
result = compress(messages, model="gpt-4o")What Happens Under the Hood
When you call compress(), here is the full sequence:
- Safety gates -- protected tools, recent turns, frozen cache prefixes, and minimum-size rules decide what may change.
- Content detection -- Magika when available plus deterministic pattern matching identifies the content type.
- Structural compression -- format-specific handlers compact JSON, logs, search results, tables, configuration, HTML, and other recognized structures.
- Fallback compression -- Kompress handles eligible text when its runtime is available; a no-saving or failed transform passes the original through.
- CCR storage in proxy flows -- when CCR is enabled, originals for marker-bearing compression are retained for later retrieval.
--losslessand--no-ccrintentionally use different contracts; see Reversible Compression.
Zero-config by default
The pipeline works out of the box with no configuration. All detection, routing, and compression happens automatically. Configuration is available when you need fine-grained control.