# lean-ctx vs Headroom

> **Last updated:** July 2026 | Both expose a drop-in `compress(messages, model)`,
> but that shared surface hides the real difference: Headroom is a stateless
> compression *library*; lean-ctx is a stateful context-engineering *layer* that
> remembers, proves, and (next) replays the context it shapes.

## Overview

| | lean-ctx | Headroom |
|---|---|---|
| **Approach** | Local context-engineering layer with a deterministic compression funnel | Compression library + proxy with optional ML compression |
| **Drop-in API** | `compress(messages, model)` (Py + TS) | `compress(messages, model)` (Py + TS) |
| **Runtime** | Single Rust binary + loopback daemon | Python package (`headroom-ai`) / Node package |
| **License** | Apache-2.0 | Apache-2.0 |
| **Determinism** | Byte-stable output, prompt-cache safe (#498) | Not a stated contract |
| **Locality** | 100% local, no telemetry by default | Local library; proxy/ML modes optional |
| **Beyond compress()** | 80 MCP tools, session memory, code intelligence | Cross-agent memory, `headroom learn`, ML compression |

## The core difference

**Headroom** is a compression library first: `compress()` inline, a transparent
proxy for zero-code integration, an MCP server, and an optional ML compressor
("Kompress", requires `torch`). Its reach comes from a broad set of framework
wrappers (LiteLLM, LangChain, Agno, Strands) and agent-wrap commands.

**lean-ctx** is a context-engineering *layer*. The same `compress()` contract is
one surface of a Rust daemon that also does cached file reads (10 modes), 95+
shell-output compression patterns, hybrid semantic search, call-graph/impact
analysis, and a temporal knowledge graph — all 100% local, behind 29 published
stability contracts. Its `/v1/compress` is **deterministic by contract**: the
same `(messages, model)` produces byte-identical output, so Anthropic (90%) and
OpenAI (50%) prompt-cache discounts survive compression.

The gap is structural, not cosmetic. A `compress()` call is stateless by design:
it sees one message list and returns a shorter one. lean-ctx keeps a stateful
record *around* that call — a Context Ledger of why each item was kept or dropped
(with Φ-scores), a signed Context Proof of what the model saw, plus session
memory and a temporal knowledge graph that persist across runs. That state is the
foundation for the **Context Time Machine** (direction; see
[`docs/concepts/context-time-machine.md`](../concepts/context-time-machine.md)): a
git-anchored, signed snapshot you can rewind, reproduce, resume, or share. A
stateless library has nothing to anchor such a timeline to.

## Feature comparison

| Feature | lean-ctx | Headroom |
|---------|:--------:|:--------:|
| Drop-in `compress()` (Py + TS) | Yes | Yes |
| Transparent proxy | Yes (multi-provider) | Yes |
| MCP server | 80 tools | `headroom_compress/retrieve/stats` |
| Reversible (reference retrieval) | CCR (#482/#493) + `/v1/references/{id}`, `ctx_expand`/`ctx_retrieve` | `headroom_retrieve` store |
| Deterministic / prompt-cache safe | Yes (#498, CI-guarded) | Not stated |
| Vercel AI SDK middleware | `leanCtxMiddleware` / `withLeanCtx` | `headroomMiddleware` / `withHeadroom` |
| LiteLLM hook | `LeanCtxLiteLLMHandler` | `HeadroomCallback` |
| LiteLLM proxy guardrail (`pre_call` sidecar) | Yes — `/v1/compress` speaks the guardrail wire contract (#700) | Yes — native `guardrail: headroom` (July 2026) |
| LangChain | `compress_messages` + retriever | wrap model |
| ML / learned compression | No (deterministic by design) | Yes (Kompress, torch) |
| JSON array crusher (row dedup) | `json_crush` — lossless + opt-in lossy with CCR, deterministic (#935) | Smart Crusher (statistical) |
| Active prompt-cache breakpoints | Anthropic `cache_control` injection, opt-in (#939) | Cache aligner |
| Volatile-field cache alignment | Detector (#940) **+ opt-in tail-relocate (#974)**, deterministic | Cache aligner (relocate) |
| Compression-learning loop | Retrieve-coupled session backoff, deterministic (#941) | CCR learning |
| Cross-agent shared memory | Knowledge graph + handoff | `SharedContext` |
| File-read compression | 10 modes, ~13-token cached re-reads | — |
| Shell-output compression | 95+ patterns | — |
| Semantic search / call graph | Hybrid BM25+vector / multi-hop | — |
| Single binary | Rust | Python / Node |

## Compression: deterministic funnel vs ML

lean-ctx's `/v1/compress` runs every text payload through a deterministic funnel
(dedup, structural prose squeeze, tool-output patterns). Because it is rule-based
it is **reproducible and cache-stable**, but it does not learn — highly novel
prose compresses modestly, while repetitive tool output, logs and RAG dumps
compress heavily (the same engine reaches up to ~99% on file reads and powers 95+
shell patterns).

For the array-of-objects JSON that dominates API responses, DB dumps and RAG
chunks, lean-ctx ships `json_crush` (#935) — the deterministic counterpart to
Headroom's statistical Smart Crusher. It hoists every key shared across all rows
to a single `_defaults` block and keeps only per-row deviations, so the lossless
stage is **exactly reconstructible**; an opt-in lossy stage drops near-unique
high-entropy columns (timestamps, UUIDs) only behind a content-addressed
`ctx_expand` handle, so a dropped datum is never irrecoverable. Unlike a
statistical crusher, the output is a pure function of the input (no mean/stddev
sampling), so it stays byte-stable and cache-safe. The accuracy floor is
CI-guarded: a model-free A/B gate (`Condition::JsonCrush`, #942) proves the crush
keeps every gold answer while cutting tokens on a redundant payload.

Headroom additionally offers an **ML** compressor (Kompress) for prose, at the
cost of a `torch` dependency and non-deterministic output.

**Rule of thumb:** choose lean-ctx when the payload is code, tool output, logs or
RAG context and you need local, deterministic, cache-preserving output; consider
Headroom's ML mode when you specifically need learned prose compression.

## Reversibility

Compression is only safe if the model can get the original bytes back when it
needs them. lean-ctx never throws content away — it moves it to a
content-addressed store and leaves a deterministic handle. There are **five**
recovery paths, so reversibility holds whether you drive lean-ctx as a proxy, an
SDK or an MCP server:

1. **Archive + `ctx_expand`** — any truncated tool output keeps an archive id; the
   agent calls `ctx_expand(id, …)` (or `head`/`tail`/`grep`) to stream the rest.
2. **`ctx_retrieve`** — fetches the verbatim original for a stored reference id.
3. **Proxy CCR (#482)** — when the proxy prunes an old `tool_result`, it persists
   the verbatim original to the shared tee store and embeds the file path as the
   retrieval handle, recoverable with the agent's *native* file read (no MCP
   needed). The handle is a pure function of the content hash, so it never breaks
   the prompt cache (#448).
4. **In-band CCR (#493)** — for a remote proxy with no shared filesystem, the stub
   advertises a compact `<lc_expand:HASH>` marker; when the model echoes it, the
   proxy splices the verbatim original back inline next turn.
5. **`GET /v1/references/{id}`** — an HTTP endpoint that resolves a reference id to
   its original, for SDK/HTTP clients.

All five are deterministic and content-addressed (see
[`rust/src/proxy/ccr.rs`](../../rust/src/proxy/ccr.rs)). Headroom is also
reversible — via its `headroom_retrieve` store — so any third-party table that
lists lean-ctx as "Reversible: No" is simply out of date.

## Benchmark (reproduce it yourself)

Numbers depend entirely on the corpus, so we ship a harness instead of cherry-
picked figures. It runs **both** libraries over the *same* files with the *same*
tokenizer and emits JSON (ratio + latency). A tool that is not installed is
reported `available: false` — never estimated.

```bash
# Optional head-to-head + accurate tokens:
pip install headroom-ai tiktoken
# lean-ctx side needs the daemon with /v1/compress:
lean-ctx dev-install

python bench/compress/benchmark.py --corpus docs/ --model gpt-4o --out report.json
```

A daemon-free lean-ctx data point (deterministic funnel, `o200k_base`) over this
repo's 27 `docs/reference/*.md` files, via
`cargo test -p lean-ctx --lib proxy::compress_api::tests::bench_real_corpus_o200k -- --ignored --nocapture`:

```json
{ "files": 27, "original_tokens": 69594, "compressed_tokens": 57615,
  "tokens_saved": 11979, "saved_pct": 17.2, "tokenizer": "o200k_base" }
```

Prose docs are a conservative corpus; tool-output / log payloads — the common
agent case — compress far more. See [`bench/compress/`](../../bench/compress/README.md).

## Where Headroom leads

- **Momentum & mindshare** — a fast-moving, popular library with broad adoption,
  amplified by the **native LiteLLM guardrail** (July 2026): `guardrail: headroom`
  ships in LiteLLM ≥ v1.92, giving Headroom first-mover distribution on every
  LiteLLM gateway. (lean-ctx speaks the same sidecar wire contract — see below —
  so the channel is open to both; the mindshare is theirs.)
- **CCR through the gateway** — LiteLLM's agentic loop natively understands
  Headroom's `hash=<24-hex>` markers and `GET /v1/retrieve/{hash}`, so Headroom's
  reversible path round-trips through LiteLLM today. lean-ctx's CCR markers
  (`<lc_expand:HASH>`) are not yet mapped onto that contract (#700 follow-up).
- **Learned compression** — the ML (Kompress) path can beat rule-based squeezing
  on free-form prose.
- **More framework wrappers out of the box** — Agno, Strands, agent-wrap commands.
- **Single-language install** — pure `pip install headroom-ai`, no separate daemon
  for the inline library path.

## Where lean-ctx leads

- **Determinism & prompt-cache safety** — byte-stable output is a CI-guarded
  contract (#498); compression never breaks Anthropic/OpenAI cache discounts.
- **Deterministic equivalents of Headroom's adaptive stages** — the JSON crusher
  (#935), active Anthropic cache-breakpoint injection (#939), volatile-field
  cache-aligner relocate (#974) and retrieve-coupled compression-learning loop
  (#941) deliver Smart-Crusher / cache-aligner / CCR-learning behaviour *without*
  sampling, ML weights or non-deterministic output.
- **It's a whole layer** — compression is 1 of 80 MCP tools alongside cached
  reads, shell compression, semantic search, code intelligence and memory.
- **Stateful, with a temporal axis** — a Context Ledger, signed proofs, session
  memory and a temporal knowledge graph wrap every compression, and are composing
  into a git-anchored **Context Time Machine** (rewind / reproduce / resume /
  share). A stateless `compress()` library has no equivalent.
- **100% local, single Rust binary** — no Python runtime, no telemetry by default.
- **Stability contracts** — 29 published contracts, frozen surfaces SHA-256-locked
  in CI; integrations can't silently break.

## When to use which

### Choose Headroom if you...
- Want a pure-Python (or Node) library with no separate daemon for the inline path
- Need learned/ML prose compression and accept a `torch` dependency
- Use Agno / Strands or want the widest set of prebuilt framework wrappers
- Need gateway-side CCR retrieval through LiteLLM's agentic loop today

Running a LiteLLM gateway is **not** by itself a reason to pick either: the
guardrail's `api_base` can point at a lean-ctx daemon just as well (deterministic,
prompt-cache-safe output — see the
[compress() SDK cookbook](../guides/compress-sdk.md#litellm-proxy-guardrail-zero-code-gateway-side)),
which makes a one-URL A/B between the two trivially easy.

### Choose lean-ctx if you...
- Need deterministic, prompt-cache-preserving compression
- Want compression *and* cached reads, shell compression, search, and memory
- Require 100% local operation in a single binary with stability guarantees
- Are compressing code, tool output, logs or RAG context

## Migration (Headroom → lean-ctx)

The contracts line up, so migration is mostly imports:

```python
# Headroom
from headroom import compress
result = compress(messages, model="gpt-4o")
messages = result.messages

# lean-ctx
from lean_ctx import ProxyClient
result = ProxyClient().compress(messages, model="gpt-4o")
messages = result.messages          # result.saved_tokens / result.saved_pct
```

```ts
// Headroom → lean-ctx (Vercel AI SDK)
- middleware: headroomMiddleware()
+ middleware: leanCtxMiddleware({ model: "gpt-4o" })
```

See the [compress() SDK cookbook](../guides/compress-sdk.md) for full recipes.

---

*Both projects are open source (Apache-2.0). Star counts and ML results move fast —
run the benchmark on your own corpus and choose what fits.*

[Get started with lean-ctx](https://leanctx.com/docs/getting-started) | [Headroom on GitHub](https://github.com/chopratejas/headroom)

