Headroom

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     │
└──────────────┘     └────────────────┘
  1. 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.
  2. 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 TypeDetection SignalCompressorTypical Savings
JSON arraysValid JSON with array elementsSmartCrusherVaries 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 codeSyntax patterns, indentation, keywordsKompress 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 resultsfile:line:content formatSearchCompressor80-95% (measured ~91% on a synthetic 40-file ripgrep-style corpus)
Build/test logsTimestamps, log levels, pytest/npm markersLogCompressor85-95% (measured ~93% on a synthetic 1,000-line log with clustered errors)
DiffsUnified diff formatDiffCompressor60-80% (measured ~70% on a multi-file diff with default max_context_lines/max_hunks_per_file limits)
HTMLTag structureHTMLExtractor70-90% (module docstring; measured ~81% on a synthetic nav/ads/script-heavy page)
Tabular (CSV/TSV/markdown tables)Delimited rows / table syntaxTabularCompressorVaries 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 syntaxConfigCompressor40-70% (measured ~50% on a commented/blank-line-heavy YAML file)
Plain textText with no stronger signalKompressworkload-dependent
Anything elseFallback chain, then passthrough if no safe saving is foundKompress / passthroughvaries

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 TypeWhat's PreservedWhat's Compressed
JSONKeys, brackets, booleans, nulls, short values, UUIDsLong string values, whitespace
CodeImports, function signatures, class definitions, typesFunction bodies, comments
LogsTimestamps, log levels, error messages, stack tracesRepeated patterns, verbose details
TextHigh-entropy tokens (IDs, hashes), headersLow-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 TypeWhat's Preserved
JSON (large arrays)All keys, structure
Source code (Python)Signatures, imports
Search resultsRelevant matches
Build logsErrors, stack traces
Plain textHigh-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:

  1. Safety gates -- protected tools, recent turns, frozen cache prefixes, and minimum-size rules decide what may change.
  2. Content detection -- Magika when available plus deterministic pattern matching identifies the content type.
  3. Structural compression -- format-specific handlers compact JSON, logs, search results, tables, configuration, HTML, and other recognized structures.
  4. Fallback compression -- Kompress handles eligible text when its runtime is available; a no-saving or failed transform passes the original through.
  5. CCR storage in proxy flows -- when CCR is enabled, originals for marker-bearing compression are retained for later retrieval. --lossless and --no-ccr intentionally 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.

On this page